diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fdb8b994..b55e57bc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,9 @@ on: branches: - main + schedule: + - cron: 00 4 * * * + env: CARGO_TERM_COLOR: always @@ -17,7 +20,7 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master with: @@ -32,8 +35,12 @@ jobs: - name: Check C formatting run: git ls-files -- '*.c' '*.h' | xargs clang-format --dry-run --Werror + + - name: Check Markdown + uses: DavidAnson/markdownlint-cli2-action@v9 - - run: taplo fmt --check + - name: Check TOML formatting + run: taplo fmt --check - name: Check formatting run: cargo fmt --all -- --check @@ -66,7 +73,7 @@ jobs: - riscv64gc-unknown-linux-gnu runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master with: @@ -119,7 +126,7 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master with: @@ -151,7 +158,7 @@ jobs: - ubuntu-22.04 runs-on: ${{ matrix.runner }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive @@ -198,12 +205,15 @@ jobs: run: | set -euxo pipefail brew update - brew install dpkg findutils gnu-tar llvm pkg-config - # Workaround for https://github.com/Homebrew/homebrew-core/pull/139492. - brew reinstall qemu + # https://github.com/actions/setup-python/issues/577 + find /usr/local/bin -type l -exec sh -c 'readlink -f "$1" \ + | grep -q ^/Library/Frameworks/Python.framework/Versions/' _ {} \; -exec rm -v {} \; + brew install dpkg findutils gnu-tar llvm pkg-config 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 + # https://github.com/Homebrew/homebrew-core/issues/140244 + codesign --verify $(which qemu-system-x86_64) || brew reinstall qemu --build-from-source - name: bpf-linker if: runner.os == 'macOS' @@ -220,7 +230,6 @@ jobs: # 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 @@ -233,7 +242,6 @@ jobs: # 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 @@ -242,7 +250,11 @@ jobs: 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 + - name: Run local integration tests + if: runner.os == 'Linux' + run: cargo xtask integration-test local + + - name: Run virtualized 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. diff --git a/.github/workflows/gen.yml b/.github/workflows/gen.yml index 37506c6a..30763c41 100644 --- a/.github/workflows/gen.yml +++ b/.github/workflows/gen.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 096442cf..6cea2982 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,7 +9,7 @@ jobs: if: startsWith(github.ref, 'refs/tags/') runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 diff --git a/.markdownlint-cli2.yaml b/.markdownlint-cli2.yaml new file mode 100644 index 00000000..33e410af --- /dev/null +++ b/.markdownlint-cli2.yaml @@ -0,0 +1,8 @@ +config: + no-duplicate-heading: false + +globs: + - "**/*.md" +ignores: + - "target/**/*" + - "xtask/libbpf/**/*" diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 57c1b866..0d9ca6f7 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -115,14 +115,14 @@ the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 2.0, available at -https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. +version 2.0, available [here][covenant-2-0]. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org +[covenant-2-0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct -For answers to common questions about this code of conduct, see the FAQ at -https://www.contributor-covenant.org/faq. Translations are available at -https://www.contributor-covenant.org/translations. +For answers to common questions about this code of conduct, see the +[FAQ](https://www.contributor-covenant.org/faq). Translations are available +[here](https://www.contributor-covenant.org/translations). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 34ada6e8..4f2cb6a8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,12 +17,16 @@ version of aya you're using and which version of the linux kernel. If you find an API that is not documented, unclear or missing examples, please file an issue. If you make changes to the documentation, please read -https://doc.rust-lang.org/rustdoc/how-to-write-documentation.html and make sure -your changes conform to the format outlined here -https://doc.rust-lang.org/rustdoc/how-to-write-documentation.html#documenting-components. +[How To Write Documentation] and make sure your changes conform to the +format outlined in [Documenting Components]. -If you want to make changes to the Aya Book, see the readme in the book repo -https://github.com/aya-rs/book. +[How To Write Documentation]: https://doc.rust-lang.org/rustdoc/how-to-write-documentation.html +[Documenting Components]: https://doc.rust-lang.org/rustdoc/how-to-write-documentation.html#documenting-components + +If you want to make changes to the Aya Book, see the readme in the +[book repository]. + +[book repository]: https://github.com/aya-rs/book ## Fixing bugs and implementing new features @@ -31,7 +35,11 @@ helps us avoid duplicating work. If your work includes publicly visible changes, make sure those are properly documented as explained in the section above. ### Running tests -Run the unit tests with `cargo test`. See [Aya Integration Tests](https://github.com/aya-rs/aya/blob/main/test/README.md) regarding running the integration tests. + +Run the unit tests with `cargo test`. See [Aya Integration Tests] regarding +running the integration tests. + +[Aya Integration Tests]: https://github.com/aya-rs/aya/blob/main/test/README.md ### Commits @@ -45,21 +53,19 @@ change, please squash those together before asking for a review. A good commit message should describe what changed and why. 1. The first line should: - - * contain a short description of the change (preferably 50 characters or less, - and no more than 72 characters) - * be entirely in lowercase with the exception of proper nouns, acronyms, and - the words that refer to code, like function/variable names - * be prefixed with the name of the sub crate being changed - - Examples: - - * aya: handle reordered functions - * aya-bpf: SkSkbContext: add ::l3_csum_replace - -2. Keep the second line blank. -3. Wrap all other lines at 72 columns (except for long URLs). -4. If your patch fixes an open issue, you can add a reference to it at the end + - Contain a short description of the change (preferably 50 characters or less, + and no more than 72 characters) + - Be entirely in lowercase with the exception of proper nouns, acronyms, and + the words that refer to code, like function/variable names + - Be prefixed with the name of the sub crate being changed + + Examples: + - `aya: handle reordered functions` + - `aya-bpf: SkSkbContext: add ::l3_csum_replace` + +1. Keep the second line blank. +1. Wrap all other lines at 72 columns (except for long URLs). +1. If your patch fixes an open issue, you can add a reference to it at the end of the log. Use the `Fixes: #` prefix and the issue number. For other references use `Refs: #`. `Refs` may include multiple issues, separated by a comma. diff --git a/Cargo.toml b/Cargo.toml index f4d1df95..ef122e4f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ default-members = [ [workspace.dependencies] anyhow = { version = "1", default-features = false } assert_matches = { version = "1.5.0", default-features = false } -async-io = { version = "1.3", default-features = false } +async-io = { version = "2.0", default-features = false } aya = { path = "aya", version = "0.11.0", default-features = false } aya-bpf = { path = "bpf/aya-bpf", default-features = false } aya-log = { path = "aya-log", default-features = false } @@ -57,16 +57,18 @@ aya-log-common = { path = "aya-log-common", version = "0.1.13", default-features aya-log-parser = { path = "aya-log-parser", default-features = false } aya-obj = { path = "aya-obj", version = "0.1.0", default-features = false } aya-tool = { path = "aya-tool", default-features = false } -bindgen = { version = "0.66", default-features = false } +bindgen = { version = "0.69", default-features = false } bitflags = { version = "2.2.1", default-features = false } bytes = { version = "1", default-features = false } -cargo_metadata = { version = "0.17.0", default-features = false } +cargo_metadata = { version = "0.18.0", default-features = false } clap = { version = "4", default-features = false } +const-assert = { version = "1.0.1", default-features = false } core-error = { version = "0.0.0", default-features = false } -dialoguer = { version = "0.10", default-features = false } +dialoguer = { version = "0.11", default-features = false } diff = { version = "0.1.13", default-features = false } env_logger = { version = "0.10", default-features = false } -futures = { version = "0.3.12", default-features = false } +epoll = { version = "4.3.3", default-features = false } +futures = { version = "0.3.28", default-features = false } hashbrown = { version = "0.14", default-features = false } indoc = { version = "2.0", default-features = false } integration-ebpf = { path = "test/integration-ebpf", default-features = false } @@ -74,14 +76,14 @@ 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 } -nix = { version = "0.26.2", default-features = false } +nix = { version = "0.27.0", 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 } -public-api = { version = "0.31.2", default-features = false } +public-api = { version = "0.32.0", default-features = false } quote = { version = "1", default-features = false } +rand = { version = "0.8", default-features = false } rbpf = { version = "0.2.0", default-features = false } rustdoc-json = { version = "0.8.6", default-features = false } rustup-toolchain = { version = "0.1.5", default-features = false } @@ -89,10 +91,12 @@ rustversion = { version = "1.0.0", default-features = false } syn = { version = "2", default-features = false } tempfile = { version = "3", default-features = false } test-case = { version = "3.1.0", default-features = false } +test-log = { version = "0.2.13", default-features = false } testing_logger = { version = "0.1.1", default-features = false } thiserror = { version = "1", default-features = false } tokio = { version = "1.24.0", default-features = false } -which = { version = "4.4.0", default-features = false } +which = { version = "5.0.0", default-features = false } +xdpilone = { version = "1.0", default-features = false } xtask = { path = "xtask", default-features = false } [profile.dev] diff --git a/README.md b/README.md index de31ec77..cb2d2222 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,14 @@ [![Crates.io][crates-badge]][crates-url] ![License][license-badge] -![Build status][build-badge] +[![Build status][build-badge]][build-url] [![Book][book-badge]][book-url] - [crates-badge]: https://img.shields.io/crates/v/aya.svg?style=for-the-badge&logo=rust [crates-url]: https://crates.io/crates/aya [license-badge]: https://img.shields.io/badge/license-MIT%2FApache--2.0-blue?style=for-the-badge -[build-badge]: https://img.shields.io/github/actions/workflow/status/aya-rs/aya/build-aya.yml?branch=main&style=for-the-badge +[build-badge]: https://img.shields.io/github/actions/workflow/status/aya-rs/aya/ci.yml?style=for-the-badge +[build-url]: https://github.com/aya-rs/aya/actions/workflows/ci.yml [book-badge]: https://img.shields.io/badge/read%20the-book-9cf.svg?style=for-the-badge&logo=mdbook [book-url]: https://aya-rs.dev/book @@ -26,8 +26,8 @@ [![Discord][discord-badge]][chat-url] [![Awesome][awesome-badge]][awesome-aya] -Join [the conversation on Discord][chat-url] to discuss anything related to Aya, or discover -and contribute to a list of [Awesome Aya][awesome-aya] projects. +Join [the conversation on Discord][chat-url] to discuss anything related to Aya +or discover and contribute to a list of [Awesome Aya][awesome-aya] projects. [discord-badge]: https://img.shields.io/badge/Discord-chat-5865F2?style=for-the-badge&logo=discord [chat-url]: https://discord.gg/xHW2cb2N6G @@ -37,7 +37,7 @@ and contribute to a list of [Awesome Aya][awesome-aya] projects. ## Overview eBPF is a technology that allows running user-supplied programs inside the Linux -kernel. For more info see https://ebpf.io/what-is-ebpf. +kernel. For more info see [What is eBBF](https://ebpf.io/what-is-ebpf). Aya is an eBPF library built with a focus on operability and developer experience. It does not rely on [libbpf] nor [bcc] - it's built from the ground @@ -69,9 +69,8 @@ Some of the major features provided include: ### Example -Aya supports a large chunk of the eBPF API. The following example shows how to use a -`BPF_PROG_TYPE_CGROUP_SKB` program with aya: - +Aya supports a large chunk of the eBPF API. The following example shows how to +use a `BPF_PROG_TYPE_CGROUP_SKB` program with aya: ```rust use std::fs::File; @@ -96,12 +95,15 @@ ingress.attach(cgroup, CgroupSkbAttachType::Ingress)?; ## Contributing Please see the [contributing guide](https://github.com/aya-rs/aya/blob/main/CONTRIBUTING.md). + ## License -Aya is distributed under the terms of either the [MIT license] or the [Apache License] (version -2.0), at your option. +Aya is distributed under the terms of either the [MIT license] or the +[Apache License] (version 2.0), at your option. -Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. [MIT license]: https://github.com/aya-rs/aya/blob/main/LICENSE-MIT [Apache license]: https://github.com/aya-rs/aya/blob/main/LICENSE-APACHE diff --git a/aya-bpf-macros/src/args.rs b/aya-bpf-macros/src/args.rs index b695053a..12ed84d1 100644 --- a/aya-bpf-macros/src/args.rs +++ b/aya-bpf-macros/src/args.rs @@ -68,7 +68,7 @@ pub(crate) fn pop_bool_arg(args: &mut Args, name: &str) -> bool { } pub(crate) fn err_on_unknown_args(args: &Args) -> Result<()> { - if let Some(arg) = args.args.get(0) { + if let Some(arg) = args.args.first() { let tokens = match arg { Arg::String(name_val) => name_val.name.clone(), Arg::Bool(ident) => ident.clone(), diff --git a/aya-bpf-macros/src/btf_tracepoint.rs b/aya-bpf-macros/src/btf_tracepoint.rs index d6148abd..1e9faa8f 100644 --- a/aya-bpf-macros/src/btf_tracepoint.rs +++ b/aya-bpf-macros/src/btf_tracepoint.rs @@ -45,9 +45,10 @@ impl BtfTracePoint { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn test_btf_tracepoint() { let prog = BtfTracePoint::parse( diff --git a/aya-bpf-macros/src/cgroup_device.rs b/aya-bpf-macros/src/cgroup_device.rs index 6acfa537..88311cbc 100644 --- a/aya-bpf-macros/src/cgroup_device.rs +++ b/aya-bpf-macros/src/cgroup_device.rs @@ -34,9 +34,10 @@ impl CgroupDevice { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn test_cgroup_device() { let prog = CgroupDevice::parse( diff --git a/aya-bpf-macros/src/cgroup_skb.rs b/aya-bpf-macros/src/cgroup_skb.rs index 606eb7b5..15b5a122 100644 --- a/aya-bpf-macros/src/cgroup_skb.rs +++ b/aya-bpf-macros/src/cgroup_skb.rs @@ -48,9 +48,10 @@ impl CgroupSkb { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn cgroup_skb() { let prog = CgroupSkb::parse( diff --git a/aya-bpf-macros/src/cgroup_sock.rs b/aya-bpf-macros/src/cgroup_sock.rs index 8facb9c1..015df836 100644 --- a/aya-bpf-macros/src/cgroup_sock.rs +++ b/aya-bpf-macros/src/cgroup_sock.rs @@ -46,9 +46,10 @@ impl CgroupSock { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn cgroup_sock_post_bind4() { let prog = CgroupSock::parse( diff --git a/aya-bpf-macros/src/cgroup_sock_addr.rs b/aya-bpf-macros/src/cgroup_sock_addr.rs index 43870c54..bc5d2477 100644 --- a/aya-bpf-macros/src/cgroup_sock_addr.rs +++ b/aya-bpf-macros/src/cgroup_sock_addr.rs @@ -48,9 +48,10 @@ impl CgroupSockAddr { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn cgroup_sock_addr_connect4() { let prog = CgroupSockAddr::parse( diff --git a/aya-bpf-macros/src/cgroup_sockopt.rs b/aya-bpf-macros/src/cgroup_sockopt.rs index b5bba0dd..f26c6417 100644 --- a/aya-bpf-macros/src/cgroup_sockopt.rs +++ b/aya-bpf-macros/src/cgroup_sockopt.rs @@ -46,9 +46,10 @@ impl CgroupSockopt { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn cgroup_sockopt_getsockopt() { let prog = CgroupSockopt::parse( diff --git a/aya-bpf-macros/src/cgroup_sysctl.rs b/aya-bpf-macros/src/cgroup_sysctl.rs index e3b11223..7542d1ea 100644 --- a/aya-bpf-macros/src/cgroup_sysctl.rs +++ b/aya-bpf-macros/src/cgroup_sysctl.rs @@ -34,9 +34,10 @@ impl CgroupSysctl { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn test_cgroup_sysctl() { let prog = CgroupSysctl::parse( diff --git a/aya-bpf-macros/src/fentry.rs b/aya-bpf-macros/src/fentry.rs index c8158dc8..d15094dc 100644 --- a/aya-bpf-macros/src/fentry.rs +++ b/aya-bpf-macros/src/fentry.rs @@ -51,9 +51,10 @@ impl FEntry { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn test_fentry() { let prog = FEntry::parse( diff --git a/aya-bpf-macros/src/fexit.rs b/aya-bpf-macros/src/fexit.rs index 7c7b17e1..4c345b0f 100644 --- a/aya-bpf-macros/src/fexit.rs +++ b/aya-bpf-macros/src/fexit.rs @@ -51,9 +51,10 @@ impl FExit { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn test_fexit() { let prog = FExit::parse( diff --git a/aya-bpf-macros/src/kprobe.rs b/aya-bpf-macros/src/kprobe.rs index 4fb9895f..a8c38d70 100644 --- a/aya-bpf-macros/src/kprobe.rs +++ b/aya-bpf-macros/src/kprobe.rs @@ -1,7 +1,6 @@ use std::borrow::Cow; use proc_macro2::TokenStream; - use quote::quote; use syn::{ItemFn, Result}; @@ -79,9 +78,10 @@ impl KProbe { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn test_kprobe() { let kprobe = KProbe::parse( diff --git a/aya-bpf-macros/src/lib.rs b/aya-bpf-macros/src/lib.rs index 5696b82d..4393ab95 100644 --- a/aya-bpf-macros/src/lib.rs +++ b/aya-bpf-macros/src/lib.rs @@ -44,10 +44,9 @@ use sk_msg::SkMsg; use sk_skb::{SkSkb, SkSkbKind}; use sock_ops::SockOps; use socket_filter::SocketFilter; -use uprobe::{UProbe, UProbeKind}; - use tc::SchedClassifier; use tracepoint::TracePoint; +use uprobe::{UProbe, UProbeKind}; use xdp::Xdp; #[proc_macro_error] #[proc_macro_attribute] @@ -128,6 +127,28 @@ pub fn sk_msg(attrs: TokenStream, item: TokenStream) -> TokenStream { } } +/// Marks a function as an eBPF XDP program that can be attached to a network interface. +/// +/// On some NIC drivers, XDP probes are compatible with jumbo frames through the use of +/// multi-buffer packets. Programs can opt-in this support by passing the `frags` argument. +/// +/// XDP programs can also be chained through the use of CPU maps and dev maps, but must opt-in +/// with the `map = "cpumap"` or `map = "devmap"` arguments. +/// +/// # Minimum kernel version +/// +/// The minimum kernel version required to use this feature is 4.8. +/// +/// # Examples +/// +/// ```no_run +/// use aya_bpf::{bindings::xdp_action::XDP_PASS, macros::xdp, programs::XdpContext}; +/// +/// #[xdp(frags)] +/// pub fn xdp(ctx: XdpContext) -> u32 { +/// XDP_PASS +/// } +/// ``` #[proc_macro_error] #[proc_macro_attribute] pub fn xdp(attrs: TokenStream, item: TokenStream) -> TokenStream { diff --git a/aya-bpf-macros/src/lsm.rs b/aya-bpf-macros/src/lsm.rs index 88a66b9b..430795eb 100644 --- a/aya-bpf-macros/src/lsm.rs +++ b/aya-bpf-macros/src/lsm.rs @@ -53,9 +53,10 @@ impl Lsm { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn test_lsm_sleepable() { let prog = Lsm::parse( diff --git a/aya-bpf-macros/src/map.rs b/aya-bpf-macros/src/map.rs index 21f9a8fa..e50f45b9 100644 --- a/aya-bpf-macros/src/map.rs +++ b/aya-bpf-macros/src/map.rs @@ -2,11 +2,9 @@ use std::borrow::Cow; use proc_macro2::TokenStream; use quote::quote; -use syn::Result; +use syn::{ItemStatic, Result}; use crate::args::name_arg; - -use syn::ItemStatic; pub(crate) struct Map { item: ItemStatic, name: String, @@ -34,9 +32,10 @@ impl Map { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn test_map_with_name() { let map = Map::parse( diff --git a/aya-bpf-macros/src/perf_event.rs b/aya-bpf-macros/src/perf_event.rs index 3756959d..8022d8b2 100644 --- a/aya-bpf-macros/src/perf_event.rs +++ b/aya-bpf-macros/src/perf_event.rs @@ -35,9 +35,10 @@ impl PerfEvent { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn test_perf_event() { let prog = PerfEvent::parse( diff --git a/aya-bpf-macros/src/raw_tracepoint.rs b/aya-bpf-macros/src/raw_tracepoint.rs index 9bb7b658..87f97988 100644 --- a/aya-bpf-macros/src/raw_tracepoint.rs +++ b/aya-bpf-macros/src/raw_tracepoint.rs @@ -1,7 +1,6 @@ use std::borrow::Cow; use proc_macro2::TokenStream; - use quote::quote; use syn::{ItemFn, Result}; @@ -45,9 +44,10 @@ impl RawTracePoint { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn test_raw_tracepoint() { let prog = RawTracePoint::parse( diff --git a/aya-bpf-macros/src/sk_lookup.rs b/aya-bpf-macros/src/sk_lookup.rs index ddeae3e8..e1d6fc92 100644 --- a/aya-bpf-macros/src/sk_lookup.rs +++ b/aya-bpf-macros/src/sk_lookup.rs @@ -34,9 +34,10 @@ impl SkLookup { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn test_sk_lookup() { let prog = SkLookup::parse( diff --git a/aya-bpf-macros/src/sk_msg.rs b/aya-bpf-macros/src/sk_msg.rs index bfb6be8a..b0e2cc4c 100644 --- a/aya-bpf-macros/src/sk_msg.rs +++ b/aya-bpf-macros/src/sk_msg.rs @@ -34,9 +34,10 @@ impl SkMsg { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn test_sk_msg() { let prog = SkMsg::parse( diff --git a/aya-bpf-macros/src/sk_skb.rs b/aya-bpf-macros/src/sk_skb.rs index 72f57ff7..5056ced6 100644 --- a/aya-bpf-macros/src/sk_skb.rs +++ b/aya-bpf-macros/src/sk_skb.rs @@ -56,9 +56,10 @@ impl SkSkb { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn test_stream_parser() { let prog = SkSkb::parse( diff --git a/aya-bpf-macros/src/sock_ops.rs b/aya-bpf-macros/src/sock_ops.rs index b47ead9c..62e2b739 100644 --- a/aya-bpf-macros/src/sock_ops.rs +++ b/aya-bpf-macros/src/sock_ops.rs @@ -34,9 +34,10 @@ impl SockOps { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn test_sock_ops() { let prog = SockOps::parse( diff --git a/aya-bpf-macros/src/socket_filter.rs b/aya-bpf-macros/src/socket_filter.rs index 6511d635..2ebc3edf 100644 --- a/aya-bpf-macros/src/socket_filter.rs +++ b/aya-bpf-macros/src/socket_filter.rs @@ -34,9 +34,10 @@ impl SocketFilter { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn test_socket_filter() { let prog = SocketFilter::parse( diff --git a/aya-bpf-macros/src/tc.rs b/aya-bpf-macros/src/tc.rs index 9db12ccd..56d3940a 100644 --- a/aya-bpf-macros/src/tc.rs +++ b/aya-bpf-macros/src/tc.rs @@ -34,9 +34,10 @@ impl SchedClassifier { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn test_sched_classifier() { let prog = SchedClassifier::parse( diff --git a/aya-bpf-macros/src/tracepoint.rs b/aya-bpf-macros/src/tracepoint.rs index 0e2a7cf6..e7675b33 100644 --- a/aya-bpf-macros/src/tracepoint.rs +++ b/aya-bpf-macros/src/tracepoint.rs @@ -52,9 +52,10 @@ impl TracePoint { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn test_tracepoint() { let prog = TracePoint::parse( diff --git a/aya-bpf-macros/src/uprobe.rs b/aya-bpf-macros/src/uprobe.rs index 7144f30f..1684cd6d 100644 --- a/aya-bpf-macros/src/uprobe.rs +++ b/aya-bpf-macros/src/uprobe.rs @@ -104,9 +104,10 @@ impl UProbe { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn uprobe() { let uprobe = UProbe::parse( diff --git a/aya-bpf-macros/src/xdp.rs b/aya-bpf-macros/src/xdp.rs index 9a5ff36a..9e0f1a5a 100644 --- a/aya-bpf-macros/src/xdp.rs +++ b/aya-bpf-macros/src/xdp.rs @@ -1,31 +1,52 @@ -use std::borrow::Cow; - use proc_macro2::TokenStream; use quote::quote; -use syn::{ItemFn, Result}; +use syn::{Error, ItemFn, Result}; -use crate::args::{err_on_unknown_args, pop_bool_arg, Args}; +use crate::args::{err_on_unknown_args, pop_bool_arg, pop_string_arg, Args}; pub(crate) struct Xdp { item: ItemFn, frags: bool, + map: Option, +} + +#[derive(Clone, Copy)] +pub(crate) enum XdpMap { + CpuMap, + DevMap, } impl Xdp { pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result { let item = syn::parse2(item)?; let mut args: Args = syn::parse2(attrs)?; + let frags = pop_bool_arg(&mut args, "frags"); + let map = match pop_string_arg(&mut args, "map").as_deref() { + Some("cpumap") => Some(XdpMap::CpuMap), + Some("devmap") => Some(XdpMap::DevMap), + Some(name) => { + return Err(Error::new_spanned( + "map", + format!("Invalid value. Expected 'cpumap' or 'devmap', found '{name}'"), + )) + } + None => None, + }; + err_on_unknown_args(&args)?; - Ok(Xdp { item, frags }) + Ok(Xdp { item, frags, map }) } pub(crate) fn expand(&self) -> Result { - let section_name: Cow<'_, _> = if self.frags { - "xdp.frags".into() - } else { - "xdp".into() + let mut section_name = vec![if self.frags { "xdp.frags" } else { "xdp" }]; + match self.map { + Some(XdpMap::CpuMap) => section_name.push("cpumap"), + Some(XdpMap::DevMap) => section_name.push("devmap"), + None => (), }; + let section_name = section_name.join("/"); + let fn_vis = &self.item.vis; let fn_name = self.item.sig.ident.clone(); let item = &self.item; @@ -43,9 +64,10 @@ impl Xdp { #[cfg(test)] mod tests { - use super::*; use syn::parse_quote; + use super::*; + #[test] fn test_xdp() { let prog = Xdp::parse( @@ -97,4 +119,122 @@ mod tests { }; assert_eq!(expected.to_string(), expanded.to_string()); } + + #[test] + fn test_xdp_cpumap() { + let prog = Xdp::parse( + parse_quote! { map = "cpumap" }, + parse_quote! { + fn prog(ctx: &mut ::aya_bpf::programs::XdpContext) -> i32 { + 0 + } + }, + ) + .unwrap(); + let expanded = prog.expand().unwrap(); + let expected = quote! { + #[no_mangle] + #[link_section = "xdp/cpumap"] + fn prog(ctx: *mut ::aya_bpf::bindings::xdp_md) -> u32 { + return prog(::aya_bpf::programs::XdpContext::new(ctx)); + + fn prog(ctx: &mut ::aya_bpf::programs::XdpContext) -> i32 { + 0 + } + } + }; + assert_eq!(expected.to_string(), expanded.to_string()); + } + + #[test] + fn test_xdp_devmap() { + let prog = Xdp::parse( + parse_quote! { map = "devmap" }, + parse_quote! { + fn prog(ctx: &mut ::aya_bpf::programs::XdpContext) -> i32 { + 0 + } + }, + ) + .unwrap(); + let expanded = prog.expand().unwrap(); + let expected = quote! { + #[no_mangle] + #[link_section = "xdp/devmap"] + fn prog(ctx: *mut ::aya_bpf::bindings::xdp_md) -> u32 { + return prog(::aya_bpf::programs::XdpContext::new(ctx)); + + fn prog(ctx: &mut ::aya_bpf::programs::XdpContext) -> i32 { + 0 + } + } + }; + assert_eq!(expected.to_string(), expanded.to_string()); + } + + #[test] + #[should_panic(expected = "Invalid value. Expected 'cpumap' or 'devmap', found 'badmap'")] + fn test_xdp_bad_map() { + Xdp::parse( + parse_quote! { map = "badmap" }, + parse_quote! { + fn prog(ctx: &mut ::aya_bpf::programs::XdpContext) -> i32 { + 0 + } + }, + ) + .unwrap(); + } + + #[test] + fn test_xdp_frags_cpumap() { + let prog = Xdp::parse( + parse_quote! { frags, map = "cpumap" }, + parse_quote! { + fn prog(ctx: &mut ::aya_bpf::programs::XdpContext) -> i32 { + 0 + } + }, + ) + .unwrap(); + let expanded = prog.expand().unwrap(); + let expected = quote! { + #[no_mangle] + #[link_section = "xdp.frags/cpumap"] + fn prog(ctx: *mut ::aya_bpf::bindings::xdp_md) -> u32 { + return prog(::aya_bpf::programs::XdpContext::new(ctx)); + + fn prog(ctx: &mut ::aya_bpf::programs::XdpContext) -> i32 { + 0 + } + } + }; + assert_eq!(expected.to_string(), expanded.to_string()); + } + + #[test] + fn test_xdp_frags_devmap() { + let prog = Xdp::parse( + parse_quote! { frags, map = "devmap" }, + parse_quote! { + fn prog(ctx: &mut ::aya_bpf::programs::XdpContext) -> i32 { + 0 + } + }, + ) + .unwrap(); + let expanded = prog.expand().unwrap(); + let expected = quote! { + #[no_mangle] + #[link_section = "xdp.frags/devmap"] + fn prog(ctx: *mut ::aya_bpf::bindings::xdp_md) -> u32 { + return prog(::aya_bpf::programs::XdpContext::new(ctx)); + + fn prog(ctx: &mut ::aya_bpf::programs::XdpContext) -> i32 { + 0 + } + } + }; + assert_eq!(expected.to_string(), expanded.to_string()); + } } diff --git a/aya-log-ebpf-macros/src/expand.rs b/aya-log-ebpf-macros/src/expand.rs index ffbe3dbe..fb4630b3 100644 --- a/aya-log-ebpf-macros/src/expand.rs +++ b/aya-log-ebpf-macros/src/expand.rs @@ -1,4 +1,6 @@ -use proc_macro2::TokenStream; +use aya_log_common::DisplayHint; +use aya_log_parser::{parse, Fragment}; +use proc_macro2::{Ident, Span, TokenStream}; use quote::quote; use syn::{ parse::{Parse, ParseStream}, @@ -6,9 +8,6 @@ use syn::{ Error, Expr, LitStr, Result, Token, }; -use aya_log_common::DisplayHint; -use aya_log_parser::{parse, Fragment}; - pub(crate) struct LogArgs { pub(crate) ctx: Expr, pub(crate) target: Option, @@ -142,13 +141,16 @@ pub(crate) fn log(args: LogArgs, level: Option) -> Result {}, Some(::aya_log_ebpf::LogBuf { buf }) => { let _: Option<()> = (|| { - let size = ::aya_log_ebpf::write_record_header( + let #size = ::aya_log_ebpf::write_record_header( buf, #target, #lvl, @@ -157,14 +159,14 @@ pub(crate) fn log(args: LogArgs, level: Option) -> Result, unescaped_literal: &str) -> Result<(), /// Parses the display hint (e.g. the `ipv4` in `{:ipv4}`). fn parse_display_hint(s: &str) -> Result { Ok(match s { - "x" => DisplayHint::LowerHex, + "p" | "x" => DisplayHint::LowerHex, "X" => DisplayHint::UpperHex, "i" => DisplayHint::Ip, "mac" => DisplayHint::LowerMac, @@ -145,7 +145,7 @@ mod test { #[test] fn test_parse() { assert_eq!( - parse("foo {} bar {:x} test {:X} ayy {:i} lmao {{}} {{something}}"), + parse("foo {} bar {:x} test {:X} ayy {:i} lmao {{}} {{something}} {:p}"), Ok(vec![ Fragment::Literal("foo ".into()), Fragment::Parameter(Parameter { @@ -163,7 +163,10 @@ mod test { Fragment::Parameter(Parameter { hint: DisplayHint::Ip }), - Fragment::Literal(" lmao {} {something}".into()), + Fragment::Literal(" lmao {} {something} ".into()), + Fragment::Parameter(Parameter { + hint: DisplayHint::LowerHex + }), ]) ); assert!(parse("foo {:}").is_err()); diff --git a/aya-log/src/lib.rs b/aya-log/src/lib.rs index 88068cbe..afd80653 100644 --- a/aya-log/src/lib.rs +++ b/aya-log/src/lib.rs @@ -59,13 +59,6 @@ use std::{ const MAP_NAME: &str = "AYA_LOGS"; -use aya_log_common::{ - Argument, DisplayHint, Level, LogValueLength, RecordField, LOG_BUF_CAPACITY, LOG_FIELDS, -}; -use bytes::BytesMut; -use log::{error, Log, Record}; -use thiserror::Error; - use aya::{ maps::{ perf::{AsyncPerfEventArray, Events, PerfBufferError}, @@ -74,6 +67,12 @@ use aya::{ util::online_cpus, Bpf, Pod, }; +use aya_log_common::{ + Argument, DisplayHint, Level, LogValueLength, RecordField, LOG_BUF_CAPACITY, LOG_FIELDS, +}; +use bytes::BytesMut; +use log::{error, Log, Record}; +use thiserror::Error; #[derive(Copy, Clone)] #[repr(transparent)] @@ -563,10 +562,11 @@ fn try_read(mut buf: &[u8]) -> Result<(T, &[u8], &[u8]), ()> { #[cfg(test)] mod test { - use super::*; use aya_log_common::{write_record_header, WriteToBuf}; use log::{logger, Level}; + use super::*; + fn new_log(args: usize) -> Option<(usize, Vec)> { let mut buf = vec![0; 8192]; let len = write_record_header( diff --git a/aya-obj/Cargo.toml b/aya-obj/Cargo.toml index ec830e8d..992793f6 100644 --- a/aya-obj/Cargo.toml +++ b/aya-obj/Cargo.toml @@ -15,11 +15,8 @@ bytes = { workspace = true } core-error = { workspace = true, default-features = true } hashbrown = { workspace = true, default-features = true } log = { workspace = true } -object = { workspace = true, default-features = false, features = [ - "elf", - "read_core", -] } -thiserror = { workspace = true, default-features = false } +object = { workspace = true, features = ["elf", "read_core"] } +thiserror = { workspace = true } [dev-dependencies] assert_matches = { workspace = true } diff --git a/aya-obj/src/btf/btf.rs b/aya-obj/src/btf/btf.rs index 02976569..de9e54e4 100644 --- a/aya-obj/src/btf/btf.rs +++ b/aya-obj/src/btf/btf.rs @@ -1,5 +1,3 @@ -use core::{ffi::CStr, mem, ptr}; - use alloc::{ borrow::{Cow, ToOwned as _}, format, @@ -7,11 +5,14 @@ use alloc::{ vec, vec::Vec, }; -use bytes::BufMut; +use core::{ffi::CStr, mem, ptr}; +use bytes::BufMut; use log::debug; use object::{Endianness, SectionIndex}; +#[cfg(not(feature = "std"))] +use crate::std; use crate::{ btf::{ info::{FuncSecInfo, LineSecInfo}, @@ -24,9 +25,6 @@ use crate::{ Object, }; -#[cfg(not(feature = "std"))] -use crate::std; - pub(crate) const MAX_RESOLVE_DEPTH: u8 = 32; pub(crate) const MAX_SPEC_LEN: usize = 64; @@ -1102,12 +1100,13 @@ pub(crate) struct SecInfo<'a> { #[cfg(test)] mod tests { + use assert_matches::assert_matches; + use super::*; use crate::btf::{ BtfEnum64, BtfParam, DataSec, DataSecEntry, DeclTag, Enum64, Float, Func, FuncProto, Ptr, TypeTag, Var, }; - use assert_matches::assert_matches; #[test] fn test_parse_header() { diff --git a/aya-obj/src/btf/info.rs b/aya-obj/src/btf/info.rs index 27982807..aa5a025f 100644 --- a/aya-obj/src/btf/info.rs +++ b/aya-obj/src/btf/info.rs @@ -1,4 +1,5 @@ use alloc::{string::String, vec, vec::Vec}; + use bytes::BufMut; use object::Endianness; diff --git a/aya-obj/src/btf/relocation.rs b/aya-obj/src/btf/relocation.rs index 898c4e44..c23bee75 100644 --- a/aya-obj/src/btf/relocation.rs +++ b/aya-obj/src/btf/relocation.rs @@ -1,5 +1,3 @@ -use core::{mem, ops::Bound::Included, ptr}; - use alloc::{ borrow::{Cow, ToOwned as _}, collections::BTreeMap, @@ -8,8 +6,12 @@ use alloc::{ vec, vec::Vec, }; +use core::{mem, ops::Bound::Included, ptr}; + use object::SectionIndex; +#[cfg(not(feature = "std"))] +use crate::std; use crate::{ btf::{ fields_are_compatible, types_are_compatible, Array, Btf, BtfError, BtfMember, BtfType, @@ -23,9 +25,6 @@ use crate::{ Function, Object, }; -#[cfg(not(feature = "std"))] -use crate::std; - /// The error type returned by [`Object::relocate_btf`]. #[derive(thiserror::Error, Debug)] #[error("error relocating `{section}`")] diff --git a/aya-obj/src/btf/types.rs b/aya-obj/src/btf/types.rs index 895484df..89b1713b 100644 --- a/aya-obj/src/btf/types.rs +++ b/aya-obj/src/btf/types.rs @@ -1,8 +1,8 @@ #![allow(missing_docs)] +use alloc::{string::ToString, vec, vec::Vec}; use core::{fmt::Display, mem, ptr}; -use alloc::{string::ToString, vec, vec::Vec}; use object::Endianness; use crate::btf::{Btf, BtfError, MAX_RESOLVE_DEPTH}; @@ -1570,9 +1570,10 @@ fn bytes_of(val: &T) -> &[u8] { } #[cfg(test)] mod tests { - use super::*; use assert_matches::assert_matches; + use super::*; + #[test] fn test_read_btf_type_int() { let endianness = Endianness::default(); diff --git a/aya-obj/src/generated/mod.rs b/aya-obj/src/generated/mod.rs index 943c2703..f9097937 100644 --- a/aya-obj/src/generated/mod.rs +++ b/aya-obj/src/generated/mod.rs @@ -21,15 +21,11 @@ mod linux_bindings_x86_64; // don't re-export __u8 __u16 etc which are already exported by the // linux_bindings_* module pub use btf_internal_bindings::{bpf_core_relo, bpf_core_relo_kind, btf_ext_header}; - -#[cfg(target_arch = "x86_64")] -pub use linux_bindings_x86_64::*; - -#[cfg(target_arch = "arm")] -pub use linux_bindings_armv7::*; - #[cfg(target_arch = "aarch64")] pub use linux_bindings_aarch64::*; - +#[cfg(target_arch = "arm")] +pub use linux_bindings_armv7::*; #[cfg(target_arch = "riscv64")] pub use linux_bindings_riscv64::*; +#[cfg(target_arch = "x86_64")] +pub use linux_bindings_x86_64::*; diff --git a/aya-obj/src/lib.rs b/aya-obj/src/lib.rs index d6d2a8a5..ea0e5670 100644 --- a/aya-obj/src/lib.rs +++ b/aya-obj/src/lib.rs @@ -77,6 +77,12 @@ mod std { pub use core_error::Error; } pub use core::*; + + pub mod os { + pub mod fd { + pub type RawFd = core::ffi::c_int; + } + } } pub mod btf; diff --git a/aya-obj/src/maps.rs b/aya-obj/src/maps.rs index dbffed0c..c4cf5c32 100644 --- a/aya-obj/src/maps.rs +++ b/aya-obj/src/maps.rs @@ -1,12 +1,11 @@ //! Map struct and type bindings. -use core::mem; - -use crate::BpfSectionKind; use alloc::vec::Vec; +use core::mem; #[cfg(not(feature = "std"))] use crate::std; +use crate::BpfSectionKind; /// Invalid map type encontered pub struct InvalidMapTypeError { @@ -176,6 +175,14 @@ impl Map { } } + /// Set the value size in bytes + pub fn set_value_size(&mut self, size: u32) { + match self { + Map::Legacy(m) => m.def.value_size = size, + Map::Btf(m) => m.def.value_size = size, + } + } + /// Returns the max entry number pub fn max_entries(&self) -> u32 { match self { diff --git a/aya-obj/src/obj.rs b/aya-obj/src/obj.rs index 70375df2..9d65690e 100644 --- a/aya-obj/src/obj.rs +++ b/aya-obj/src/obj.rs @@ -7,7 +7,8 @@ use alloc::{ string::{String, ToString}, vec::Vec, }; -use core::{ffi::CStr, mem, ptr, str::FromStr}; +use core::{ffi::CStr, mem, ptr, slice::from_raw_parts_mut, str::FromStr}; + use log::debug; use object::{ read::{Object as ElfObject, ObjectSection, Section as ObjSection}, @@ -15,26 +16,23 @@ use object::{ SymbolKind, }; -use crate::{ - btf::BtfFeatures, - generated::{BPF_CALL, BPF_JMP, BPF_K}, - maps::{BtfMap, LegacyMap, Map, MINIMUM_MAP_SIZE}, - relocation::*, - util::HashMap, -}; - #[cfg(not(feature = "std"))] use crate::std; - use crate::{ - btf::{Btf, BtfError, BtfExt, BtfType}, - generated::{bpf_insn, bpf_map_info, bpf_map_type::BPF_MAP_TYPE_ARRAY, BPF_F_RDONLY_PROG}, - maps::{bpf_map_def, BtfMapDef, PinningType}, - programs::{CgroupSockAddrAttachType, CgroupSockAttachType, CgroupSockoptAttachType}, + btf::{ + Array, Btf, BtfError, BtfExt, BtfFeatures, BtfType, DataSecEntry, FuncSecInfo, LineSecInfo, + }, + generated::{ + bpf_insn, bpf_map_info, bpf_map_type::BPF_MAP_TYPE_ARRAY, BPF_CALL, BPF_F_RDONLY_PROG, + BPF_JMP, BPF_K, + }, + maps::{bpf_map_def, BtfMap, BtfMapDef, LegacyMap, Map, PinningType, MINIMUM_MAP_SIZE}, + programs::{ + CgroupSockAddrAttachType, CgroupSockAttachType, CgroupSockoptAttachType, XdpAttachType, + }, + relocation::*, + util::HashMap, }; -use core::slice::from_raw_parts_mut; - -use crate::btf::{Array, DataSecEntry, FuncSecInfo, LineSecInfo}; const KERNEL_VERSION_ANY: u32 = 0xFFFF_FFFE; @@ -47,17 +45,22 @@ pub struct Features { bpf_perf_link: bool, bpf_global_data: bool, bpf_cookie: bool, + cpumap_prog_id: bool, + devmap_prog_id: bool, btf: Option, } impl Features { #[doc(hidden)] + #[allow(clippy::too_many_arguments)] pub fn new( bpf_name: bool, bpf_probe_read_kernel: bool, bpf_perf_link: bool, bpf_global_data: bool, bpf_cookie: bool, + cpumap_prog_id: bool, + devmap_prog_id: bool, btf: Option, ) -> Self { Self { @@ -66,6 +69,8 @@ impl Features { bpf_perf_link, bpf_global_data, bpf_cookie, + cpumap_prog_id, + devmap_prog_id, btf, } } @@ -95,6 +100,16 @@ impl Features { self.bpf_cookie } + /// Returns whether XDP CPU Maps support chained program IDs. + pub fn cpumap_prog_id(&self) -> bool { + self.cpumap_prog_id + } + + /// Returns whether XDP Device Maps support chained program IDs. + pub fn devmap_prog_id(&self) -> bool { + self.devmap_prog_id + } + /// If BTF is supported, returns which BTF features are supported. pub fn btf(&self) -> Option<&BtfFeatures> { self.btf.as_ref() @@ -204,8 +219,6 @@ pub struct Function { /// - `struct_ops+` /// - `fmod_ret+`, `fmod_ret.s+` /// - `iter+`, `iter.s+` -/// - `xdp.frags/cpumap`, `xdp/cpumap` -/// - `xdp.frags/devmap`, `xdp/devmap` #[derive(Debug, Clone)] #[allow(missing_docs)] pub enum ProgramSection { @@ -221,6 +234,7 @@ pub enum ProgramSection { SocketFilter, Xdp { frags: bool, + attach_type: XdpAttachType, }, SkMsg, SkSkbStreamParser, @@ -266,10 +280,15 @@ impl FromStr for ProgramSection { // parse the common case, eg "xdp/program_name" or // "sk_skb/stream_verdict/program_name" - let (kind, name) = match section.rsplit_once('/') { - None => (section, section), - Some((kind, name)) => (kind, name), + let mut pieces = section.split('/'); + let mut next = || { + pieces + .next() + .ok_or_else(|| ParseError::InvalidProgramSection { + section: section.to_owned(), + }) }; + let kind = next()?; Ok(match kind { "kprobe" => KProbe, @@ -278,131 +297,119 @@ impl FromStr for ProgramSection { "uprobe.s" => UProbe { sleepable: true }, "uretprobe" => URetProbe { sleepable: false }, "uretprobe.s" => URetProbe { sleepable: true }, - "xdp" => Xdp { frags: false }, - "xdp.frags" => Xdp { frags: true }, + "xdp" | "xdp.frags" => Xdp { + frags: kind == "xdp.frags", + attach_type: match pieces.next() { + None => XdpAttachType::Interface, + Some("cpumap") => XdpAttachType::CpuMap, + Some("devmap") => XdpAttachType::DevMap, + Some(_) => { + return Err(ParseError::InvalidProgramSection { + section: section.to_owned(), + }) + } + }, + }, "tp_btf" => BtfTracePoint, - kind if kind.starts_with("tracepoint") || kind.starts_with("tp") => TracePoint, + "tracepoint" | "tp" => TracePoint, "socket" => SocketFilter, "sk_msg" => SkMsg, - "sk_skb" => match name { - "stream_parser" => SkSkbStreamParser, - "stream_verdict" => SkSkbStreamVerdict, - _ => { - return Err(ParseError::InvalidProgramSection { - section: section.to_owned(), - }) - } - }, - "sk_skb/stream_parser" => SkSkbStreamParser, - "sk_skb/stream_verdict" => SkSkbStreamVerdict, - "sockops" => SockOps, - "classifier" => SchedClassifier, - "cgroup_skb" => match name { - "ingress" => CgroupSkbIngress, - "egress" => CgroupSkbEgress, - _ => { - return Err(ParseError::InvalidProgramSection { - section: section.to_owned(), - }) - } - }, - "cgroup_skb/ingress" => CgroupSkbIngress, - "cgroup_skb/egress" => CgroupSkbEgress, - "cgroup/skb" => CgroupSkb, - "cgroup/sock" => CgroupSock { - attach_type: CgroupSockAttachType::default(), - }, - "cgroup/sysctl" => CgroupSysctl, - "cgroup/dev" => CgroupDevice, - "cgroup/getsockopt" => CgroupSockopt { - attach_type: CgroupSockoptAttachType::Get, - }, - "cgroup/setsockopt" => CgroupSockopt { - attach_type: CgroupSockoptAttachType::Set, - }, - "cgroup" => match name { - "skb" => CgroupSkb, - "sysctl" => CgroupSysctl, - "dev" => CgroupDevice, - "getsockopt" | "setsockopt" => { - if let Ok(attach_type) = CgroupSockoptAttachType::try_from(name) { - CgroupSockopt { attach_type } - } else { + "sk_skb" => { + let name = next()?; + match name { + "stream_parser" => SkSkbStreamParser, + "stream_verdict" => SkSkbStreamVerdict, + _ => { return Err(ParseError::InvalidProgramSection { section: section.to_owned(), - }); + }) } } - "sock" => CgroupSock { - attach_type: CgroupSockAttachType::default(), - }, - "post_bind4" | "post_bind6" | "sock_create" | "sock_release" => { - if let Ok(attach_type) = CgroupSockAttachType::try_from(name) { - CgroupSock { attach_type } - } else { + } + "sockops" => SockOps, + "classifier" => SchedClassifier, + "cgroup_skb" => { + let name = next()?; + match name { + "ingress" => CgroupSkbIngress, + "egress" => CgroupSkbEgress, + _ => { return Err(ParseError::InvalidProgramSection { section: section.to_owned(), - }); + }) } } - name => { - if let Ok(attach_type) = CgroupSockAddrAttachType::try_from(name) { - CgroupSockAddr { attach_type } - } else { + } + "cgroup" => { + let name = next()?; + match name { + "skb" => CgroupSkb, + "sysctl" => CgroupSysctl, + "dev" => CgroupDevice, + "getsockopt" => CgroupSockopt { + attach_type: CgroupSockoptAttachType::Get, + }, + "setsockopt" => CgroupSockopt { + attach_type: CgroupSockoptAttachType::Set, + }, + "sock" => CgroupSock { + attach_type: CgroupSockAttachType::default(), + }, + "post_bind4" => CgroupSock { + attach_type: CgroupSockAttachType::PostBind4, + }, + "post_bind6" => CgroupSock { + attach_type: CgroupSockAttachType::PostBind6, + }, + "sock_create" => CgroupSock { + attach_type: CgroupSockAttachType::SockCreate, + }, + "sock_release" => CgroupSock { + attach_type: CgroupSockAttachType::SockRelease, + }, + "bind4" => CgroupSockAddr { + attach_type: CgroupSockAddrAttachType::Bind4, + }, + "bind6" => CgroupSockAddr { + attach_type: CgroupSockAddrAttachType::Bind6, + }, + "connect4" => CgroupSockAddr { + attach_type: CgroupSockAddrAttachType::Connect4, + }, + "connect6" => CgroupSockAddr { + attach_type: CgroupSockAddrAttachType::Connect6, + }, + "getpeername4" => CgroupSockAddr { + attach_type: CgroupSockAddrAttachType::GetPeerName4, + }, + "getpeername6" => CgroupSockAddr { + attach_type: CgroupSockAddrAttachType::GetPeerName6, + }, + "getsockname4" => CgroupSockAddr { + attach_type: CgroupSockAddrAttachType::GetSockName4, + }, + "getsockname6" => CgroupSockAddr { + attach_type: CgroupSockAddrAttachType::GetSockName6, + }, + "sendmsg4" => CgroupSockAddr { + attach_type: CgroupSockAddrAttachType::UDPSendMsg4, + }, + "sendmsg6" => CgroupSockAddr { + attach_type: CgroupSockAddrAttachType::UDPSendMsg6, + }, + "recvmsg4" => CgroupSockAddr { + attach_type: CgroupSockAddrAttachType::UDPRecvMsg4, + }, + "recvmsg6" => CgroupSockAddr { + attach_type: CgroupSockAddrAttachType::UDPRecvMsg6, + }, + _ => { return Err(ParseError::InvalidProgramSection { section: section.to_owned(), }); } } - }, - "cgroup/post_bind4" => CgroupSock { - attach_type: CgroupSockAttachType::PostBind4, - }, - "cgroup/post_bind6" => CgroupSock { - attach_type: CgroupSockAttachType::PostBind6, - }, - "cgroup/sock_create" => CgroupSock { - attach_type: CgroupSockAttachType::SockCreate, - }, - "cgroup/sock_release" => CgroupSock { - attach_type: CgroupSockAttachType::SockRelease, - }, - "cgroup/bind4" => CgroupSockAddr { - attach_type: CgroupSockAddrAttachType::Bind4, - }, - "cgroup/bind6" => CgroupSockAddr { - attach_type: CgroupSockAddrAttachType::Bind6, - }, - "cgroup/connect4" => CgroupSockAddr { - attach_type: CgroupSockAddrAttachType::Connect4, - }, - "cgroup/connect6" => CgroupSockAddr { - attach_type: CgroupSockAddrAttachType::Connect6, - }, - "cgroup/getpeername4" => CgroupSockAddr { - attach_type: CgroupSockAddrAttachType::GetPeerName4, - }, - "cgroup/getpeername6" => CgroupSockAddr { - attach_type: CgroupSockAddrAttachType::GetPeerName6, - }, - "cgroup/getsockname4" => CgroupSockAddr { - attach_type: CgroupSockAddrAttachType::GetSockName4, - }, - "cgroup/getsockname6" => CgroupSockAddr { - attach_type: CgroupSockAddrAttachType::GetSockName6, - }, - "cgroup/sendmsg4" => CgroupSockAddr { - attach_type: CgroupSockAddrAttachType::UDPSendMsg4, - }, - "cgroup/sendmsg6" => CgroupSockAddr { - attach_type: CgroupSockAddrAttachType::UDPSendMsg6, - }, - "cgroup/recvmsg4" => CgroupSockAddr { - attach_type: CgroupSockAddrAttachType::UDPRecvMsg4, - }, - "cgroup/recvmsg6" => CgroupSockAddr { - attach_type: CgroupSockAddrAttachType::UDPRecvMsg6, - }, + } "lirc_mode2" => LircMode2, "perf_event" => PerfEvent, "raw_tp" | "raw_tracepoint" => RawTracePoint, @@ -592,12 +599,12 @@ impl Object { .get(symbol_index) .expect("all symbols in symbols_by_section are also in symbol_table"); - let Some(name) = symbol.name.as_ref() else { - continue; + // Here we get both ::Label (LBB*) and ::Text symbols, and we only want the latter. + let name = match (symbol.name.as_ref(), symbol.kind) { + (Some(name), SymbolKind::Text) if !name.is_empty() => name, + _ => continue, }; - if name.is_empty() { - continue; - } + let (p, f) = self.parse_program(section, program_section.clone(), name.to_string(), symbol)?; let key = p.function_key(); @@ -1385,6 +1392,7 @@ fn get_func_and_line_info( #[cfg(test)] mod tests { use alloc::vec; + use assert_matches::assert_matches; use object::Endianness; @@ -1642,15 +1650,12 @@ mod tests { let prog_foo = obj.programs.get("foo").unwrap(); - assert_matches!( - prog_foo, - Program { - license, - kernel_version: None, - section: ProgramSection::KProbe { .. }, - .. - } if license.to_str().unwrap() == "GPL" - ); + assert_matches!(prog_foo, Program { + license, + kernel_version: None, + section: ProgramSection::KProbe { .. }, + .. + } => assert_eq!(license.to_str().unwrap(), "GPL")); assert_matches!( obj.functions.get(&prog_foo.function_key()), @@ -1704,14 +1709,12 @@ mod tests { let prog_bar = obj.programs.get("bar").unwrap(); let function_bar = obj.functions.get(&prog_bar.function_key()).unwrap(); - assert_matches!(prog_foo, - Program { - license, - kernel_version: None, - section: ProgramSection::KProbe { .. }, - .. - } if license.to_string_lossy() == "GPL" - ); + assert_matches!(prog_foo, Program { + license, + kernel_version: None, + section: ProgramSection::KProbe { .. }, + .. + } => assert_eq!(license.to_str().unwrap(), "GPL")); assert_matches!( function_foo, Function { @@ -1724,14 +1727,12 @@ mod tests { } if name == "foo" && instructions.len() == 1 ); - assert_matches!(prog_bar, - Program { - license, - kernel_version: None, - section: ProgramSection::KProbe { .. }, - .. - } if license.to_string_lossy() == "GPL" - ); + assert_matches!(prog_bar, Program { + license, + kernel_version: None, + section: ProgramSection::KProbe { .. }, + .. + } => assert_eq!(license.to_str().unwrap(), "GPL")); assert_matches!( function_bar, Function { @@ -2037,7 +2038,7 @@ mod tests { assert_matches!( obj.parse_section(fake_section( BpfSectionKind::Program, - "xdp/foo", + "xdp", bytes_of(&fake_ins()), None )), @@ -2060,7 +2061,7 @@ mod tests { assert_matches!( obj.parse_section(fake_section( BpfSectionKind::Program, - "xdp.frags/foo", + "xdp.frags", bytes_of(&fake_ins()), None )), diff --git a/aya-obj/src/programs/cgroup_sock.rs b/aya-obj/src/programs/cgroup_sock.rs index 227e26d5..545dee2e 100644 --- a/aya-obj/src/programs/cgroup_sock.rs +++ b/aya-obj/src/programs/cgroup_sock.rs @@ -1,11 +1,6 @@ //! Cgroup socket programs. -use alloc::{borrow::ToOwned, string::String}; - use crate::generated::bpf_attach_type; -#[cfg(not(feature = "std"))] -use crate::std; - /// Defines where to attach a `CgroupSock` program. #[derive(Copy, Clone, Debug, Default)] pub enum CgroupSockAttachType { @@ -30,19 +25,3 @@ impl From for bpf_attach_type { } } } - -#[derive(Debug, thiserror::Error)] -#[error("{0} is not a valid attach type for a CGROUP_SOCK program")] -pub(crate) struct InvalidAttachType(String); - -impl CgroupSockAttachType { - pub(crate) fn try_from(value: &str) -> Result { - match value { - "post_bind4" => Ok(CgroupSockAttachType::PostBind4), - "post_bind6" => Ok(CgroupSockAttachType::PostBind6), - "sock_create" => Ok(CgroupSockAttachType::SockCreate), - "sock_release" => Ok(CgroupSockAttachType::SockRelease), - _ => Err(InvalidAttachType(value.to_owned())), - } - } -} diff --git a/aya-obj/src/programs/cgroup_sock_addr.rs b/aya-obj/src/programs/cgroup_sock_addr.rs index 6bd4070e..13d5c1c5 100644 --- a/aya-obj/src/programs/cgroup_sock_addr.rs +++ b/aya-obj/src/programs/cgroup_sock_addr.rs @@ -1,11 +1,6 @@ //! Cgroup socket address programs. -use alloc::{borrow::ToOwned, string::String}; - use crate::generated::bpf_attach_type; -#[cfg(not(feature = "std"))] -use crate::std; - /// Defines where to attach a `CgroupSockAddr` program. #[derive(Copy, Clone, Debug)] pub enum CgroupSockAddrAttachType { @@ -53,27 +48,3 @@ impl From for bpf_attach_type { } } } - -#[derive(Debug, thiserror::Error)] -#[error("{0} is not a valid attach type for a CGROUP_SOCK_ADDR program")] -pub(crate) struct InvalidAttachType(String); - -impl CgroupSockAddrAttachType { - pub(crate) fn try_from(value: &str) -> Result { - match value { - "bind4" => Ok(CgroupSockAddrAttachType::Bind4), - "bind6" => Ok(CgroupSockAddrAttachType::Bind6), - "connect4" => Ok(CgroupSockAddrAttachType::Connect4), - "connect6" => Ok(CgroupSockAddrAttachType::Connect6), - "getpeername4" => Ok(CgroupSockAddrAttachType::GetPeerName4), - "getpeername6" => Ok(CgroupSockAddrAttachType::GetPeerName6), - "getsockname4" => Ok(CgroupSockAddrAttachType::GetSockName4), - "getsockname6" => Ok(CgroupSockAddrAttachType::GetSockName6), - "sendmsg4" => Ok(CgroupSockAddrAttachType::UDPSendMsg4), - "sendmsg6" => Ok(CgroupSockAddrAttachType::UDPSendMsg6), - "recvmsg4" => Ok(CgroupSockAddrAttachType::UDPRecvMsg4), - "recvmsg6" => Ok(CgroupSockAddrAttachType::UDPRecvMsg6), - _ => Err(InvalidAttachType(value.to_owned())), - } - } -} diff --git a/aya-obj/src/programs/cgroup_sockopt.rs b/aya-obj/src/programs/cgroup_sockopt.rs index e3495728..3794c8cc 100644 --- a/aya-obj/src/programs/cgroup_sockopt.rs +++ b/aya-obj/src/programs/cgroup_sockopt.rs @@ -1,11 +1,6 @@ //! Cgroup socket option programs. -use alloc::{borrow::ToOwned, string::String}; - use crate::generated::bpf_attach_type; -#[cfg(not(feature = "std"))] -use crate::std; - /// Defines where to attach a `CgroupSockopt` program. #[derive(Copy, Clone, Debug)] pub enum CgroupSockoptAttachType { @@ -23,17 +18,3 @@ impl From for bpf_attach_type { } } } - -#[derive(Debug, thiserror::Error)] -#[error("{0} is not a valid attach type for a CGROUP_SOCKOPT program")] -pub(crate) struct InvalidAttachType(String); - -impl CgroupSockoptAttachType { - pub(crate) fn try_from(value: &str) -> Result { - match value { - "getsockopt" => Ok(CgroupSockoptAttachType::Get), - "setsockopt" => Ok(CgroupSockoptAttachType::Set), - _ => Err(InvalidAttachType(value.to_owned())), - } - } -} diff --git a/aya-obj/src/programs/mod.rs b/aya-obj/src/programs/mod.rs index 4f76211a..6b66b005 100644 --- a/aya-obj/src/programs/mod.rs +++ b/aya-obj/src/programs/mod.rs @@ -3,7 +3,9 @@ pub mod cgroup_sock; pub mod cgroup_sock_addr; pub mod cgroup_sockopt; +pub mod xdp; pub use cgroup_sock::CgroupSockAttachType; pub use cgroup_sock_addr::CgroupSockAddrAttachType; pub use cgroup_sockopt::CgroupSockoptAttachType; +pub use xdp::XdpAttachType; diff --git a/aya-obj/src/programs/xdp.rs b/aya-obj/src/programs/xdp.rs new file mode 100644 index 00000000..17fab6ab --- /dev/null +++ b/aya-obj/src/programs/xdp.rs @@ -0,0 +1,24 @@ +//! XDP programs. + +use crate::generated::bpf_attach_type; + +/// Defines where to attach an `XDP` program. +#[derive(Copy, Clone, Debug)] +pub enum XdpAttachType { + /// Attach to a network interface. + Interface, + /// Attach to a cpumap. Requires kernel 5.9 or later. + CpuMap, + /// Attach to a devmap. Requires kernel 5.8 or later. + DevMap, +} + +impl From for bpf_attach_type { + fn from(value: XdpAttachType) -> Self { + match value { + XdpAttachType::Interface => bpf_attach_type::BPF_XDP, + XdpAttachType::CpuMap => bpf_attach_type::BPF_XDP_CPUMAP, + XdpAttachType::DevMap => bpf_attach_type::BPF_XDP_DEVMAP, + } + } +} diff --git a/aya-obj/src/relocation.rs b/aya-obj/src/relocation.rs index 8269f6ca..54039465 100644 --- a/aya-obj/src/relocation.rs +++ b/aya-obj/src/relocation.rs @@ -1,11 +1,13 @@ //! Program relocation handling. +use alloc::{borrow::ToOwned, collections::BTreeMap, string::String}; use core::mem; -use alloc::{borrow::ToOwned, collections::BTreeMap, string::String}; use log::debug; use object::{SectionIndex, SymbolKind}; +#[cfg(not(feature = "std"))] +use crate::std; use crate::{ generated::{ bpf_insn, BPF_CALL, BPF_JMP, BPF_K, BPF_PSEUDO_CALL, BPF_PSEUDO_FUNC, BPF_PSEUDO_MAP_FD, @@ -17,9 +19,6 @@ use crate::{ BpfSectionKind, }; -#[cfg(not(feature = "std"))] -use crate::std; - pub(crate) const INS_SIZE: usize = mem::size_of::(); /// The error type returned by [`Object::relocate_maps`] and [`Object::relocate_calls`] @@ -105,7 +104,7 @@ pub(crate) struct Symbol { impl Object { /// Relocates the map references - pub fn relocate_maps<'a, I: Iterator>( + pub fn relocate_maps<'a, I: Iterator>( &mut self, maps: I, text_sections: &HashSet, @@ -178,8 +177,8 @@ impl Object { fn relocate_maps<'a, I: Iterator>( fun: &mut Function, relocations: I, - maps_by_section: &HashMap, - maps_by_symbol: &HashMap, + maps_by_section: &HashMap, + maps_by_symbol: &HashMap, symbol_table: &HashMap, text_sections: &HashSet, ) -> Result<(), RelocationError> { @@ -498,13 +497,12 @@ fn insn_is_call(ins: &bpf_insn) -> bool { mod test { use alloc::{string::ToString, vec, vec::Vec}; + use super::*; use crate::{ maps::{BtfMap, LegacyMap, Map}, BpfSectionKind, }; - use super::*; - fn fake_sym(index: usize, section_index: usize, address: u64, name: &str, size: u64) -> Symbol { Symbol { index, diff --git a/aya-obj/src/util.rs b/aya-obj/src/util.rs index 53209444..80d0179d 100644 --- a/aya-obj/src/util.rs +++ b/aya-obj/src/util.rs @@ -1,14 +1,13 @@ use core::{mem, slice}; - -#[cfg(not(feature = "std"))] -pub(crate) use hashbrown::HashMap; #[cfg(feature = "std")] pub(crate) use std::collections::HashMap; +#[cfg(feature = "std")] +pub(crate) use std::collections::HashSet; +#[cfg(not(feature = "std"))] +pub(crate) use hashbrown::HashMap; #[cfg(not(feature = "std"))] pub(crate) use hashbrown::HashSet; -#[cfg(feature = "std")] -pub(crate) use std::collections::HashSet; /// bytes_of converts a to a byte slice pub(crate) unsafe fn bytes_of(val: &T) -> &[u8] { diff --git a/aya-tool/src/bin/aya-tool.rs b/aya-tool/src/bin/aya-tool.rs index 4e12a020..759131d3 100644 --- a/aya-tool/src/bin/aya-tool.rs +++ b/aya-tool/src/bin/aya-tool.rs @@ -1,7 +1,6 @@ -use aya_tool::generate::{generate, InputFile}; - use std::{path::PathBuf, process::exit}; +use aya_tool::generate::{generate, InputFile}; use clap::Parser; #[derive(Parser)] diff --git a/aya-tool/src/generate.rs b/aya-tool/src/generate.rs index c8b97f6a..69658a04 100644 --- a/aya-tool/src/generate.rs +++ b/aya-tool/src/generate.rs @@ -7,7 +7,6 @@ use std::{ }; use tempfile::tempdir; - use thiserror::Error; use crate::bindgen; diff --git a/aya/Cargo.toml b/aya/Cargo.toml index 4e5eec16..74ef5660 100644 --- a/aya/Cargo.toml +++ b/aya/Cargo.toml @@ -12,6 +12,7 @@ edition = "2021" rust-version = "1.66" [dependencies] +assert_matches = { workspace = true } async-io = { workspace = true, optional = true } aya-obj = { workspace = true, features = ["std"] } bitflags = { workspace = true } @@ -19,24 +20,17 @@ bytes = { workspace = true } lazy_static = { workspace = true } libc = { workspace = true } log = { workspace = true } -object = { workspace = true, default-features = false, features = [ - "elf", - "read_core", - "std", -] } -parking_lot = { workspace = true } +object = { workspace = true, features = ["elf", "read_core", "std"] } thiserror = { workspace = true } tokio = { workspace = true, features = ["rt"], optional = true } [dev-dependencies] -assert_matches = { workspace = true } -futures = { workspace = true } tempfile = { workspace = true } [features] default = [] async_tokio = ["tokio/net"] -async_std = ["async-io"] +async_std = ["dep:async-io"] [package.metadata.docs.rs] all-features = true diff --git a/aya/README.md b/aya/README.md index 873612af..f64767f9 100644 --- a/aya/README.md +++ b/aya/README.md @@ -5,11 +5,10 @@ ![Build status][build-badge] [![Book][book-badge]][book-url] - [crates-badge]: https://img.shields.io/crates/v/aya.svg?style=for-the-badge&logo=rust [crates-url]: https://crates.io/crates/aya [license-badge]: https://img.shields.io/badge/license-MIT%2FApache--2.0-blue?style=for-the-badge -[build-badge]: https://img.shields.io/github/workflow/status/aya-rs/aya/build-aya?style=for-the-badge&logo=github +[build-badge]: https://img.shields.io/github/actions/workflow/status/aya-rs/aya/build-aya.yml?branch=main&style=for-the-badge [book-badge]: https://img.shields.io/badge/read%20the-book-9cf.svg?style=for-the-badge&logo=mdbook [book-url]: https://aya-rs.dev/book @@ -26,8 +25,8 @@ [![Discord][discord-badge]][chat-url] [![Awesome][awesome-badge]][awesome-aya] -Join [the conversation on Discord][chat-url] to discuss anything related to Aya, or discover -and contribute to a list of [Awesome Aya][awesome-aya] projects. +Join [the conversation on Discord][chat-url] to discuss anything related to Aya +or discover and contribute to a list of [Awesome Aya][awesome-aya] projects. [discord-badge]: https://img.shields.io/badge/Discord-chat-5865F2?style=for-the-badge&logo=discord [chat-url]: https://discord.gg/xHW2cb2N6G @@ -37,7 +36,7 @@ and contribute to a list of [Awesome Aya][awesome-aya] projects. ## Overview eBPF is a technology that allows running user-supplied programs inside the Linux -kernel. For more info see https://ebpf.io/what-is-ebpf. +kernel. For more info see [What is eBBF](https://ebpf.io/what-is-ebpf). Aya is an eBPF library built with a focus on operability and developer experience. It does not rely on [libbpf] nor [bcc] - it's built from the ground @@ -69,9 +68,8 @@ Some of the major features provided include: ### Example -Aya supports a large chunk of the eBPF API. The following example shows how to use a -`BPF_PROG_TYPE_CGROUP_SKB` program with aya: - +Aya supports a large chunk of the eBPF API. The following example shows how to +use a `BPF_PROG_TYPE_CGROUP_SKB` program with aya: ```rust use std::fs::File; @@ -96,12 +94,15 @@ ingress.attach(cgroup, CgroupSkbAttachType::Ingress)?; ## Contributing Please see the [contributing guide](https://github.com/aya-rs/aya/blob/main/CONTRIBUTING.md). + ## License -Aya is distributed under the terms of either the [MIT license] or the [Apache License] (version -2.0), at your option. +Aya is distributed under the terms of either the [MIT license] or the +[Apache License] (version 2.0), at your option. -Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. [MIT license]: https://github.com/aya-rs/aya/blob/main/LICENSE-MIT [Apache license]: https://github.com/aya-rs/aya/blob/main/LICENSE-APACHE diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index f5841f3f..6086dfa3 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -1,10 +1,9 @@ use std::{ borrow::Cow, collections::{HashMap, HashSet}, - ffi::CString, fs, io, os::{ - fd::{AsFd as _, OwnedFd}, + fd::{AsFd as _, AsRawFd as _, OwnedFd}, raw::c_int, }, path::{Path, PathBuf}, @@ -37,14 +36,14 @@ use crate::{ SkMsg, SkSkb, SkSkbKind, SockOps, SocketFilter, TracePoint, UProbe, Xdp, }, 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_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, + bpf_load_btf, is_bpf_cookie_supported, is_bpf_global_data_supported, + is_btf_datasec_supported, is_btf_decl_tag_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_id_supported, is_prog_name_supported, + retry_with_verifier_logs, }, - util::{bytes_of, bytes_of_slice, possible_cpus, POSSIBLE_CPUS}, + util::{bytes_of, bytes_of_slice, page_size, possible_cpus, POSSIBLE_CPUS}, }; pub(crate) const BPF_OBJ_NAME_LEN: usize = 16; @@ -71,7 +70,7 @@ unsafe impl Pod for [T; N] {} pub use aya_obj::maps::{bpf_map_def, PinningType}; -lazy_static! { +lazy_static::lazy_static! { pub(crate) static ref FEATURES: Features = detect_features(); } @@ -95,6 +94,8 @@ fn detect_features() -> Features { is_perf_link_supported(), is_bpf_global_data_supported(), is_bpf_cookie_supported(), + is_prog_id_supported(BPF_MAP_TYPE_CPUMAP), + is_prog_id_supported(BPF_MAP_TYPE_DEVMAP), btf, ); debug!("BPF Feature Detection: {:#?}", f); @@ -138,7 +139,7 @@ pub struct BpfLoader<'a> { allow_unsupported_maps: bool, } -bitflags! { +bitflags::bitflags! { /// Used to set the verifier log level flags in [BpfLoader](BpfLoader::verifier_log_level()). #[derive(Clone, Copy, Debug)] pub struct VerifierLogLevel: u32 { @@ -161,8 +162,8 @@ impl Default for VerifierLogLevel { impl<'a> BpfLoader<'a> { /// Creates a new loader instance. - pub fn new() -> BpfLoader<'a> { - BpfLoader { + pub fn new() -> Self { + Self { btf: Btf::from_sys_fs().ok().map(Cow::Owned), map_pin_path: None, globals: HashMap::new(), @@ -397,7 +398,7 @@ impl<'a> BpfLoader<'a> { if let Some(btf) = obj.fixup_and_sanitize_btf(features)? { match load_btf(btf.to_bytes(), *verifier_log_level) { Ok(btf_fd) => Some(Arc::new(btf_fd)), - // Only report an error here if the BTF is truely needed, otherwise proceed without. + // Only report an error here if the BTF is truly needed, otherwise proceed without. Err(err) => { for program in obj.programs.values() { match program.section { @@ -414,7 +415,10 @@ impl<'a> BpfLoader<'a> { | ProgramSection::URetProbe { sleepable: _ } | ProgramSection::TracePoint | ProgramSection::SocketFilter - | ProgramSection::Xdp { frags: _ } + | ProgramSection::Xdp { + frags: _, + attach_type: _, + } | ProgramSection::SkMsg | ProgramSection::SkSkbStreamParser | ProgramSection::SkSkbStreamVerdict @@ -457,49 +461,47 @@ impl<'a> BpfLoader<'a> { { continue; } - - match max_entries.get(name.as_str()) { - Some(size) => obj.set_max_entries(*size), - None => { - if obj.map_type() == BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32 - && obj.max_entries() == 0 - { - obj.set_max_entries( - possible_cpus() - .map_err(|error| BpfError::FileError { - path: PathBuf::from(POSSIBLE_CPUS), - error, - })? - .len() as u32, - ); - } + let num_cpus = || -> Result { + Ok(possible_cpus() + .map_err(|error| BpfError::FileError { + path: PathBuf::from(POSSIBLE_CPUS), + error, + })? + .len() as u32) + }; + let map_type: bpf_map_type = obj.map_type().try_into().map_err(MapError::from)?; + if let Some(max_entries) = max_entries_override( + map_type, + max_entries.get(name.as_str()).copied(), + || obj.max_entries(), + num_cpus, + || page_size() as u32, + )? { + obj.set_max_entries(max_entries) + } + match obj.map_type().try_into() { + Ok(BPF_MAP_TYPE_CPUMAP) => { + obj.set_value_size(if FEATURES.cpumap_prog_id() { 8 } else { 4 }) + } + Ok(BPF_MAP_TYPE_DEVMAP | BPF_MAP_TYPE_DEVMAP_HASH) => { + obj.set_value_size(if FEATURES.devmap_prog_id() { 8 } else { 4 }) } + _ => (), } 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 = map_pin_path.as_ref().ok_or(BpfError::NoPinPath)?; - MapData::create_pinned(path, obj, &name, btf_fd)? + // pin maps in /sys/fs/bpf by default to align with libbpf + // behavior https://github.com/libbpf/libbpf/blob/v1.2.2/src/libbpf.c#L2161. + let path = map_pin_path + .as_deref() + .unwrap_or_else(|| Path::new("/sys/fs/bpf")); + + MapData::create_pinned_by_name(path, obj, &name, btf_fd)? } }; - 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 { - call: "bpf_map_update_elem", - io_error, - }) - .map_err(MapError::from)?; - } - if map.obj.section_kind() == BpfSectionKind::Rodata { - bpf_map_freeze(fd) - .map_err(|(_, io_error)| SyscallError { - call: "bpf_map_freeze", - io_error, - }) - .map_err(MapError::from)?; - } + map.finalize()?; maps.insert(name, map); } @@ -511,7 +513,7 @@ impl<'a> BpfLoader<'a> { obj.relocate_maps( maps.iter() - .map(|(s, data)| (s.as_str(), data.fd, &data.obj)), + .map(|(s, data)| (s.as_str(), data.fd().as_fd().as_raw_fd(), data.obj())), &text_sections, )?; obj.relocate_calls(&text_sections)?; @@ -574,13 +576,18 @@ impl<'a> BpfLoader<'a> { ProgramSection::SocketFilter => Program::SocketFilter(SocketFilter { data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level), }), - ProgramSection::Xdp { frags, .. } => { + ProgramSection::Xdp { + frags, attach_type, .. + } => { let mut data = ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level); if *frags { data.flags = BPF_F_XDP_HAS_FRAGS; } - Program::Xdp(Xdp { data }) + Program::Xdp(Xdp { + data, + attach_type: *attach_type, + }) } ProgramSection::SkMsg => Program::SkMsg(SkMsg { data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level), @@ -608,10 +615,6 @@ impl<'a> BpfLoader<'a> { ProgramSection::SchedClassifier => { Program::SchedClassifier(SchedClassifier { data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level), - name: unsafe { - CString::from_vec_unchecked(Vec::from(name.clone())) - .into_boxed_c_str() - }, }) } ProgramSection::CgroupSkb => Program::CgroupSkb(CgroupSkb { @@ -696,7 +699,7 @@ impl<'a> BpfLoader<'a> { if !*allow_unsupported_maps { maps.iter().try_for_each(|(_, x)| match x { Map::Unsupported(map) => Err(BpfError::MapError(MapError::Unsupported { - map_type: map.obj.map_type(), + map_type: map.obj().map_type(), })), _ => Ok(()), })?; @@ -707,12 +710,8 @@ impl<'a> BpfLoader<'a> { } fn parse_map(data: (String, MapData)) -> Result<(String, Map), BpfError> { - let name = data.0; - let map = data.1; - let map_type = - bpf_map_type::try_from(map.obj.map_type()).map_err(|e| MapError::InvalidMapType { - map_type: e.map_type, - })?; + let (name, map) = data; + let map_type = bpf_map_type::try_from(map.obj().map_type()).map_err(MapError::from)?; let map = match map_type { BPF_MAP_TYPE_ARRAY => Map::Array(map), BPF_MAP_TYPE_PERCPU_ARRAY => Map::PerCpuArray(map), @@ -722,6 +721,7 @@ fn parse_map(data: (String, MapData)) -> Result<(String, Map), BpfError> { BPF_MAP_TYPE_PERCPU_HASH => Map::PerCpuHashMap(map), BPF_MAP_TYPE_LRU_PERCPU_HASH => Map::PerCpuLruHashMap(map), BPF_MAP_TYPE_PERF_EVENT_ARRAY => Map::PerfEventArray(map), + BPF_MAP_TYPE_RINGBUF => Map::RingBuf(map), BPF_MAP_TYPE_SOCKHASH => Map::SockHash(map), BPF_MAP_TYPE_SOCKMAP => Map::SockMap(map), BPF_MAP_TYPE_BLOOM_FILTER => Map::BloomFilter(map), @@ -729,6 +729,10 @@ fn parse_map(data: (String, MapData)) -> Result<(String, Map), BpfError> { BPF_MAP_TYPE_STACK => Map::Stack(map), BPF_MAP_TYPE_STACK_TRACE => Map::StackTraceMap(map), BPF_MAP_TYPE_QUEUE => Map::Queue(map), + BPF_MAP_TYPE_CPUMAP => Map::CpuMap(map), + BPF_MAP_TYPE_DEVMAP => Map::DevMap(map), + BPF_MAP_TYPE_DEVMAP_HASH => Map::DevMapHash(map), + BPF_MAP_TYPE_XSKMAP => Map::XskMap(map), m => { warn!("The map {name} is of type {:#?} which is currently unsupported in Aya, use `allow_unsupported_maps()` to load it anyways", m); Map::Unsupported(map) @@ -738,7 +742,106 @@ fn parse_map(data: (String, MapData)) -> Result<(String, Map), BpfError> { Ok((name, map)) } -impl<'a> Default for BpfLoader<'a> { +/// Computes the value which should be used to override the max_entries value of the map +/// based on the user-provided override and the rules for that map type. +fn max_entries_override( + map_type: bpf_map_type, + user_override: Option, + current_value: impl Fn() -> u32, + num_cpus: impl Fn() -> Result, + page_size: impl Fn() -> u32, +) -> Result, BpfError> { + let max_entries = || user_override.unwrap_or_else(¤t_value); + Ok(match map_type { + BPF_MAP_TYPE_PERF_EVENT_ARRAY if max_entries() == 0 => Some(num_cpus()?), + BPF_MAP_TYPE_RINGBUF => Some(adjust_to_page_size(max_entries(), page_size())) + .filter(|adjusted| *adjusted != max_entries()) + .or(user_override), + _ => user_override, + }) +} + +// Adjusts the byte size of a RingBuf map to match a power-of-two multiple of the page size. +// +// This mirrors the logic used by libbpf. +// See https://github.com/libbpf/libbpf/blob/ec6f716eda43/src/libbpf.c#L2461-L2463 +fn adjust_to_page_size(byte_size: u32, page_size: u32) -> u32 { + // If the byte_size is zero, return zero and let the verifier reject the map + // when it is loaded. This is the behavior of libbpf. + if byte_size == 0 { + return 0; + } + // TODO: Replace with primitive method when int_roundings (https://github.com/rust-lang/rust/issues/88581) + // is stabilized. + fn div_ceil(n: u32, rhs: u32) -> u32 { + let d = n / rhs; + let r = n % rhs; + if r > 0 && rhs > 0 { + d + 1 + } else { + d + } + } + let pages_needed = div_ceil(byte_size, page_size); + page_size * pages_needed.next_power_of_two() +} + +#[cfg(test)] +mod tests { + use crate::generated::bpf_map_type::*; + + const PAGE_SIZE: u32 = 4096; + const NUM_CPUS: u32 = 4; + + #[test] + fn test_adjust_to_page_size() { + use super::adjust_to_page_size; + [ + (0, 0), + (4096, 1), + (4096, 4095), + (4096, 4096), + (8192, 4097), + (8192, 8192), + (16384, 8193), + ] + .into_iter() + .for_each(|(exp, input)| assert_eq!(exp, adjust_to_page_size(input, PAGE_SIZE))) + } + + #[test] + fn test_max_entries_override() { + use super::max_entries_override; + [ + (BPF_MAP_TYPE_RINGBUF, Some(1), 1, Some(PAGE_SIZE)), + (BPF_MAP_TYPE_RINGBUF, None, 1, Some(PAGE_SIZE)), + (BPF_MAP_TYPE_RINGBUF, None, PAGE_SIZE, None), + (BPF_MAP_TYPE_PERF_EVENT_ARRAY, None, 1, None), + (BPF_MAP_TYPE_PERF_EVENT_ARRAY, Some(42), 1, Some(42)), + (BPF_MAP_TYPE_PERF_EVENT_ARRAY, Some(0), 1, Some(NUM_CPUS)), + (BPF_MAP_TYPE_PERF_EVENT_ARRAY, None, 0, Some(NUM_CPUS)), + (BPF_MAP_TYPE_PERF_EVENT_ARRAY, None, 42, None), + (BPF_MAP_TYPE_ARRAY, None, 1, None), + (BPF_MAP_TYPE_ARRAY, Some(2), 1, Some(2)), + ] + .into_iter() + .for_each(|(map_type, user_override, current_value, exp)| { + assert_eq!( + exp, + max_entries_override( + map_type, + user_override, + || { current_value }, + || Ok(NUM_CPUS), + || PAGE_SIZE + ) + .unwrap() + ) + }) + } +} + +impl Default for BpfLoader<'_> { fn default() -> Self { BpfLoader::new() } @@ -768,7 +871,7 @@ impl Bpf { /// let bpf = Bpf::load_file("file.o")?; /// # Ok::<(), aya::BpfError>(()) /// ``` - pub fn load_file>(path: P) -> Result { + pub fn load_file>(path: P) -> Result { BpfLoader::new() .btf(Btf::from_sys_fs().ok().as_ref()) .load_file(path) @@ -793,7 +896,7 @@ impl Bpf { /// let bpf = Bpf::load(&data)?; /// # Ok::<(), aya::BpfError>(()) /// ``` - pub fn load(data: &[u8]) -> Result { + pub fn load(data: &[u8]) -> Result { BpfLoader::new() .btf(Btf::from_sys_fs().ok().as_ref()) .load(data) @@ -854,6 +957,29 @@ impl Bpf { self.maps.iter().map(|(name, map)| (name.as_str(), map)) } + /// A mutable iterator over all the maps. + /// + /// # Examples + /// ```no_run + /// # use std::path::Path; + /// # #[derive(thiserror::Error, Debug)] + /// # enum Error { + /// # #[error(transparent)] + /// # Bpf(#[from] aya::BpfError), + /// # #[error(transparent)] + /// # Pin(#[from] aya::pin::PinError) + /// # } + /// # let mut bpf = aya::Bpf::load(&[])?; + /// # let pin_path = Path::new("/tmp/pin_path"); + /// for (_, map) in bpf.maps_mut() { + /// map.pin(pin_path)?; + /// } + /// # Ok::<(), Error>(()) + /// ``` + pub fn maps_mut(&mut self) -> impl Iterator { + self.maps.iter_mut().map(|(name, map)| (name.as_str(), map)) + } + /// Returns a reference to the program with the given name. /// /// You can use this to inspect a program and its properties. To load and attach a program, use @@ -949,10 +1075,6 @@ pub enum BpfError { error: io::Error, }, - /// Pinning requested but no path provided - #[error("pinning requested but no path provided")] - NoPinPath, - /// Unexpected pinning type #[error("unexpected pinning type {name}")] UnexpectedPinningType { @@ -960,13 +1082,6 @@ pub enum BpfError { name: u32, }, - /// Invalid path - #[error("invalid path `{error}`")] - InvalidPath { - /// The error message - error: String, - }, - /// Error parsing BPF object #[error("error parsing BPF object: {0}")] ParseError(#[from] ParseError), diff --git a/aya/src/lib.rs b/aya/src/lib.rs index 4ba70c2a..743ea26d 100644 --- a/aya/src/lib.rs +++ b/aya/src/lib.rs @@ -37,13 +37,47 @@ html_favicon_url = "https://aya-rs.dev/assets/images/crabby.svg" )] #![cfg_attr(docsrs, feature(doc_cfg))] -#![deny(clippy::all, missing_docs)] +#![deny( + clippy::all, + clippy::use_self, + absolute_paths_not_starting_with_crate, + deprecated_in_future, + elided_lifetimes_in_paths, + explicit_outlives_requirements, + ffi_unwind_calls, + keyword_idents, + //let_underscore_drop, + macro_use_extern_crate, + meta_variable_misuse, + missing_abi, + //missing_copy_implementations, + missing_docs, + non_ascii_idents, + noop_method_call, + pointer_structural_match, + rust_2021_incompatible_closure_captures, + rust_2021_incompatible_or_patterns, + rust_2021_prefixes_incompatible_syntax, + rust_2021_prelude_collisions, + single_use_lifetimes, + trivial_numeric_casts, + unreachable_pub, + //unsafe_op_in_unsafe_fn, + unstable_features, + unused_crate_dependencies, + unused_extern_crates, + unused_import_braces, + unused_lifetimes, + unused_macro_rules, + unused_qualifications, + //unused_results, + unused_tuple_struct_fields, +)] #![allow(clippy::missing_safety_doc, clippy::len_without_is_empty)] - -#[macro_use] -extern crate lazy_static; -#[macro_use] -extern crate bitflags; +#![cfg_attr( + all(feature = "async_tokio", feature = "async_std"), + allow(unused_crate_dependencies) +)] mod bpf; use aya_obj::generated; diff --git a/aya/src/maps/array/array.rs b/aya/src/maps/array/array.rs index 97bb46d6..9fdc91e3 100644 --- a/aya/src/maps/array/array.rs +++ b/aya/src/maps/array/array.rs @@ -1,6 +1,7 @@ use std::{ borrow::{Borrow, BorrowMut}, marker::PhantomData, + os::fd::AsFd as _, }; use crate::{ @@ -30,16 +31,16 @@ use crate::{ /// ``` #[doc(alias = "BPF_MAP_TYPE_ARRAY")] pub struct Array { - inner: T, + pub(crate) inner: T, _v: PhantomData, } impl, V: Pod> Array { - pub(crate) fn new(map: T) -> Result, MapError> { + pub(crate) fn new(map: T) -> Result { let data = map.borrow(); check_kv_size::(data)?; - Ok(Array { + Ok(Self { inner: map, _v: PhantomData, }) @@ -61,7 +62,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; + let fd = data.fd().as_fd(); let value = bpf_map_lookup_elem(fd, index, flags).map_err(|(_, io_error)| SyscallError { @@ -88,7 +89,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; + let fd = data.fd().as_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 6405af4a..9c261f0c 100644 --- a/aya/src/maps/array/per_cpu_array.rs +++ b/aya/src/maps/array/per_cpu_array.rs @@ -1,6 +1,7 @@ use std::{ borrow::{Borrow, BorrowMut}, marker::PhantomData, + os::fd::AsFd as _, }; use crate::{ @@ -49,16 +50,16 @@ use crate::{ /// ``` #[doc(alias = "BPF_MAP_TYPE_PERCPU_ARRAY")] pub struct PerCpuArray { - inner: T, + pub(crate) inner: T, _v: PhantomData, } impl, V: Pod> PerCpuArray { - pub(crate) fn new(map: T) -> Result, MapError> { + pub(crate) fn new(map: T) -> Result { let data = map.borrow(); check_kv_size::(data)?; - Ok(PerCpuArray { + Ok(Self { inner: map, _v: PhantomData, }) @@ -80,7 +81,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; + let fd = data.fd().as_fd(); let value = bpf_map_lookup_elem_per_cpu(fd, index, flags).map_err(|(_, io_error)| { SyscallError { @@ -108,7 +109,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; + let fd = data.fd().as_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 e2152b56..513bf77f 100644 --- a/aya/src/maps/array/program_array.rs +++ b/aya/src/maps/array/program_array.rs @@ -48,15 +48,15 @@ use crate::{ /// ``` #[doc(alias = "BPF_MAP_TYPE_PROG_ARRAY")] pub struct ProgramArray { - inner: T, + pub(crate) inner: T, } impl> ProgramArray { - pub(crate) fn new(map: T) -> Result, MapError> { + pub(crate) fn new(map: T) -> Result { let data = map.borrow(); check_kv_size::(data)?; - Ok(ProgramArray { inner: map }) + Ok(Self { inner: map }) } /// An iterator over the indices of the array that point to a program. The iterator item type @@ -74,7 +74,7 @@ impl> ProgramArray { 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; + let fd = data.fd().as_fd(); let prog_fd = program.as_fd(); let prog_fd = prog_fd.as_raw_fd(); @@ -94,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; + let fd = data.fd().as_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 84bff986..5c547fb0 100644 --- a/aya/src/maps/bloom_filter.rs +++ b/aya/src/maps/bloom_filter.rs @@ -2,6 +2,7 @@ use std::{ borrow::{Borrow, BorrowMut}, marker::PhantomData, + os::fd::AsFd as _, }; use crate::{ @@ -35,16 +36,16 @@ use crate::{ #[doc(alias = "BPF_MAP_TYPE_BLOOM_FILTER")] #[derive(Debug)] pub struct BloomFilter { - inner: T, + pub(crate) inner: T, _v: PhantomData, } impl, V: Pod> BloomFilter { - pub(crate) fn new(map: T) -> Result, MapError> { + pub(crate) fn new(map: T) -> Result { let data = map.borrow(); check_v_size::(data)?; - Ok(BloomFilter { + Ok(Self { inner: map, _v: PhantomData, }) @@ -52,7 +53,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; + let fd = self.inner.borrow().fd().as_fd(); bpf_map_lookup_elem_ptr::(fd, None, &mut value, flags) .map_err(|(_, io_error)| SyscallError { @@ -67,7 +68,7 @@ impl, V: Pod> BloomFilter { impl, V: Pod> BloomFilter { /// Inserts a value into the map. pub fn insert(&mut self, value: impl Borrow, flags: u64) -> Result<(), MapError> { - let fd = self.inner.borrow_mut().fd; + let fd = self.inner.borrow_mut().fd().as_fd(); bpf_map_push_elem(fd, value.borrow(), flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_push_elem", io_error, @@ -78,6 +79,11 @@ impl, V: Pod> BloomFilter { #[cfg(test)] mod tests { + use std::{ffi::c_long, io}; + + use assert_matches::assert_matches; + use libc::{EFAULT, ENOENT}; + use super::*; use crate::{ bpf_map_def, @@ -89,9 +95,6 @@ mod tests { obj::{self, maps::LegacyMap, BpfSectionKind}, sys::{override_syscall, SysResult, Syscall}, }; - use assert_matches::assert_matches; - use libc::{EFAULT, ENOENT}; - use std::{ffi::c_long, io}; fn new_obj_map() -> obj::Map { obj::Map::Legacy(LegacyMap { diff --git a/aya/src/maps/hash_map/hash_map.rs b/aya/src/maps/hash_map/hash_map.rs index b2f9e547..72c81b95 100644 --- a/aya/src/maps/hash_map/hash_map.rs +++ b/aya/src/maps/hash_map/hash_map.rs @@ -1,6 +1,7 @@ use std::{ borrow::{Borrow, BorrowMut}, marker::PhantomData, + os::fd::AsFd as _, }; use crate::{ @@ -33,17 +34,17 @@ use crate::{ #[doc(alias = "BPF_MAP_TYPE_LRU_HASH")] #[derive(Debug)] pub struct HashMap { - inner: T, + pub(crate) inner: T, _k: PhantomData, _v: PhantomData, } impl, K: Pod, V: Pod> HashMap { - pub(crate) fn new(map: T) -> Result, MapError> { + pub(crate) fn new(map: T) -> Result { let data = map.borrow(); check_kv_size::(data)?; - Ok(HashMap { + Ok(Self { inner: map, _k: PhantomData, _v: PhantomData, @@ -52,7 +53,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; + let fd = self.inner.borrow().fd().as_fd(); let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_lookup_elem", io_error, @@ -96,7 +97,7 @@ impl, K: Pod, V: Pod> IterableMap for HashMap } fn get(&self, key: &K) -> Result { - HashMap::get(self, key, 0) + Self::get(self, key, 0) } } @@ -107,44 +108,22 @@ mod tests { use assert_matches::assert_matches; use libc::{EFAULT, ENOENT}; + use super::{ + super::test_utils::{self, new_map}, + *, + }; use crate::{ - bpf_map_def, generated::{ bpf_attr, bpf_cmd, bpf_map_type::{BPF_MAP_TYPE_HASH, BPF_MAP_TYPE_LRU_HASH}, }, - maps::{Map, MapData}, - obj::{self, maps::LegacyMap, BpfSectionKind}, + maps::Map, + obj, sys::{override_syscall, SysResult, Syscall}, }; - use super::*; - fn new_obj_map() -> obj::Map { - obj::Map::Legacy(LegacyMap { - def: bpf_map_def { - map_type: BPF_MAP_TYPE_HASH as u32, - key_size: 4, - value_size: 4, - max_entries: 1024, - ..Default::default() - }, - section_index: 0, - section_kind: BpfSectionKind::Maps, - data: Vec::new(), - symbol_index: None, - }) - } - - 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() + test_utils::new_obj_map(BPF_MAP_TYPE_HASH) } fn sys_error(value: i32) -> SysResult { @@ -213,21 +192,10 @@ mod tests { #[test] fn test_try_from_ok_lru() { - 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); - + let map_data = || new_map(test_utils::new_obj_map(BPF_MAP_TYPE_LRU_HASH)); + let map = Map::HashMap(map_data()); + assert!(HashMap::<_, u32, u32>::try_from(&map).is_ok()); + let map = Map::LruHashMap(map_data()); assert!(HashMap::<_, u32, u32>::try_from(&map).is_ok()) } diff --git a/aya/src/maps/hash_map/mod.rs b/aya/src/maps/hash_map/mod.rs index 87fc0d70..31e0bc8b 100644 --- a/aya/src/maps/hash_map/mod.rs +++ b/aya/src/maps/hash_map/mod.rs @@ -1,4 +1,6 @@ //! Hash map types. +use std::os::fd::AsFd as _; + use crate::{ maps::MapError, sys::{bpf_map_delete_elem, bpf_map_update_elem, SyscallError}, @@ -20,7 +22,7 @@ pub(crate) fn insert( value: &V, flags: u64, ) -> Result<(), MapError> { - let fd = map.fd; + let fd = map.fd().as_fd(); bpf_map_update_elem(fd, Some(key), value, flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_update_elem", io_error, @@ -30,7 +32,7 @@ pub(crate) fn insert( } pub(crate) fn remove(map: &MapData, key: &K) -> Result<(), MapError> { - let fd = map.fd; + let fd = map.fd().as_fd(); bpf_map_delete_elem(fd, key) .map(|_| ()) .map_err(|(_, io_error)| { @@ -41,3 +43,41 @@ pub(crate) fn remove(map: &MapData, key: &K) -> Result<(), MapError> { .into() }) } + +#[cfg(test)] +mod test_utils { + use crate::{ + bpf_map_def, + generated::{bpf_cmd, bpf_map_type}, + maps::MapData, + obj::{self, maps::LegacyMap, BpfSectionKind}, + sys::{override_syscall, Syscall}, + }; + + pub(super) 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() + } + + pub(super) fn new_obj_map(map_type: bpf_map_type) -> obj::Map { + obj::Map::Legacy(LegacyMap { + def: bpf_map_def { + map_type: map_type as u32, + key_size: 4, + value_size: 4, + max_entries: 1024, + ..Default::default() + }, + section_index: 0, + section_kind: BpfSectionKind::Maps, + data: Vec::new(), + symbol_index: None, + }) + } +} 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 7fd90ec0..fe404ce0 100644 --- a/aya/src/maps/hash_map/per_cpu_hash_map.rs +++ b/aya/src/maps/hash_map/per_cpu_hash_map.rs @@ -2,6 +2,7 @@ use std::{ borrow::{Borrow, BorrowMut}, marker::PhantomData, + os::fd::AsFd as _, }; use crate::{ @@ -42,17 +43,17 @@ use crate::{ #[doc(alias = "BPF_MAP_TYPE_LRU_PERCPU_HASH")] #[doc(alias = "BPF_MAP_TYPE_PERCPU_HASH")] pub struct PerCpuHashMap { - inner: T, + pub(crate) inner: T, _k: PhantomData, _v: PhantomData, } impl, K: Pod, V: Pod> PerCpuHashMap { - pub(crate) fn new(map: T) -> Result, MapError> { + pub(crate) fn new(map: T) -> Result { let data = map.borrow(); check_kv_size::(data)?; - Ok(PerCpuHashMap { + Ok(Self { inner: map, _k: PhantomData, _v: PhantomData, @@ -61,7 +62,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; + let fd = self.inner.borrow().fd().as_fd(); let values = bpf_map_lookup_elem_per_cpu(fd, key, flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_lookup_elem", @@ -118,7 +119,7 @@ impl, K: Pod, V: Pod> PerCpuHashMap { values: PerCpuValues, flags: u64, ) -> Result<(), MapError> { - let fd = self.inner.borrow_mut().fd; + let fd = self.inner.borrow_mut().fd().as_fd(); bpf_map_update_elem_per_cpu(fd, key.borrow(), &values, flags).map_err( |(_, io_error)| SyscallError { call: "bpf_map_update_elem", @@ -143,6 +144,32 @@ impl, K: Pod, V: Pod> IterableMap> } fn get(&self, key: &K) -> Result, MapError> { - PerCpuHashMap::get(self, key, 0) + Self::get(self, key, 0) + } +} + +#[cfg(test)] +mod tests { + use super::{super::test_utils, *}; + use crate::{ + generated::bpf_map_type::{BPF_MAP_TYPE_LRU_PERCPU_HASH, BPF_MAP_TYPE_PERCPU_HASH}, + maps::Map, + }; + + #[test] + fn test_try_from_ok() { + let map = Map::PerCpuHashMap(test_utils::new_map(test_utils::new_obj_map( + BPF_MAP_TYPE_PERCPU_HASH, + ))); + assert!(PerCpuHashMap::<_, u32, u32>::try_from(&map).is_ok()) + } + #[test] + fn test_try_from_ok_lru() { + let map_data = + || test_utils::new_map(test_utils::new_obj_map(BPF_MAP_TYPE_LRU_PERCPU_HASH)); + let map = Map::PerCpuHashMap(map_data()); + assert!(PerCpuHashMap::<_, u32, u32>::try_from(&map).is_ok()); + let map = Map::PerCpuLruHashMap(map_data()); + assert!(PerCpuHashMap::<_, u32, u32>::try_from(&map).is_ok()) } } diff --git a/aya/src/maps/lpm_trie.rs b/aya/src/maps/lpm_trie.rs index d05ec2cf..139a9cb9 100644 --- a/aya/src/maps/lpm_trie.rs +++ b/aya/src/maps/lpm_trie.rs @@ -2,6 +2,7 @@ use std::{ borrow::{Borrow, BorrowMut}, marker::PhantomData, + os::fd::AsFd as _, }; use crate::{ @@ -47,7 +48,7 @@ use crate::{ #[doc(alias = "BPF_MAP_TYPE_LPM_TRIE")] #[derive(Debug)] pub struct LpmTrie { - inner: T, + pub(crate) inner: T, _k: PhantomData, _v: PhantomData, } @@ -113,11 +114,11 @@ impl Clone for Key { unsafe impl Pod for Key {} impl, K: Pod, V: Pod> LpmTrie { - pub(crate) fn new(map: T) -> Result, MapError> { + pub(crate) fn new(map: T) -> Result { let data = map.borrow(); check_kv_size::, V>(data)?; - Ok(LpmTrie { + Ok(Self { inner: map, _k: PhantomData, _v: PhantomData, @@ -126,7 +127,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; + let fd = self.inner.borrow().fd().as_fd(); let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_lookup_elem", io_error, @@ -155,7 +156,7 @@ impl, K: Pod, V: Pod> LpmTrie { value: impl Borrow, flags: u64, ) -> Result<(), MapError> { - let fd = self.inner.borrow().fd; + let fd = self.inner.borrow().fd().as_fd(); bpf_map_update_elem(fd, Some(key), value.borrow(), flags).map_err(|(_, io_error)| { SyscallError { call: "bpf_map_update_elem", @@ -170,7 +171,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; + let fd = self.inner.borrow().fd().as_fd(); bpf_map_delete_elem(fd, key) .map(|_| ()) .map_err(|(_, io_error)| { @@ -195,6 +196,11 @@ impl, K: Pod, V: Pod> IterableMap, V> for LpmTrie obj::Map { obj::Map::Legacy(LegacyMap { diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index 8458989c..c81e7bb0 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -5,30 +5,41 @@ //! [`Bpf::load_file`](crate::Bpf::load_file) or //! [`Bpf::load`](crate::Bpf::load), all the maps defined in the eBPF code get //! initialized and can then be accessed using [`Bpf::map`](crate::Bpf::map), -//! [`Bpf::map_mut`](crate::Bpf::map_mut), or [`Bpf::take_map`](crate::Bpf::take_map). +//! [`Bpf::map_mut`](crate::Bpf::map_mut), or +//! [`Bpf::take_map`](crate::Bpf::take_map). //! //! # Typed maps //! //! The eBPF API includes many map types each supporting different operations. //! [`Bpf::map`](crate::Bpf::map), [`Bpf::map_mut`](crate::Bpf::map_mut), and -//! [`Bpf::take_map`](crate::Bpf::take_map) always return the -//! opaque [`&Map`](crate::maps::Map), [`&mut Map`](crate::maps::Map), and [`Map`](crate::maps::Map) +//! [`Bpf::take_map`](crate::Bpf::take_map) always return the opaque +//! [`&Map`](crate::maps::Map), [`&mut Map`](crate::maps::Map), and [`Map`] //! types respectively. Those three types can be converted to *typed maps* using -//! the [`TryFrom`](std::convert::TryFrom) or [`TryInto`](std::convert::TryInto) -//! trait. For example: +//! the [`TryFrom`] or [`TryInto`] trait. For example: //! //! ```no_run +//! # #[derive(Debug, thiserror::Error)] +//! # enum Error { +//! # #[error(transparent)] +//! # IO(#[from] std::io::Error), +//! # #[error(transparent)] +//! # Map(#[from] aya::maps::MapError), +//! # #[error(transparent)] +//! # Program(#[from] aya::programs::ProgramError), +//! # #[error(transparent)] +//! # Bpf(#[from] aya::BpfError) +//! # } //! # let mut bpf = aya::Bpf::load(&[])?; //! use aya::maps::SockMap; //! use aya::programs::SkMsg; //! //! let intercept_egress = SockMap::try_from(bpf.map_mut("INTERCEPT_EGRESS").unwrap())?; -//! let map_fd = intercept_egress.fd()?; +//! let map_fd = intercept_egress.fd().try_clone()?; //! let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?; //! prog.load()?; -//! prog.attach(map_fd)?; +//! prog.attach(&map_fd)?; //! -//! # Ok::<(), aya::BpfError>(()) +//! # Ok::<(), Error>(()) //! ``` //! //! # Maps and `Pod` values @@ -37,29 +48,32 @@ //! versa. Because of that, all map values must be plain old data and therefore //! implement the [Pod] trait. use std::{ - ffi::CString, + borrow::BorrowMut, + ffi::{c_long, CString}, fmt, io, marker::PhantomData, mem, ops::Deref, - os::fd::{AsFd as _, AsRawFd, BorrowedFd, IntoRawFd as _, OwnedFd, RawFd}, + os::fd::{AsFd, BorrowedFd, OwnedFd}, path::Path, ptr, }; -use crate::util::KernelVersion; -use libc::{getrlimit, rlimit, RLIMIT_MEMLOCK, RLIM_INFINITY}; +use libc::{getrlimit, rlim_t, rlimit, RLIMIT_MEMLOCK, RLIM_INFINITY}; use log::warn; +use obj::maps::InvalidMapTypeError; use thiserror::Error; use crate::{ - obj::{self, parse_map_info}, + generated::bpf_map_info, + obj::{self, parse_map_info, BpfSectionKind}, pin::PinError, sys::{ - bpf_create_map, bpf_get_object, bpf_map_get_info_by_fd, bpf_map_get_next_key, - bpf_pin_object, SyscallError, + bpf_create_map, bpf_get_object, bpf_map_freeze, bpf_map_get_fd_by_id, + bpf_map_get_info_by_fd, bpf_map_get_next_key, bpf_map_update_elem_ptr, bpf_pin_object, + iter_map_ids, SyscallError, }, - util::nr_cpus, + util::{bytes_of_bpf_name, nr_cpus, KernelVersion}, PinningType, Pod, }; @@ -69,9 +83,11 @@ pub mod hash_map; pub mod lpm_trie; pub mod perf; pub mod queue; +pub mod ring_buf; pub mod sock; pub mod stack; pub mod stack_trace; +pub mod xdp; pub use array::{Array, PerCpuArray, ProgramArray}; pub use bloom_filter::BloomFilter; @@ -82,9 +98,11 @@ pub use lpm_trie::LpmTrie; pub use perf::AsyncPerfEventArray; pub use perf::PerfEventArray; pub use queue::Queue; +pub use ring_buf::RingBuf; pub use sock::{SockHash, SockMap}; pub use stack::Stack; pub use stack_trace::StackTraceMap; +pub use xdp::{CpuMap, DevMap, DevMapHash, XskMap}; #[derive(Error, Debug)] /// Errors occuring from working with Maps @@ -109,7 +127,7 @@ pub enum MapError { /// Map name name: String, /// Error code - code: libc::c_long, + code: c_long, #[source] /// Original io::Error io_error: io::Error, @@ -158,8 +176,8 @@ pub enum MapError { #[error(transparent)] SyscallError(#[from] SyscallError), - /// Could not pin map by name - #[error("map `{name:?}` requested pinning by name. pinning failed")] + /// Could not pin map + #[error("map `{name:?}` requested pinning. pinning failed")] PinError { /// The map name name: Option, @@ -168,6 +186,10 @@ pub enum MapError { error: PinError, }, + /// Program IDs are not supported + #[error("program ids are not supported by the current kernel")] + ProgIdNotSupported, + /// Unsupported Map type #[error("Unsupported map type found {map_type}")] Unsupported { @@ -176,26 +198,24 @@ pub enum MapError { }, } -/// A map file descriptor. -pub struct MapFd(RawFd); - -impl AsRawFd for MapFd { - fn as_raw_fd(&self) -> RawFd { - self.0 +// Note that this is not just derived using #[from] because InvalidMapTypeError cannot implement +// Error due the the fact that aya-obj is no_std and error_in_core is not stabilized +// (https://github.com/rust-lang/rust/issues/103765). +impl From for MapError { + fn from(e: InvalidMapTypeError) -> Self { + let InvalidMapTypeError { map_type } = e; + Self::InvalidMapType { map_type } } } -#[derive(PartialEq, Eq, PartialOrd, Ord)] -struct RlimitSize(usize); -impl fmt::Display for RlimitSize { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.0 < 1024 { - write!(f, "{} bytes", self.0) - } else if self.0 < 1024 * 1024 { - write!(f, "{} KiB", self.0 / 1024) - } else { - write!(f, "{} MiB", self.0 / 1024 / 1024) - } +/// A map file descriptor. +#[derive(Debug)] +pub struct MapFd(OwnedFd); + +impl AsFd for MapFd { + fn as_fd(&self) -> BorrowedFd<'_> { + let Self(fd) = self; + fd.as_fd() } } @@ -207,15 +227,28 @@ fn maybe_warn_rlimit() { if ret == 0 { let limit = unsafe { limit.assume_init() }; - let limit: RlimitSize = RlimitSize(limit.rlim_cur.try_into().unwrap()); - if limit.0 == RLIM_INFINITY.try_into().unwrap() { + if limit.rlim_cur == RLIM_INFINITY { return; } + struct HumanSize(rlim_t); + + impl fmt::Display for HumanSize { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let &Self(size) = self; + if size < 1024 { + write!(f, "{} bytes", size) + } else if size < 1024 * 1024 { + write!(f, "{} KiB", size / 1024) + } else { + write!(f, "{} MiB", size / 1024 / 1024) + } + } + } warn!( - "RLIMIT_MEMLOCK value is {}, not RLIM_INFNITY; if experiencing problems with creating \ - maps, try raising RMILIT_MEMLOCK either to RLIM_INFINITY or to a higher value sufficient \ - for size of your maps", - limit + "RLIMIT_MEMLOCK value is {}, not RLIM_INFINITY; if experiencing problems with creating \ + maps, try raising RLIMIT_MEMLOCK either to RLIM_INFINITY or to a higher value sufficient \ + for the size of your maps", + HumanSize(limit.rlim_cur) ); } } @@ -223,213 +256,242 @@ fn maybe_warn_rlimit() { /// eBPF map types. #[derive(Debug)] pub enum Map { - /// A [`Array`] map + /// An [`Array`] map. Array(MapData), - /// A [`PerCpuArray`] map - PerCpuArray(MapData), - /// A [`ProgramArray`] map - ProgramArray(MapData), - /// A [`HashMap`] map + /// A [`BloomFilter`] map. + BloomFilter(MapData), + /// A [`CpuMap`] map. + CpuMap(MapData), + /// A [`DevMap`] map. + DevMap(MapData), + /// A [`DevMapHash`] map. + DevMapHash(MapData), + /// A [`HashMap`] map. HashMap(MapData), - /// A [`PerCpuHashMap`] map - PerCpuHashMap(MapData), + /// A [`LpmTrie`] map. + LpmTrie(MapData), /// A [`HashMap`] map that uses a LRU eviction policy. LruHashMap(MapData), + /// A [`PerCpuArray`] map. + PerCpuArray(MapData), + /// A [`PerCpuHashMap`] map. + PerCpuHashMap(MapData), /// A [`PerCpuHashMap`] map that uses a LRU eviction policy. PerCpuLruHashMap(MapData), - /// A [`PerfEventArray`] map + /// A [`PerfEventArray`] map. PerfEventArray(MapData), - /// A [`SockMap`] map - SockMap(MapData), + /// A [`ProgramArray`] map. + ProgramArray(MapData), + /// A [`Queue`] map. + Queue(MapData), + /// A [`RingBuf`] map. + RingBuf(MapData), /// A [`SockHash`] map SockHash(MapData), - /// A [`BloomFilter`] map - BloomFilter(MapData), - /// A [`LpmTrie`] map - LpmTrie(MapData), - /// A [`Stack`] map + /// A [`SockMap`] map. + SockMap(MapData), + /// A [`Stack`] map. Stack(MapData), - /// A [`StackTraceMap`] map + /// A [`StackTraceMap`] map. StackTraceMap(MapData), - /// A [`Queue`] map - Queue(MapData), - /// An unsupported map type + /// An unsupported map type. Unsupported(MapData), + /// A [`XskMap`] map. + XskMap(MapData), } impl Map { /// Returns the low level map type. fn map_type(&self) -> u32 { match self { - Map::Array(map) => map.obj.map_type(), - Map::PerCpuArray(map) => map.obj.map_type(), - Map::ProgramArray(map) => map.obj.map_type(), - Map::HashMap(map) => map.obj.map_type(), - Map::LruHashMap(map) => map.obj.map_type(), - Map::PerCpuHashMap(map) => map.obj.map_type(), - Map::PerCpuLruHashMap(map) => map.obj.map_type(), - Map::PerfEventArray(map) => map.obj.map_type(), - Map::SockHash(map) => map.obj.map_type(), - Map::SockMap(map) => map.obj.map_type(), - Map::BloomFilter(map) => map.obj.map_type(), - Map::LpmTrie(map) => map.obj.map_type(), - Map::Stack(map) => map.obj.map_type(), - Map::StackTraceMap(map) => map.obj.map_type(), - Map::Queue(map) => map.obj.map_type(), - Map::Unsupported(map) => map.obj.map_type(), + Self::Array(map) => map.obj.map_type(), + Self::BloomFilter(map) => map.obj.map_type(), + Self::CpuMap(map) => map.obj.map_type(), + Self::DevMap(map) => map.obj.map_type(), + Self::DevMapHash(map) => map.obj.map_type(), + Self::HashMap(map) => map.obj.map_type(), + Self::LpmTrie(map) => map.obj.map_type(), + Self::LruHashMap(map) => map.obj.map_type(), + Self::PerCpuArray(map) => map.obj.map_type(), + Self::PerCpuHashMap(map) => map.obj.map_type(), + Self::PerCpuLruHashMap(map) => map.obj.map_type(), + Self::PerfEventArray(map) => map.obj.map_type(), + Self::ProgramArray(map) => map.obj.map_type(), + Self::Queue(map) => map.obj.map_type(), + Self::RingBuf(map) => map.obj.map_type(), + Self::SockHash(map) => map.obj.map_type(), + Self::SockMap(map) => map.obj.map_type(), + Self::Stack(map) => map.obj.map_type(), + Self::StackTraceMap(map) => map.obj.map_type(), + Self::Unsupported(map) => map.obj.map_type(), + Self::XskMap(map) => map.obj.map_type(), } } -} - -macro_rules! impl_try_from_map { - ($($tx:ident from Map::$ty:ident),+ $(,)?) => { - $( - impl<'a> TryFrom<&'a Map> for $tx<&'a MapData> { - type Error = MapError; - - fn try_from(map: &'a Map) -> Result<$tx<&'a MapData>, MapError> { - match map { - Map::$ty(m) => { - $tx::new(m) - }, - _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}), - } - } - } - impl<'a,> TryFrom<&'a mut Map> for $tx<&'a mut MapData> { - type Error = MapError; + /// Pins the map to a BPF filesystem. + /// + /// When a map is pinned it will remain loaded until the corresponding file + /// is deleted. All parent directories in the given `path` must already exist. + pub fn pin>(&mut self, path: P) -> Result<(), PinError> { + match self { + Self::Array(map) => map.pin(path), + Self::BloomFilter(map) => map.pin(path), + Self::CpuMap(map) => map.pin(path), + Self::DevMap(map) => map.pin(path), + Self::DevMapHash(map) => map.pin(path), + Self::HashMap(map) => map.pin(path), + Self::LpmTrie(map) => map.pin(path), + Self::LruHashMap(map) => map.pin(path), + Self::PerCpuArray(map) => map.pin(path), + Self::PerCpuHashMap(map) => map.pin(path), + Self::PerCpuLruHashMap(map) => map.pin(path), + Self::PerfEventArray(map) => map.pin(path), + Self::ProgramArray(map) => map.pin(path), + Self::Queue(map) => map.pin(path), + Self::RingBuf(map) => map.pin(path), + Self::SockHash(map) => map.pin(path), + Self::SockMap(map) => map.pin(path), + Self::Stack(map) => map.pin(path), + Self::StackTraceMap(map) => map.pin(path), + Self::Unsupported(map) => map.pin(path), + Self::XskMap(map) => map.pin(path), + } + } +} - fn try_from(map: &'a mut Map) -> Result<$tx<&'a mut MapData>, MapError> { - match map { - Map::$ty(m) => { - $tx::new(m) - }, - _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}), +// Implements map pinning for different map implementations +// TODO add support for PerfEventArrays and AsyncPerfEventArrays +macro_rules! impl_map_pin { + ($ty_param:tt { + $($ty:ident),+ $(,)? + }) => { + $(impl_map_pin!(<$ty_param> $ty);)+ + }; + ( + <($($ty_param:ident),*)> + $ty:ident + ) => { + impl, $($ty_param: Pod),*> $ty + { + /// Pins the map to a BPF filesystem. + /// + /// When a map is pinned it will remain loaded until the corresponding file + /// is deleted. All parent directories in the given `path` must already exist. + pub fn pin>(&mut self, path: P) -> Result<(), PinError> { + let data = self.inner.borrow_mut(); + data.pin(path) } - } } - impl TryFrom for $tx { - type Error = MapError; + }; +} - fn try_from(map: Map) -> Result<$tx, MapError> { - match map { - Map::$ty(m) => { - $tx::new(m) - }, - _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}), - } +impl_map_pin!(() { + ProgramArray, + SockMap, + StackTraceMap, + CpuMap, + DevMap, + DevMapHash, + XskMap, +}); + +impl_map_pin!((V) { + Array, + PerCpuArray, + SockHash, + BloomFilter, + Queue, + Stack, +}); + +impl_map_pin!((K, V) { + HashMap, + PerCpuHashMap, + LpmTrie, +}); + +// Implements TryFrom for different map implementations. Different map implementations can be +// constructed from different variants of the map enum. Also, the implementation may have type +// parameters (which we assume all have the bound `Pod` and nothing else). +macro_rules! impl_try_from_map { + // At the root the type parameters are marked as a single token tree which will be pasted into + // the invocation for each type. Note that the later patterns require that the token tree be + // zero or more comma separated idents wrapped in parens. Note that the tt metavar is used here + // rather than the repeated idents used later because the macro language does not allow one + // repetition to be pasted inside another. + ($ty_param:tt { + $($ty:ident $(from $($variant:ident)|+)?),+ $(,)? + }) => { + $(impl_try_from_map!(<$ty_param> $ty $(from $($variant)|+)?);)+ + }; + // Add the "from $variant" using $ty as the default if it is missing. + (<$ty_param:tt> $ty:ident) => { + impl_try_from_map!(<$ty_param> $ty from $ty); + }; + // Dispatch for each of the lifetimes. + ( + <($($ty_param:ident),*)> $ty:ident from $($variant:ident)|+ + ) => { + impl_try_from_map!(<'a> ($($ty_param),*) $ty from $($variant)|+); + impl_try_from_map!(<'a mut> ($($ty_param),*) $ty from $($variant)|+); + impl_try_from_map!(<> ($($ty_param),*) $ty from $($variant)|+); + }; + // An individual impl. + ( + <$($l:lifetime $($m:ident)?)?> + ($($ty_param:ident),*) + $ty:ident from $($variant:ident)|+ + ) => { + impl<$($l,)? $($ty_param: Pod),*> TryFrom<$(&$l $($m)?)? Map> + for $ty<$(&$l $($m)?)? MapData, $($ty_param),*> + { + type Error = MapError; + + fn try_from(map: $(&$l $($m)?)? Map) -> Result { + match map { + $(Map::$variant(map_data) => Self::new(map_data),)+ + map => Err(MapError::InvalidMapType { + map_type: map.map_type() + }), } } - )+ - } + } + }; } -impl_try_from_map!( - ProgramArray from Map::ProgramArray, - SockMap from Map::SockMap, - PerfEventArray from Map::PerfEventArray, - StackTraceMap from Map::StackTraceMap, -); +impl_try_from_map!(() { + CpuMap, + DevMap, + DevMapHash, + PerfEventArray, + ProgramArray, + RingBuf, + SockMap, + StackTraceMap, + XskMap, +}); #[cfg(any(feature = "async_tokio", feature = "async_std"))] #[cfg_attr(docsrs, doc(cfg(any(feature = "async_tokio", feature = "async_std"))))] -impl_try_from_map!( - AsyncPerfEventArray from Map::PerfEventArray, -); - -macro_rules! impl_try_from_map_generic_key_or_value { - ($($ty:ident),+ $(,)?) => { - $( - impl<'a, V:Pod> TryFrom<&'a Map> for $ty<&'a MapData, V> { - type Error = MapError; - - fn try_from(map: &'a Map) -> Result<$ty<&'a MapData , V>, MapError> { - match map { - Map::$ty(m) => { - $ty::new(m) - }, - _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}), - } - } - } - - impl<'a,V: Pod> TryFrom<&'a mut Map> for $ty<&'a mut MapData, V> { - type Error = MapError; - - fn try_from(map: &'a mut Map) -> Result<$ty<&'a mut MapData, V>, MapError> { - match map { - Map::$ty(m) => { - $ty::new(m) - }, - _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}), - } - } - } - - impl TryFrom for $ty { - type Error = MapError; - - fn try_from(map: Map) -> Result<$ty, MapError> { - match map { - Map::$ty(m) => { - $ty::new(m) - }, - _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}), - } - } - } - )+ - } -} - -impl_try_from_map_generic_key_or_value!(Array, PerCpuArray, SockHash, BloomFilter, Queue, Stack,); - -macro_rules! impl_try_from_map_generic_key_and_value { - ($($ty:ident),+ $(,)?) => { - $( - impl<'a, V: Pod, K: Pod> TryFrom<&'a Map> for $ty<&'a MapData, V, K> { - type Error = MapError; - - fn try_from(map: &'a Map) -> Result<$ty<&'a MapData,V,K>, MapError> { - match map { - Map::$ty(m) => { - $ty::new(m) - }, - _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}), - } - } - } - - impl<'a,V: Pod,K: Pod> TryFrom<&'a mut Map> for $ty<&'a mut MapData, V, K> { - type Error = MapError; - - fn try_from(map: &'a mut Map) -> Result<$ty<&'a mut MapData, V, K>, MapError> { - match map { - Map::$ty(m) => { - $ty::new(m) - }, - _ => Err(MapError::InvalidMapType{ map_type: map.map_type()}), - } - } - } - - impl TryFrom for $ty { - type Error = MapError; - - fn try_from(map: Map) -> Result<$ty, MapError> { - match map { - Map::$ty(m) => $ty::new(m), - _ => Err(MapError::InvalidMapType { map_type: map.map_type() }), - } - } - } - )+ - } -} - -impl_try_from_map_generic_key_and_value!(HashMap, PerCpuHashMap, LpmTrie); +impl_try_from_map!(() { + AsyncPerfEventArray from PerfEventArray, +}); + +impl_try_from_map!((V) { + Array, + BloomFilter, + PerCpuArray, + Queue, + SockHash, + Stack, +}); + +impl_try_from_map!((K, V) { + HashMap from HashMap|LruHashMap, + LpmTrie, + PerCpuHashMap from PerCpuHashMap|PerCpuLruHashMap, +}); pub(crate) fn check_bounds(map: &MapData, index: u32) -> Result<(), MapError> { let max_entries = map.obj.max_entries(); @@ -468,10 +530,8 @@ pub(crate) fn check_v_size(map: &MapData) -> Result<(), MapError> { /// You should never need to use this unless you're implementing a new map type. #[derive(Debug)] pub struct MapData { - pub(crate) obj: obj::Map, - pub(crate) fd: RawFd, - /// Indicates if this map has been pinned to bpffs - pub pinned: bool, + obj: obj::Map, + fd: MapFd, } impl MapData { @@ -499,35 +559,40 @@ impl MapData { io_error, } })?; - - Ok(Self { - obj, - fd: fd as RawFd, - pinned: false, - }) + let fd = MapFd(fd); + Ok(Self { obj, fd }) } - pub(crate) fn create_pinned>( + pub(crate) fn create_pinned_by_name>( path: P, obj: obj::Map, name: &str, btf_fd: Option>, ) -> Result { + use std::os::unix::ffi::OsStrExt as _; + // 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 path = path.as_ref().join(name); + let path_string = match CString::new(path.as_os_str().as_bytes()) { + Ok(path) => path, + Err(error) => { + return Err(MapError::PinError { + name: Some(name.into()), + error: PinError::InvalidPinPath { path, error }, + }); + } + }; match bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError { call: "BPF_OBJ_GET", io_error, }) { - Ok(fd) => Ok(Self { - obj, - fd: fd.into_raw_fd(), - pinned: false, - }), + Ok(fd) => { + let fd = MapFd(fd); + Ok(Self { obj, fd }) + } Err(_) => { let mut map = Self::create(obj, name, btf_fd)?; - map.pin(name, path).map_err(|error| MapError::PinError { + map.pin(&path).map_err(|error| MapError::PinError { name: Some(name.into()), error, })?; @@ -536,16 +601,39 @@ impl MapData { } } + pub(crate) fn finalize(&mut self) -> Result<(), MapError> { + let Self { obj, fd } = self; + if !obj.data().is_empty() && obj.section_kind() != BpfSectionKind::Bss { + bpf_map_update_elem_ptr(fd.as_fd(), &0 as *const _, obj.data_mut().as_mut_ptr(), 0) + .map_err(|(_, io_error)| SyscallError { + call: "bpf_map_update_elem", + io_error, + }) + .map_err(MapError::from)?; + } + if obj.section_kind() == BpfSectionKind::Rodata { + bpf_map_freeze(fd.as_fd()) + .map_err(|(_, io_error)| SyscallError { + call: "bpf_map_freeze", + io_error, + }) + .map_err(MapError::from)?; + } + Ok(()) + } + /// Loads a map from a pinned path in bpffs. - pub fn from_pin>(path: P) -> Result { + pub fn from_pin>(path: P) -> Result { + use std::os::unix::ffi::OsStrExt as _; + + let path = path.as_ref(); let path_string = - CString::new(path.as_ref().to_string_lossy().into_owned()).map_err(|e| { - MapError::PinError { - name: None, - error: PinError::InvalidPinPath { - error: e.to_string(), - }, - } + CString::new(path.as_os_str().as_bytes()).map_err(|error| MapError::PinError { + name: None, + error: PinError::InvalidPinPath { + path: path.into(), + error, + }, })?; let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError { @@ -553,13 +641,13 @@ impl MapData { io_error, })?; - let info = bpf_map_get_info_by_fd(fd.as_fd())?; + Self::from_fd(fd) + } - Ok(MapData { - obj: parse_map_info(info, PinningType::ByName), - fd: fd.into_raw_fd(), - pinned: true, - }) + /// Loads a map from a map id. + pub fn from_id(id: u32) -> Result { + let fd = bpf_map_get_fd_by_id(id)?; + Self::from_fd(fd) } /// Loads a map from a file descriptor. @@ -567,60 +655,70 @@ impl MapData { /// If loading from a BPF Filesystem (bpffs) you should use [`Map::from_pin`](crate::maps::MapData::from_pin). /// This API is intended for cases where you have received a valid BPF FD from some other means. /// For example, you received an FD over Unix Domain Socket. - pub fn from_fd(fd: OwnedFd) -> Result { - let info = bpf_map_get_info_by_fd(fd.as_fd())?; - - Ok(MapData { + pub fn from_fd(fd: OwnedFd) -> Result { + let MapInfo(info) = MapInfo::new_from_fd(fd.as_fd())?; + Ok(Self { obj: parse_map_info(info, PinningType::None), - fd: fd.into_raw_fd(), - pinned: false, + fd: MapFd(fd), }) } - pub(crate) fn pin>(&mut self, name: &str, path: P) -> Result<(), PinError> { - let Self { fd, pinned, obj: _ } = self; - if *pinned { - return Err(PinError::AlreadyPinned { name: name.into() }); - } - let map_path = path.as_ref().join(name); - let path_string = CString::new(map_path.to_string_lossy().into_owned()).map_err(|e| { + /// Allows the map to be pinned to the provided path. + /// + /// Any directories in the the path provided should have been created by the caller. + /// The path must be on a BPF filesystem. + /// + /// # Errors + /// + /// Returns a [`PinError::SyscallError`] if the underlying syscall fails. + /// This may also happen if the path already exists, in which case the wrapped + /// [`std::io::Error`] kind will be [`std::io::ErrorKind::AlreadyExists`]. + /// Returns a [`PinError::InvalidPinPath`] if the path provided cannot be + /// converted to a [`CString`]. + /// + /// # Example + /// + /// ```no_run + /// # let mut bpf = aya::Bpf::load(&[])?; + /// # use aya::maps::MapData; + /// + /// let mut map = MapData::from_pin("/sys/fs/bpf/my_map")?; + /// map.pin("/sys/fs/bpf/my_map2")?; + /// + /// # Ok::<(), Box>(()) + /// ``` + pub fn pin>(&mut self, path: P) -> Result<(), PinError> { + use std::os::unix::ffi::OsStrExt as _; + + let Self { fd, obj: _ } = self; + let path = path.as_ref(); + let path_string = CString::new(path.as_os_str().as_bytes()).map_err(|error| { PinError::InvalidPinPath { - error: e.to_string(), + path: path.to_path_buf(), + error, } })?; - bpf_pin_object(*fd, &path_string).map_err(|(_, io_error)| SyscallError { + bpf_pin_object(fd.as_fd(), &path_string).map_err(|(_, io_error)| SyscallError { call: "BPF_OBJ_PIN", io_error, })?; - *pinned = true; Ok(()) } /// Returns the file descriptor of the map. - /// - /// Can be converted to [`RawFd`] using [`AsRawFd`]. - pub fn fd(&self) -> MapFd { - MapFd(self.fd) + pub fn fd(&self) -> &MapFd { + let Self { obj: _, fd } = self; + fd } -} -impl Drop for MapData { - fn drop(&mut self) { - // TODO: Replace this with an OwnedFd once that is stabilized. - // - // SAFETY: `drop` is only called once. - unsafe { libc::close(self.fd) }; + pub(crate) fn obj(&self) -> &obj::Map { + let Self { obj, fd: _ } = self; + obj } -} -impl Clone for MapData { - fn clone(&self) -> Self { - let Self { obj, fd, pinned } = self; - Self { - obj: obj.clone(), - fd: unsafe { libc::dup(*fd) }, - pinned: *pinned, - } + /// Returns the kernel's information about the loaded map. + pub fn info(&self) -> Result { + MapInfo::new_from_fd(self.fd.as_fd()) } } @@ -641,8 +739,8 @@ pub struct MapKeys<'coll, K: Pod> { } impl<'coll, K: Pod> MapKeys<'coll, K> { - fn new(map: &'coll MapData) -> MapKeys<'coll, K> { - MapKeys { + fn new(map: &'coll MapData) -> Self { + Self { map, err: false, key: None, @@ -658,7 +756,7 @@ impl Iterator for MapKeys<'_, K> { return None; } - let fd = self.map.fd; + let fd = self.map.fd().as_fd(); let key = bpf_map_get_next_key(fd, self.key.as_ref()).map_err(|(_, io_error)| SyscallError { call: "bpf_map_get_next_key", @@ -685,8 +783,8 @@ pub struct MapIter<'coll, K: Pod, V, I: IterableMap> { } impl<'coll, K: Pod, V, I: IterableMap> MapIter<'coll, K, V, I> { - fn new(map: &'coll I) -> MapIter<'coll, K, V, I> { - MapIter { + fn new(map: &'coll I) -> Self { + Self { keys: MapKeys::new(map.map()), map, _v: PhantomData, @@ -761,7 +859,7 @@ impl TryFrom> for PerCpuValues { format!("not enough values ({}), nr_cpus: {}", values.len(), nr_cpus), )); } - Ok(PerCpuValues { + Ok(Self { values: values.into_boxed_slice(), }) } @@ -775,7 +873,7 @@ impl PerCpuValues { }) } - pub(crate) unsafe fn from_kernel_mem(mem: PerCpuKernelMem) -> PerCpuValues { + pub(crate) unsafe fn from_kernel_mem(mem: PerCpuKernelMem) -> Self { let mem_ptr = mem.bytes.as_ptr() as usize; let value_size = (mem::size_of::() + 7) & !7; let mut values = Vec::new(); @@ -785,13 +883,13 @@ impl PerCpuValues { offset += value_size; } - PerCpuValues { + Self { values: values.into_boxed_slice(), } } pub(crate) fn build_kernel_mem(&self) -> Result { - let mut mem = PerCpuValues::::alloc_kernel_mem()?; + let mut mem = Self::alloc_kernel_mem()?; let mem_ptr = mem.as_mut_ptr() as usize; let value_size = (mem::size_of::() + 7) & !7; for i in 0..self.values.len() { @@ -810,11 +908,127 @@ impl Deref for PerCpuValues { } } +/// Provides information about a loaded map, like name, id and size. +#[derive(Debug)] +pub struct MapInfo(bpf_map_info); + +impl MapInfo { + fn new_from_fd(fd: BorrowedFd<'_>) -> Result { + let info = bpf_map_get_info_by_fd(fd.as_fd())?; + Ok(Self(info)) + } + + /// Loads map info from a map id. + pub fn from_id(id: u32) -> Result { + bpf_map_get_fd_by_id(id) + .map_err(MapError::from) + .and_then(|fd| Self::new_from_fd(fd.as_fd())) + } + + /// The name of the map, limited to 16 bytes. + pub fn name(&self) -> &[u8] { + bytes_of_bpf_name(&self.0.name) + } + + /// The name of the map as a &str. If the name is not valid unicode, None is returned. + pub fn name_as_str(&self) -> Option<&str> { + std::str::from_utf8(self.name()).ok() + } + + /// The id for this map. Each map has a unique id. + pub fn id(&self) -> u32 { + self.0.id + } + + /// The map type as defined by the linux kernel enum + /// [`bpf_map_type`](https://elixir.bootlin.com/linux/v6.4.4/source/include/uapi/linux/bpf.h#L905). + pub fn map_type(&self) -> u32 { + self.0.type_ + } + + /// The key size for this map. + pub fn key_size(&self) -> u32 { + self.0.key_size + } + + /// The value size for this map. + pub fn value_size(&self) -> u32 { + self.0.value_size + } + + /// The maximum number of entries in this map. + pub fn max_entries(&self) -> u32 { + self.0.max_entries + } + + /// The flags for this map. + pub fn map_flags(&self) -> u32 { + self.0.map_flags + } + + /// Returns a file descriptor referencing the map. + /// + /// The returned file descriptor can be closed at any time and doing so does + /// not influence the life cycle of the map. + pub fn fd(&self) -> Result { + let Self(info) = self; + let fd = bpf_map_get_fd_by_id(info.id)?; + Ok(MapFd(fd)) + } + + /// Loads a map from a pinned path in bpffs. + pub fn from_pin>(path: P) -> Result { + use std::os::unix::ffi::OsStrExt as _; + + // TODO: avoid this unwrap by adding a new error variant. + let path_string = CString::new(path.as_ref().as_os_str().as_bytes()).unwrap(); + let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError { + call: "BPF_OBJ_GET", + io_error, + })?; + + Self::new_from_fd(fd.as_fd()) + } +} + +/// Returns an iterator over all loaded bpf maps. +/// +/// This differs from [`crate::Bpf::maps`] since it will return all maps +/// listed on the host system and not only maps for a specific [`crate::Bpf`] instance. +/// +/// # Example +/// ``` +/// # use aya::maps::loaded_maps; +/// +/// for m in loaded_maps() { +/// match m { +/// Ok(map) => println!("{:?}", map.name_as_str()), +/// Err(e) => println!("Error iterating maps: {:?}", e), +/// } +/// } +/// ``` +/// +/// # Errors +/// +/// Returns [`MapError::SyscallError`] if any of the syscalls required to either get +/// next map id, get the map fd, or the [`MapInfo`] fail. In cases where +/// iteration can't be performed, for example the caller does not have the necessary privileges, +/// a single item will be yielded containing the error that occurred. +pub fn loaded_maps() -> impl Iterator> { + iter_map_ids().map(|id| { + let id = id?; + MapInfo::from_id(id) + }) +} + #[cfg(test)] mod tests { + use std::os::fd::AsRawFd as _; + use assert_matches::assert_matches; use libc::EFAULT; + use super::*; use crate::{ bpf_map_def, generated::{bpf_cmd, bpf_map_type::BPF_MAP_TYPE_HASH}, @@ -823,8 +1037,6 @@ mod tests { sys::{override_syscall, Syscall}, }; - use super::*; - fn new_obj_map() -> obj::Map { obj::Map::Legacy(LegacyMap { def: bpf_map_def { @@ -841,6 +1053,38 @@ mod tests { }) } + #[test] + fn test_from_map_id() { + override_syscall(|call| match call { + Syscall::Bpf { + cmd: bpf_cmd::BPF_MAP_GET_FD_BY_ID, + attr, + } => { + assert_eq!( + unsafe { attr.__bindgen_anon_6.__bindgen_anon_1.map_id }, + 1234 + ); + Ok(42) + } + Syscall::Bpf { + cmd: bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, + attr, + } => { + assert_eq!(unsafe { attr.info.bpf_fd }, 42); + Ok(0) + } + _ => Err((-1, io::Error::from_raw_os_error(EFAULT))), + }); + + assert_matches!( + MapData::from_id(1234), + Ok(MapData { + obj: _, + fd, + }) => assert_eq!(fd.as_fd().as_raw_fd(), 42) + ); + } + #[test] fn test_create() { override_syscall(|call| match call { @@ -855,12 +1099,101 @@ mod tests { MapData::create(new_obj_map(), "foo", None), Ok(MapData { obj: _, - fd: 42, - pinned: false - }) + fd, + }) => assert_eq!(fd.as_fd().as_raw_fd(), 42) ); } + #[test] + // Syscall overrides are performing integer-to-pointer conversions, which + // should be done with `ptr::from_exposed_addr` in Rust nightly, but we have + // to support stable as well. + #[cfg_attr(miri, ignore)] + fn test_name() { + use crate::generated::bpf_map_info; + + const TEST_NAME: &str = "foo"; + + override_syscall(|call| match call { + Syscall::Bpf { + cmd: bpf_cmd::BPF_MAP_CREATE, + .. + } => Ok(42), + Syscall::Bpf { + cmd: bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, + attr, + } => { + assert_eq!( + unsafe { attr.info.info_len }, + mem::size_of::() as u32 + ); + let map_info = unsafe { &mut *(attr.info.info as *mut bpf_map_info) }; + map_info.name[..TEST_NAME.len()] + .copy_from_slice(unsafe { std::mem::transmute(TEST_NAME) }); + Ok(0) + } + _ => Err((-1, io::Error::from_raw_os_error(EFAULT))), + }); + + let map_data = MapData::create(new_obj_map(), TEST_NAME, None).unwrap(); + assert_eq!(TEST_NAME, map_data.info().unwrap().name_as_str().unwrap()); + } + + #[test] + // Syscall overrides are performing integer-to-pointer conversions, which + // should be done with `ptr::from_exposed_addr` in Rust nightly, but we have + // to support stable as well. + #[cfg_attr(miri, ignore)] + fn test_loaded_maps() { + use crate::generated::bpf_map_info; + + override_syscall(|call| match call { + Syscall::Bpf { + cmd: bpf_cmd::BPF_MAP_GET_NEXT_ID, + attr, + } => unsafe { + let id = attr.__bindgen_anon_6.__bindgen_anon_1.start_id; + if id < 5 { + attr.__bindgen_anon_6.next_id = id + 1; + Ok(0) + } else { + Err((-1, io::Error::from_raw_os_error(libc::ENOENT))) + } + }, + Syscall::Bpf { + cmd: bpf_cmd::BPF_MAP_GET_FD_BY_ID, + attr, + } => Ok((1000 + unsafe { attr.__bindgen_anon_6.__bindgen_anon_1.map_id }) as c_long), + Syscall::Bpf { + cmd: bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, + attr, + } => { + let map_info = unsafe { &mut *(attr.info.info as *mut bpf_map_info) }; + map_info.id = unsafe { attr.info.bpf_fd } - 1000; + map_info.key_size = 32; + map_info.value_size = 64; + map_info.map_flags = 1234; + map_info.max_entries = 99; + Ok(0) + } + _ => Err((-1, io::Error::from_raw_os_error(EFAULT))), + }); + + let loaded_maps: Vec<_> = loaded_maps().collect(); + assert_eq!(loaded_maps.len(), 5); + + for (i, map_info) in loaded_maps.into_iter().enumerate() { + let i = i + 1; + let map_info = map_info.unwrap(); + assert_eq!(map_info.id(), i as u32); + assert_eq!(map_info.key_size(), 32); + assert_eq!(map_info.value_size(), 64); + assert_eq!(map_info.map_flags(), 1234); + assert_eq!(map_info.max_entries(), 99); + assert_eq!(map_info.fd().unwrap().as_fd().as_raw_fd(), 1000 + i as i32); + } + } + #[test] fn test_create_failed() { override_syscall(|_| Err((-42, io::Error::from_raw_os_error(EFAULT)))); diff --git a/aya/src/maps/perf/async_perf_event_array.rs b/aya/src/maps/perf/async_perf_event_array.rs index 447df95d..7828759a 100644 --- a/aya/src/maps/perf/async_perf_event_array.rs +++ b/aya/src/maps/perf/async_perf_event_array.rs @@ -1,8 +1,4 @@ -use bytes::BytesMut; -use std::{ - borrow::{Borrow, BorrowMut}, - os::fd::{AsRawFd as _, RawFd}, -}; +use std::borrow::{Borrow, BorrowMut}; // See https://doc.rust-lang.org/cargo/reference/features.html#mutually-exclusive-features. // @@ -10,7 +6,7 @@ use std::{ // "async-async-std". Presently we arbitrarily choose tokio over async-std when both are requested. #[cfg(all(not(feature = "async_tokio"), feature = "async_std"))] use async_io::Async; - +use bytes::BytesMut; #[cfg(feature = "async_tokio")] use tokio::io::unix::AsyncFd; @@ -52,7 +48,6 @@ use crate::maps::{ /// # let mut bpf = aya::Bpf::load(&[])?; /// use aya::maps::perf::{AsyncPerfEventArray, PerfBufferError}; /// use aya::util::online_cpus; -/// use futures::future; /// use bytes::BytesMut; /// use tokio::task; // or async_std::task /// @@ -93,7 +88,7 @@ pub struct AsyncPerfEventArray { perf_map: PerfEventArray, } -impl + Borrow> AsyncPerfEventArray { +impl> AsyncPerfEventArray { /// Opens the perf buffer at the given index. /// /// The returned buffer will receive all the events eBPF programs send at the given index. @@ -104,22 +99,17 @@ impl + Borrow> AsyncPerfEventArray { ) -> Result, PerfBufferError> { let Self { perf_map } = self; let buf = perf_map.open(index, page_count)?; - let fd = buf.as_raw_fd(); - Ok(AsyncPerfEventArrayBuffer { - buf, - - #[cfg(feature = "async_tokio")] - async_tokio_fd: AsyncFd::new(fd)?, - - #[cfg(all(not(feature = "async_tokio"), feature = "async_std"))] - async_std_fd: Async::new(fd)?, - }) + #[cfg(feature = "async_tokio")] + let buf = AsyncFd::new(buf)?; + #[cfg(all(not(feature = "async_tokio"), feature = "async_std"))] + let buf = Async::new(buf)?; + Ok(AsyncPerfEventArrayBuffer { buf }) } } impl> AsyncPerfEventArray { - pub(crate) fn new(map: T) -> Result, MapError> { - Ok(AsyncPerfEventArray { + pub(crate) fn new(map: T) -> Result { + Ok(Self { perf_map: PerfEventArray::new(map)?, }) } @@ -132,17 +122,18 @@ impl> AsyncPerfEventArray { /// /// See the [`AsyncPerfEventArray` documentation](AsyncPerfEventArray) for an overview of how to /// use perf buffers. -pub struct AsyncPerfEventArrayBuffer { +pub struct AsyncPerfEventArrayBuffer> { + #[cfg(not(any(feature = "async_tokio", feature = "async_std")))] buf: PerfEventArrayBuffer, #[cfg(feature = "async_tokio")] - async_tokio_fd: AsyncFd, + buf: AsyncFd>, #[cfg(all(not(feature = "async_tokio"), feature = "async_std"))] - async_std_fd: Async, + buf: Async>, } -impl + Borrow> AsyncPerfEventArrayBuffer { +impl> AsyncPerfEventArrayBuffer { /// Reads events from the buffer. /// /// This method reads events into the provided slice of buffers, filling @@ -156,21 +147,20 @@ impl + Borrow> AsyncPerfEventArrayBuffer { &mut self, buffers: &mut [BytesMut], ) -> Result { - let Self { - buf, - #[cfg(feature = "async_tokio")] - async_tokio_fd, - #[cfg(all(not(feature = "async_tokio"), feature = "async_std"))] - async_std_fd, - } = self; + let Self { buf } = self; loop { #[cfg(feature = "async_tokio")] - let mut guard = async_tokio_fd.readable_mut().await?; + let mut guard = buf.readable_mut().await?; + #[cfg(feature = "async_tokio")] + let buf = guard.get_inner_mut(); #[cfg(all(not(feature = "async_tokio"), feature = "async_std"))] - if !buf.readable() { - async_std_fd.readable().await?; - } + let buf = { + if !buf.get_ref().readable() { + buf.readable().await?; + } + unsafe { buf.get_mut() } + }; let events = buf.read_events(buffers)?; const EMPTY: Events = Events { read: 0, lost: 0 }; diff --git a/aya/src/maps/perf/mod.rs b/aya/src/maps/perf/mod.rs index 80f08b61..765b052d 100644 --- a/aya/src/maps/perf/mod.rs +++ b/aya/src/maps/perf/mod.rs @@ -1,6 +1,7 @@ -//! Ring buffer types used to receive events from eBPF programs using the linux `perf` API. +//! Ring buffer types used to receive events from eBPF programs using the linux +//! `perf` API. //! -//! See the [`PerfEventArray`](crate::maps::PerfEventArray) and [`AsyncPerfEventArray`](crate::maps::perf::AsyncPerfEventArray). +//! See [`PerfEventArray`] and [`AsyncPerfEventArray`]. #[cfg(any(feature = "async_tokio", feature = "async_std"))] #[cfg_attr(docsrs, doc(cfg(any(feature = "async_tokio", feature = "async_std"))))] mod async_perf_event_array; diff --git a/aya/src/maps/perf/perf_buffer.rs b/aya/src/maps/perf/perf_buffer.rs index 2a5bfe3d..c50bbb86 100644 --- a/aya/src/maps/perf/perf_buffer.rs +++ b/aya/src/maps/perf/perf_buffer.rs @@ -7,7 +7,7 @@ use std::{ }; use bytes::BytesMut; -use libc::{c_int, munmap, MAP_FAILED, MAP_SHARED, PROT_READ, PROT_WRITE}; +use libc::{munmap, MAP_FAILED, MAP_SHARED, PROT_READ, PROT_WRITE}; use thiserror::Error; use crate::{ @@ -15,7 +15,7 @@ use crate::{ perf_event_header, perf_event_mmap_page, perf_event_type::{PERF_RECORD_LOST, PERF_RECORD_SAMPLE}, }, - sys::{perf_event_ioctl, perf_event_open_bpf, SysResult}, + sys::{mmap, perf_event_ioctl, perf_event_open_bpf, SysResult}, PERF_EVENT_IOC_DISABLE, PERF_EVENT_IOC_ENABLE, }; @@ -96,7 +96,7 @@ impl PerfBuffer { cpu_id: u32, page_size: usize, page_count: usize, - ) -> Result { + ) -> Result { if !page_count.is_power_of_two() { return Err(PerfBufferError::InvalidPageCount { page_count }); } @@ -120,7 +120,7 @@ impl PerfBuffer { }); } - let perf_buf = PerfBuffer { + let perf_buf = Self { buf: AtomicPtr::new(buf as *mut perf_event_mmap_page), fd, size, @@ -282,49 +282,32 @@ impl Drop for PerfBuffer { } } -#[cfg_attr(test, allow(unused_variables))] -unsafe fn mmap( - addr: *mut c_void, - len: usize, - prot: c_int, - flags: c_int, - fd: BorrowedFd<'_>, - offset: libc::off_t, -) -> *mut c_void { - #[cfg(not(test))] - return libc::mmap(addr, len, prot, flags, fd.as_raw_fd(), offset); - - #[cfg(test)] - use crate::sys::TEST_MMAP_RET; - - #[cfg(test)] - TEST_MMAP_RET.with(|ret| *ret.borrow()) -} - #[derive(Debug)] #[repr(C)] struct Sample { header: perf_event_header, - pub size: u32, + size: u32, } #[repr(C)] #[derive(Debug)] struct LostSamples { header: perf_event_header, - pub id: u64, - pub count: u64, + id: u64, + count: u64, } #[cfg(test)] mod tests { + use std::{fmt::Debug, mem}; + + use assert_matches::assert_matches; + use super::*; use crate::{ generated::perf_event_mmap_page, sys::{override_syscall, Syscall, TEST_MMAP_RET}, }; - use assert_matches::assert_matches; - use std::{fmt::Debug, mem}; const PAGE_SIZE: usize = 4096; union MMappedBuf { diff --git a/aya/src/maps/perf/perf_event_array.rs b/aya/src/maps/perf/perf_event_array.rs index 7d647164..c1df535a 100644 --- a/aya/src/maps/perf/perf_event_array.rs +++ b/aya/src/maps/perf/perf_event_array.rs @@ -4,7 +4,7 @@ use std::{ borrow::{Borrow, BorrowMut}, ops::Deref, - os::fd::{AsRawFd, RawFd}, + os::fd::{AsFd, AsRawFd, BorrowedFd, RawFd}, sync::Arc, }; @@ -31,7 +31,7 @@ pub struct PerfEventArrayBuffer { buf: PerfBuffer, } -impl + Borrow> PerfEventArrayBuffer { +impl> PerfEventArrayBuffer { /// Returns true if the buffer contains events that haven't been read. pub fn readable(&self) -> bool { self.buf.readable() @@ -55,7 +55,13 @@ impl + Borrow> PerfEventArrayBuffer { } } -impl + Borrow> AsRawFd for PerfEventArrayBuffer { +impl> AsFd for PerfEventArrayBuffer { + fn as_fd(&self) -> BorrowedFd<'_> { + self.buf.as_fd() + } +} + +impl> AsRawFd for PerfEventArrayBuffer { fn as_raw_fd(&self) -> RawFd { self.buf.as_raw_fd() } @@ -161,15 +167,15 @@ pub struct PerfEventArray { } impl> PerfEventArray { - pub(crate) fn new(map: T) -> Result, MapError> { - Ok(PerfEventArray { + pub(crate) fn new(map: T) -> Result { + Ok(Self { map: Arc::new(map), page_size: page_size(), }) } } -impl + Borrow> PerfEventArray { +impl> PerfEventArray { /// Opens the perf buffer at the given index. /// /// The returned buffer will receive all the events eBPF programs send at the given index. @@ -180,9 +186,8 @@ impl + Borrow> PerfEventArray { ) -> Result, PerfBufferError> { // FIXME: keep track of open buffers - // 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; + let map_fd = map_data.fd().as_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 78b81ec2..b9177b24 100644 --- a/aya/src/maps/queue.rs +++ b/aya/src/maps/queue.rs @@ -2,6 +2,7 @@ use std::{ borrow::{Borrow, BorrowMut}, marker::PhantomData, + os::fd::AsFd as _, }; use crate::{ @@ -29,16 +30,16 @@ use crate::{ /// ``` #[doc(alias = "BPF_MAP_TYPE_QUEUE")] pub struct Queue { - inner: T, + pub(crate) inner: T, _v: PhantomData, } impl, V: Pod> Queue { - pub(crate) fn new(map: T) -> Result, MapError> { + pub(crate) fn new(map: T) -> Result { let data = map.borrow(); check_kv_size::<(), V>(data)?; - Ok(Queue { + Ok(Self { inner: map, _v: PhantomData, }) @@ -60,7 +61,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; + let fd = self.inner.borrow().fd().as_fd(); let value = bpf_map_lookup_and_delete_elem::(fd, None, flags).map_err( |(_, io_error)| SyscallError { @@ -77,7 +78,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; + let fd = self.inner.borrow().fd().as_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/ring_buf.rs b/aya/src/maps/ring_buf.rs new file mode 100644 index 00000000..16f4c175 --- /dev/null +++ b/aya/src/maps/ring_buf.rs @@ -0,0 +1,458 @@ +//! A [ring buffer map][ringbuf] that may be used to receive events from eBPF programs. +//! As of Linux 5.8, this is the preferred way to transfer per-event data from eBPF +//! programs to userspace. +//! +//! [ringbuf]: https://www.kernel.org/doc/html/latest/bpf/ringbuf.html + +use std::{ + borrow::Borrow, + ffi::{c_int, c_void}, + fmt::{self, Debug, Formatter}, + io, mem, + ops::Deref, + os::fd::{AsFd as _, AsRawFd, BorrowedFd, RawFd}, + ptr, + ptr::NonNull, + slice, + sync::atomic::{AtomicU32, AtomicUsize, Ordering}, +}; + +use libc::{munmap, off_t, MAP_FAILED, MAP_SHARED, PROT_READ, PROT_WRITE}; + +use crate::{ + generated::{BPF_RINGBUF_BUSY_BIT, BPF_RINGBUF_DISCARD_BIT, BPF_RINGBUF_HDR_SZ}, + maps::{MapData, MapError}, + sys::{mmap, SyscallError}, + util::page_size, +}; + +/// A map that can be used to receive events from eBPF programs. +/// +/// This is similar to [`crate::maps::PerfEventArray`], but different in a few ways: +/// * It's shared across all CPUs, which allows a strong ordering between events. +/// * Data notifications are delivered precisely instead of being sampled for every N events; the +/// eBPF program can also control notification delivery if sampling is desired for performance +/// reasons. By default, a notification will be sent if the consumer is caught up at the time of +/// committing. The eBPF program can use the `BPF_RB_NO_WAKEUP` or `BPF_RB_FORCE_WAKEUP` flags to +/// control this behavior. +/// * On the eBPF side, it supports the reverse-commit pattern where the event can be directly +/// written into the ring without copying from a temporary location. +/// * Dropped sample notifications go to the eBPF program as the return value of `reserve`/`output`, +/// and not the userspace reader. This might require extra code to handle, but allows for more +/// flexible schemes to handle dropped samples. +/// +/// To receive events you need to: +/// * Construct [`RingBuf`] using [`RingBuf::try_from`]. +/// * Call [`RingBuf::next`] to poll events from the [`RingBuf`]. +/// +/// To receive async notifications of data availability, you may construct an +/// [`tokio::io::unix::AsyncFd`] from the [`RingBuf`]'s file descriptor and poll it for readiness. +/// +/// # Minimum kernel version +/// +/// The minimum kernel version required to use this feature is 5.8. +/// +/// # Examples +/// +/// ```no_run +/// # struct PollFd(T); +/// # fn poll_fd(t: T) -> PollFd { PollFd(t) } +/// # impl PollFd { +/// # fn readable(&mut self) -> Guard<'_, T> { Guard(self) } +/// # } +/// # struct Guard<'a, T>(&'a mut PollFd); +/// # impl Guard<'_, T> { +/// # fn inner_mut(&mut self) -> &mut T { +/// # let Guard(PollFd(t)) = self; +/// # t +/// # } +/// # fn clear_ready(&mut self) {} +/// # } +/// # let bpf = aya::Bpf::load(&[])?; +/// use aya::maps::RingBuf; +/// use std::convert::TryFrom; +/// +/// let ring_buf = RingBuf::try_from(bpf.map_mut("ARRAY")?)?; +/// let poll = poll_fd(ring_buf); +/// loop { +/// let mut guard = poll.readable()?; +/// let ring_buf = guard.inner_mut() +/// while let Some(item) = ring_buf.next() { +/// println!("Received: {:?}", item); +/// } +/// guard.clear_ready(); +/// } +/// # Ok::<(), aya::BpfError>(()) +/// ``` +/// +/// # Polling +/// +/// In the example above the implementations of poll(), poll.readable(), guard.inner_mut(), and +/// guard.clear_ready() are not given. RingBuf implements the AsRawFd trait, so you can implement +/// polling using any crate that can poll file descriptors, like epoll, mio etc. The above example +/// API is motivated by that of [`tokio::io::unix::AsyncFd`]. +#[doc(alias = "BPF_MAP_TYPE_RINGBUF")] +pub struct RingBuf { + map: T, + consumer: ConsumerPos, + producer: ProducerData, +} + +impl> RingBuf { + pub(crate) fn new(map: T) -> Result { + let data: &MapData = map.borrow(); + let page_size = page_size(); + let map_fd = data.fd().as_fd(); + let byte_size = data.obj.max_entries(); + let consumer_metadata = ConsumerMetadata::new(map_fd, 0, page_size)?; + let consumer = ConsumerPos::new(consumer_metadata); + let producer = ProducerData::new(map_fd, page_size, page_size, byte_size)?; + Ok(Self { + map, + consumer, + producer, + }) + } +} + +impl RingBuf { + /// Try to take a new entry from the ringbuf. + /// + /// Returns `Some(item)` if the ringbuf is not empty. Returns `None` if the ringbuf is empty, in + /// which case the caller may register for availability notifications through `epoll` or other + /// APIs. Only one RingBufItem may be outstanding at a time. + // + // This is not an implementation of `Iterator` because we need to be able to refer to the + // lifetime of the iterator in the returned `RingBufItem`. If the Iterator::Item leveraged GATs, + // one could imagine an implementation of `Iterator` that would work. GATs are stabilized in + // Rust 1.65, but there's not yet a trait that the community seems to have standardized around. + #[allow(clippy::should_implement_trait)] + pub fn next(&mut self) -> Option> { + let Self { + consumer, producer, .. + } = self; + producer.next(consumer) + } +} + +/// Access to the RawFd can be used to construct an AsyncFd for use with epoll. +impl> AsRawFd for RingBuf { + fn as_raw_fd(&self) -> RawFd { + let Self { + map, + consumer: _, + producer: _, + } = self; + map.borrow().fd().as_fd().as_raw_fd() + } +} + +/// The current outstanding item read from the ringbuf. +pub struct RingBufItem<'a> { + data: &'a [u8], + consumer: &'a mut ConsumerPos, +} + +impl Deref for RingBufItem<'_> { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + let Self { data, .. } = self; + data + } +} + +impl Drop for RingBufItem<'_> { + fn drop(&mut self) { + let Self { consumer, data } = self; + consumer.consume(data.len()) + } +} + +impl Debug for RingBufItem<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let Self { + data, + consumer: + ConsumerPos { + pos, + metadata: ConsumerMetadata { mmap: _ }, + }, + } = self; + // In general Relaxed here is sufficient, for debugging, it certainly is. + f.debug_struct("RingBufItem") + .field("pos", pos) + .field("len", &data.len()) + .finish() + } +} + +struct ConsumerMetadata { + mmap: MMap, +} + +impl ConsumerMetadata { + fn new(fd: BorrowedFd<'_>, offset: usize, page_size: usize) -> Result { + let mmap = MMap::new( + fd, + page_size, + PROT_READ | PROT_WRITE, + MAP_SHARED, + offset.try_into().unwrap(), + )?; + Ok(Self { mmap }) + } +} + +impl AsRef for ConsumerMetadata { + fn as_ref(&self) -> &AtomicUsize { + let Self { + mmap: MMap { ptr, .. }, + } = self; + unsafe { ptr.cast::().as_ref() } + } +} + +struct ConsumerPos { + pos: usize, + metadata: ConsumerMetadata, +} + +impl ConsumerPos { + fn new(metadata: ConsumerMetadata) -> Self { + // Load the initial value of the consumer position. SeqCst is used to be safe given we don't + // have any claims about memory synchronization performed by some previous writer. + let pos = metadata.as_ref().load(Ordering::SeqCst); + Self { pos, metadata } + } + + fn consume(&mut self, len: usize) { + let Self { pos, metadata } = self; + + // TODO: Use primitive method when https://github.com/rust-lang/rust/issues/88581 is stabilized. + fn next_multiple_of(n: usize, multiple: usize) -> usize { + match n % multiple { + 0 => n, + rem => n + (multiple - rem), + } + } + *pos += next_multiple_of(usize::try_from(BPF_RINGBUF_HDR_SZ).unwrap() + len, 8); + + // Write operation needs to be properly ordered with respect to the producer committing new + // data to the ringbuf. The producer uses xchg (SeqCst) to commit new data [1]. The producer + // reads the consumer offset after clearing the busy bit on a new entry [2]. By using SeqCst + // here we ensure that either a subsequent read by the consumer to consume messages will see + // an available message, or the producer in the kernel will see the updated consumer offset + // that is caught up. + // + // [1]: https://github.com/torvalds/linux/blob/2772d7df/kernel/bpf/ringbuf.c#L487-L488 + // [2]: https://github.com/torvalds/linux/blob/2772d7df/kernel/bpf/ringbuf.c#L494 + metadata.as_ref().store(*pos, Ordering::SeqCst); + } +} + +struct ProducerData { + mmap: MMap, + + // Offset in the mmap where the data starts. + data_offset: usize, + + // A cache of the value of the producer position. It is used to avoid re-reading the producer + // position when we know there is more data to consume. + pos_cache: usize, + + // A bitmask which truncates u32 values to the domain of valid offsets in the ringbuf. + mask: u32, +} + +impl ProducerData { + fn new( + fd: BorrowedFd<'_>, + offset: usize, + page_size: usize, + byte_size: u32, + ) -> Result { + // The producer pages have one page of metadata and then the data pages, all mapped + // read-only. Note that the length of the mapping includes the data pages twice as the + // kernel will map them two time consecutively to avoid special handling of entries that + // cross over the end of the ring buffer. + // + // The kernel diagram below shows the layout of the ring buffer. It references "meta pages", + // but we only map exactly one producer meta page read-only. The consumer meta page is mapped + // read-write elsewhere, and is taken into consideration via the offset parameter. + // + // From kernel/bpf/ringbuf.c[0]: + // + // Each data page is mapped twice to allow "virtual" + // continuous read of samples wrapping around the end of ring + // buffer area: + // ------------------------------------------------------ + // | meta pages | real data pages | same data pages | + // ------------------------------------------------------ + // | | 1 2 3 4 5 6 7 8 9 | 1 2 3 4 5 6 7 8 9 | + // ------------------------------------------------------ + // | | TA DA | TA DA | + // ------------------------------------------------------ + // ^^^^^^^ + // | + // Here, no need to worry about special handling of wrapped-around + // data due to double-mapped data pages. This works both in kernel and + // when mmap()'ed in user-space, simplifying both kernel and + // user-space implementations significantly. + // + // [0]: https://github.com/torvalds/linux/blob/3f01e9fe/kernel/bpf/ringbuf.c#L108-L124 + let len = page_size + 2 * usize::try_from(byte_size).unwrap(); + let mmap = MMap::new(fd, len, PROT_READ, MAP_SHARED, offset.try_into().unwrap())?; + + // byte_size is required to be a power of two multiple of page_size (which implicitly is a + // power of 2), so subtracting one will create a bitmask for values less than byte_size. + debug_assert!(byte_size.is_power_of_two()); + let mask = byte_size - 1; + Ok(Self { + mmap, + data_offset: page_size, + pos_cache: 0, + mask, + }) + } + + fn next<'a>(&'a mut self, consumer: &'a mut ConsumerPos) -> Option> { + let Self { + ref mmap, + data_offset, + pos_cache, + mask, + } = self; + let pos = unsafe { mmap.ptr.cast().as_ref() }; + let mmap_data = mmap.as_ref(); + let data_pages = mmap_data.get(*data_offset..).unwrap_or_else(|| { + panic!( + "offset {} out of bounds, data len {}", + data_offset, + mmap_data.len() + ) + }); + while data_available(pos, pos_cache, consumer) { + match read_item(data_pages, *mask, consumer) { + Item::Busy => return None, + Item::Discard { len } => consumer.consume(len), + Item::Data(data) => return Some(RingBufItem { data, consumer }), + } + } + return None; + + enum Item<'a> { + Busy, + Discard { len: usize }, + Data(&'a [u8]), + } + + fn data_available( + producer: &AtomicUsize, + cache: &mut usize, + consumer: &ConsumerPos, + ) -> bool { + let ConsumerPos { pos: consumer, .. } = consumer; + if consumer == cache { + // This value is written using Release by the kernel [1], and should be read with + // Acquire to ensure that the prior writes to the entry header are visible. + // + // [1]: https://github.com/torvalds/linux/blob/eb26cbb1/kernel/bpf/ringbuf.c#L447-L448 + *cache = producer.load(Ordering::Acquire); + } + + // Note that we don't compare the order of the values because the producer position may + // overflow u32 and wrap around to 0. Instead we just compare equality and assume that + // the consumer position is always logically less than the producer position. + // + // Note also that the kernel, at the time of writing [1], doesn't seem to handle this + // overflow correctly at all, and it's not clear that one can produce events after the + // producer position has wrapped around. + // + // [1]: https://github.com/torvalds/linux/blob/4b810bf0/kernel/bpf/ringbuf.c#L434-L440 + consumer != cache + } + + fn read_item<'data>(data: &'data [u8], mask: u32, pos: &ConsumerPos) -> Item<'data> { + let ConsumerPos { pos, .. } = pos; + let offset = pos & usize::try_from(mask).unwrap(); + let must_get_data = |offset, len| { + data.get(offset..offset + len).unwrap_or_else(|| { + panic!("{:?} not in {:?}", offset..offset + len, 0..data.len()) + }) + }; + let header_ptr = + must_get_data(offset, mem::size_of::()).as_ptr() as *const AtomicU32; + // Pair the kernel's SeqCst write (implies Release) [1] with an Acquire load. This + // ensures data written by the producer will be visible. + // + // [1]: https://github.com/torvalds/linux/blob/eb26cbb1/kernel/bpf/ringbuf.c#L488 + let header = unsafe { &*header_ptr }.load(Ordering::Acquire); + if header & BPF_RINGBUF_BUSY_BIT != 0 { + Item::Busy + } else { + let len = usize::try_from(header & mask).unwrap(); + if header & BPF_RINGBUF_DISCARD_BIT != 0 { + Item::Discard { len } + } else { + let data_offset = offset + usize::try_from(BPF_RINGBUF_HDR_SZ).unwrap(); + let data = must_get_data(data_offset, len); + Item::Data(data) + } + } + } + } +} + +// MMap corresponds to a memory-mapped region. +// +// The data is unmapped in Drop. +struct MMap { + ptr: NonNull, + len: usize, +} + +impl MMap { + fn new( + fd: BorrowedFd<'_>, + len: usize, + prot: c_int, + flags: c_int, + offset: off_t, + ) -> Result { + match unsafe { mmap(ptr::null_mut(), len, prot, flags, fd, offset) } { + MAP_FAILED => Err(MapError::SyscallError(SyscallError { + call: "mmap", + io_error: io::Error::last_os_error(), + })), + ptr => Ok(Self { + ptr: ptr::NonNull::new(ptr).ok_or( + // This should never happen, but to be paranoid, and so we never need to talk + // about a null pointer, we check it anyway. + MapError::SyscallError(SyscallError { + call: "mmap", + io_error: io::Error::new( + io::ErrorKind::Other, + "mmap returned null pointer", + ), + }), + )?, + len, + }), + } + } +} + +impl AsRef<[u8]> for MMap { + fn as_ref(&self) -> &[u8] { + let Self { ptr, len } = self; + unsafe { slice::from_raw_parts(ptr.as_ptr().cast(), *len) } + } +} + +impl Drop for MMap { + fn drop(&mut self) { + let Self { ptr, len } = *self; + unsafe { munmap(ptr.as_ptr(), len) }; + } +} diff --git a/aya/src/maps/sock/mod.rs b/aya/src/maps/sock/mod.rs index 1b9f00e9..067e9d03 100644 --- a/aya/src/maps/sock/mod.rs +++ b/aya/src/maps/sock/mod.rs @@ -2,17 +2,32 @@ mod sock_hash; mod sock_map; +use std::{ + io, + os::fd::{AsFd, BorrowedFd}, +}; + pub use sock_hash::SockHash; pub use sock_map::SockMap; -use std::os::fd::{AsRawFd, RawFd}; - /// A socket map file descriptor. -#[derive(Copy, Clone)] -pub struct SockMapFd(RawFd); +#[repr(transparent)] +pub struct SockMapFd(super::MapFd); + +impl SockMapFd { + /// Creates a new instance that shares the same underlying file description as [`self`]. + pub fn try_clone(&self) -> io::Result { + let Self(inner) = self; + let super::MapFd(inner) = inner; + let inner = inner.try_clone()?; + let inner = super::MapFd(inner); + Ok(Self(inner)) + } +} -impl AsRawFd for SockMapFd { - fn as_raw_fd(&self) -> RawFd { - self.0 +impl AsFd for SockMapFd { + fn as_fd(&self) -> BorrowedFd<'_> { + let Self(fd) = self; + fd.as_fd() } } diff --git a/aya/src/maps/sock/sock_hash.rs b/aya/src/maps/sock/sock_hash.rs index 1904ec1e..e3074be8 100644 --- a/aya/src/maps/sock/sock_hash.rs +++ b/aya/src/maps/sock/sock_hash.rs @@ -1,12 +1,13 @@ use std::{ borrow::{Borrow, BorrowMut}, marker::PhantomData, - os::fd::{AsRawFd, RawFd}, + os::fd::{AsFd as _, AsRawFd, RawFd}, }; use crate::{ maps::{ - check_kv_size, hash_map, sock::SockMapFd, IterableMap, MapData, MapError, MapIter, MapKeys, + check_kv_size, hash_map, sock::SockMapFd, IterableMap, MapData, MapError, MapFd, MapIter, + MapKeys, }, sys::{bpf_map_lookup_elem, SyscallError}, Pod, @@ -47,11 +48,11 @@ use crate::{ /// use aya::programs::SkMsg; /// /// let mut intercept_egress = SockHash::<_, u32>::try_from(bpf.map("INTERCEPT_EGRESS").unwrap())?; -/// let map_fd = intercept_egress.fd()?; +/// let map_fd = intercept_egress.fd().try_clone()?; /// /// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?; /// prog.load()?; -/// prog.attach(map_fd)?; +/// prog.attach(&map_fd)?; /// /// let mut client = TcpStream::connect("127.0.0.1:1234")?; /// let mut intercept_egress = SockHash::try_from(bpf.map_mut("INTERCEPT_EGRESS").unwrap())?; @@ -64,16 +65,16 @@ use crate::{ /// ``` #[doc(alias = "BPF_MAP_TYPE_SOCKHASH")] pub struct SockHash { - inner: T, + pub(crate) inner: T, _k: PhantomData, } impl, K: Pod> SockHash { - pub(crate) fn new(map: T) -> Result, MapError> { + pub(crate) fn new(map: T) -> Result { let data = map.borrow(); check_kv_size::(data)?; - Ok(SockHash { + Ok(Self { inner: map, _k: PhantomData, }) @@ -81,7 +82,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; + let fd = self.inner.borrow().fd().as_fd(); let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_lookup_elem", io_error, @@ -105,8 +106,11 @@ 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)) + pub fn fd(&self) -> &SockMapFd { + let fd: &MapFd = self.inner.borrow().fd(); + // TODO(https://github.com/rust-lang/rfcs/issues/3066): avoid this unsafe. + // SAFETY: `SockMapFd` is #[repr(transparent)] over `MapFd`. + unsafe { std::mem::transmute(fd) } } } @@ -138,6 +142,6 @@ impl, K: Pod> IterableMap for SockHash { } fn get(&self, key: &K) -> Result { - SockHash::get(self, key, 0) + Self::get(self, key, 0) } } diff --git a/aya/src/maps/sock/sock_map.rs b/aya/src/maps/sock/sock_map.rs index 52574f23..42246c8b 100644 --- a/aya/src/maps/sock/sock_map.rs +++ b/aya/src/maps/sock/sock_map.rs @@ -2,11 +2,11 @@ use std::{ borrow::{Borrow, BorrowMut}, - os::fd::{AsRawFd, RawFd}, + os::fd::{AsFd as _, AsRawFd, RawFd}, }; use crate::{ - maps::{check_bounds, check_kv_size, sock::SockMapFd, MapData, MapError, MapKeys}, + maps::{check_bounds, check_kv_size, sock::SockMapFd, MapData, MapError, MapFd, MapKeys}, sys::{bpf_map_delete_elem, bpf_map_update_elem, SyscallError}, }; @@ -26,18 +26,29 @@ use crate::{ /// # Examples /// /// ```no_run +/// # #[derive(Debug, thiserror::Error)] +/// # enum Error { +/// # #[error(transparent)] +/// # IO(#[from] std::io::Error), +/// # #[error(transparent)] +/// # Map(#[from] aya::maps::MapError), +/// # #[error(transparent)] +/// # Program(#[from] aya::programs::ProgramError), +/// # #[error(transparent)] +/// # Bpf(#[from] aya::BpfError) +/// # } /// # let mut bpf = aya::Bpf::load(&[])?; /// use aya::maps::SockMap; /// use aya::programs::SkSkb; /// /// let intercept_ingress = SockMap::try_from(bpf.map("INTERCEPT_INGRESS").unwrap())?; -/// let map_fd = intercept_ingress.fd()?; +/// let map_fd = intercept_ingress.fd().try_clone()?; /// /// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?; /// prog.load()?; -/// prog.attach(map_fd)?; +/// prog.attach(&map_fd)?; /// -/// # Ok::<(), aya::BpfError>(()) +/// # Ok::<(), Error>(()) /// ``` #[doc(alias = "BPF_MAP_TYPE_SOCKMAP")] pub struct SockMap { @@ -45,11 +56,11 @@ pub struct SockMap { } impl> SockMap { - pub(crate) fn new(map: T) -> Result, MapError> { + pub(crate) fn new(map: T) -> Result { let data = map.borrow(); check_kv_size::(data)?; - Ok(SockMap { inner: map }) + Ok(Self { inner: map }) } /// An iterator over the indices of the array that point to a program. The iterator item type @@ -62,8 +73,11 @@ 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)) + pub fn fd(&self) -> &SockMapFd { + let fd: &MapFd = self.inner.borrow().fd(); + // TODO(https://github.com/rust-lang/rfcs/issues/3066): avoid this unsafe. + // SAFETY: `SockMapFd` is #[repr(transparent)] over `MapFd`. + unsafe { std::mem::transmute(&fd) } } } @@ -71,7 +85,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; + let fd = data.fd().as_fd(); check_bounds(data, index)?; bpf_map_update_elem(fd, Some(&index), &socket.as_raw_fd(), flags).map_err( |(_, io_error)| SyscallError { @@ -85,7 +99,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; + let fd = data.fd().as_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 0cc9b1d8..a85fe14d 100644 --- a/aya/src/maps/stack.rs +++ b/aya/src/maps/stack.rs @@ -2,6 +2,7 @@ use std::{ borrow::{Borrow, BorrowMut}, marker::PhantomData, + os::fd::AsFd as _, }; use crate::{ @@ -29,16 +30,16 @@ use crate::{ /// ``` #[doc(alias = "BPF_MAP_TYPE_STACK")] pub struct Stack { - inner: T, + pub(crate) inner: T, _v: PhantomData, } impl, V: Pod> Stack { - pub(crate) fn new(map: T) -> Result, MapError> { + pub(crate) fn new(map: T) -> Result { let data = map.borrow(); check_kv_size::<(), V>(data)?; - Ok(Stack { + Ok(Self { inner: map, _v: PhantomData, }) @@ -60,7 +61,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; + let fd = self.inner.borrow().fd().as_fd(); let value = bpf_map_lookup_and_delete_elem::(fd, None, flags).map_err( |(_, io_error)| SyscallError { @@ -77,7 +78,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; + let fd = self.inner.borrow().fd().as_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 8f84a09e..389b28f7 100644 --- a/aya/src/maps/stack_trace.rs +++ b/aya/src/maps/stack_trace.rs @@ -1,7 +1,7 @@ //! A hash map of kernel or user space stack traces. //! //! See [`StackTraceMap`] for documentation and examples. -use std::{borrow::Borrow, fs, io, mem, path::Path, str::FromStr}; +use std::{borrow::Borrow, fs, io, mem, os::fd::AsFd as _, path::Path, str::FromStr}; use crate::{ maps::{IterableMap, MapData, MapError, MapIter, MapKeys}, @@ -67,12 +67,12 @@ use crate::{ #[derive(Debug)] #[doc(alias = "BPF_MAP_TYPE_STACK_TRACE")] pub struct StackTraceMap { - inner: T, + pub(crate) inner: T, max_stack_depth: usize, } impl> StackTraceMap { - pub(crate) fn new(map: T) -> Result, MapError> { + pub(crate) fn new(map: T) -> Result { let data = map.borrow(); let expected = mem::size_of::(); let size = data.obj.key_size() as usize; @@ -90,7 +90,7 @@ impl> StackTraceMap { return Err(MapError::InvalidValueSize { size, expected }); } - Ok(StackTraceMap { + Ok(Self { inner: map, max_stack_depth, }) @@ -103,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; + let fd = self.inner.borrow().fd().as_fd(); let mut frames = vec![0; self.max_stack_depth]; bpf_map_lookup_elem_ptr(fd, Some(stack_id), frames.as_mut_ptr(), flags) diff --git a/aya/src/maps/xdp/cpu_map.rs b/aya/src/maps/xdp/cpu_map.rs new file mode 100644 index 00000000..85f9e679 --- /dev/null +++ b/aya/src/maps/xdp/cpu_map.rs @@ -0,0 +1,194 @@ +//! An array of available CPUs. + +use std::{ + borrow::{Borrow, BorrowMut}, + num::NonZeroU32, + os::fd::{AsFd, AsRawFd}, +}; + +use aya_obj::generated::bpf_cpumap_val; + +use super::XdpMapError; +use crate::{ + maps::{check_bounds, check_kv_size, IterableMap, MapData, MapError}, + programs::ProgramFd, + sys::{bpf_map_lookup_elem, bpf_map_update_elem, SyscallError}, + Pod, FEATURES, +}; + +/// An array of available CPUs. +/// +/// XDP programs can use this map to redirect packets to a target +/// CPU for processing. +/// +/// # Minimum kernel version +/// +/// The minimum kernel version required to use this feature is 4.15. +/// +/// # Examples +/// ```no_run +/// # let elf_bytes = &[]; +/// use aya::maps::xdp::CpuMap; +/// +/// let ncpus = aya::util::nr_cpus().unwrap() as u32; +/// let mut bpf = aya::BpfLoader::new() +/// .set_max_entries("CPUS", ncpus) +/// .load(elf_bytes) +/// .unwrap(); +/// let mut cpumap = CpuMap::try_from(bpf.map_mut("CPUS").unwrap())?; +/// let flags = 0; +/// let queue_size = 2048; +/// for i in 0..ncpus { +/// cpumap.set(i, queue_size, None, flags); +/// } +/// +/// # Ok::<(), aya::BpfError>(()) +/// ``` +/// +/// # See also +/// +/// Kernel documentation: +#[doc(alias = "BPF_MAP_TYPE_CPUMAP")] +pub struct CpuMap { + pub(crate) inner: T, +} + +impl> CpuMap { + pub(crate) fn new(map: T) -> Result { + let data = map.borrow(); + + if FEATURES.cpumap_prog_id() { + check_kv_size::(data)?; + } else { + check_kv_size::(data)?; + } + + Ok(Self { inner: map }) + } + + /// Returns the number of elements in the array. + /// + /// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side. + pub fn len(&self) -> u32 { + self.inner.borrow().obj.max_entries() + } + + /// Returns the queue size and optional program for a given CPU index. + /// + /// # Errors + /// + /// Returns [`MapError::OutOfBounds`] if `cpu_index` is out of bounds, + /// [`MapError::SyscallError`] if `bpf_map_lookup_elem` fails. + pub fn get(&self, cpu_index: u32, flags: u64) -> Result { + let data = self.inner.borrow(); + check_bounds(data, cpu_index)?; + let fd = data.fd().as_fd(); + + let value = if FEATURES.cpumap_prog_id() { + bpf_map_lookup_elem::<_, bpf_cpumap_val>(fd, &cpu_index, flags).map(|value| { + value.map(|value| CpuMapValue { + queue_size: value.qsize, + // SAFETY: map writes use fd, map reads use id. + // https://github.com/torvalds/linux/blob/2dde18cd1d8fac735875f2e4987f11817cc0bc2c/include/uapi/linux/bpf.h#L6241 + prog_id: NonZeroU32::new(unsafe { value.bpf_prog.id }), + }) + }) + } else { + bpf_map_lookup_elem::<_, u32>(fd, &cpu_index, flags).map(|value| { + value.map(|qsize| CpuMapValue { + queue_size: qsize, + prog_id: None, + }) + }) + }; + value + .map_err(|(_, io_error)| SyscallError { + call: "bpf_map_lookup_elem", + io_error, + })? + .ok_or(MapError::KeyNotFound) + } + + /// An iterator over the elements of the map. + pub fn iter(&self) -> impl Iterator> + '_ { + (0..self.len()).map(move |i| self.get(i, 0)) + } +} + +impl> CpuMap { + /// Sets the queue size at the given CPU index, and optionally a chained program. + /// + /// When sending the packet to the CPU at the given index, the kernel will queue up to + /// `queue_size` packets before dropping them. + /// + /// Starting from Linux kernel 5.9, another XDP program can be passed in that will be run on the + /// target CPU, instead of the CPU that receives the packets. This allows to perform minimal + /// computations on CPUs that directly handle packets from a NIC's RX queues, and perform + /// possibly heavier ones in other, less busy CPUs. + /// + /// The chained program must be loaded with the `BPF_XDP_CPUMAP` attach type. When using + /// `aya-ebpf`, that means XDP programs that specify the `map = "cpumap"` argument. See the + /// kernel-space `aya_ebpf::xdp` for more information. + /// + /// # Errors + /// + /// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`] + /// if `bpf_map_update_elem` fails, [`XdpMapError::ChainedProgramNotSupported`] if the kernel + /// does not support chained programs and one is provided. + pub fn set( + &mut self, + cpu_index: u32, + queue_size: u32, + program: Option<&ProgramFd>, + flags: u64, + ) -> Result<(), XdpMapError> { + let data = self.inner.borrow_mut(); + check_bounds(data, cpu_index)?; + let fd = data.fd().as_fd(); + + let res = if FEATURES.cpumap_prog_id() { + let mut value = unsafe { std::mem::zeroed::() }; + value.qsize = queue_size; + // Default is valid as the kernel will only consider fd > 0: + // https://github.com/torvalds/linux/blob/2dde18cd1d8fac735875f2e4987f11817cc0bc2c/kernel/bpf/cpumap.c#L466 + value.bpf_prog.fd = program + .map(|prog| prog.as_fd().as_raw_fd()) + .unwrap_or_default(); + bpf_map_update_elem(fd, Some(&cpu_index), &value, flags) + } else { + if program.is_some() { + return Err(XdpMapError::ChainedProgramNotSupported); + } + bpf_map_update_elem(fd, Some(&cpu_index), &queue_size, flags) + }; + + res.map_err(|(_, io_error)| { + MapError::from(SyscallError { + call: "bpf_map_update_elem", + io_error, + }) + })?; + Ok(()) + } +} + +impl> IterableMap for CpuMap { + fn map(&self) -> &MapData { + self.inner.borrow() + } + + fn get(&self, key: &u32) -> Result { + self.get(*key, 0) + } +} + +unsafe impl Pod for bpf_cpumap_val {} + +#[derive(Clone, Copy, Debug)] +/// The value of a CPU map. +pub struct CpuMapValue { + /// Size of the for the CPU. + pub queue_size: u32, + /// Chained XDP program ID. + pub prog_id: Option, +} diff --git a/aya/src/maps/xdp/dev_map.rs b/aya/src/maps/xdp/dev_map.rs new file mode 100644 index 00000000..31e9b3ac --- /dev/null +++ b/aya/src/maps/xdp/dev_map.rs @@ -0,0 +1,186 @@ +//! An array of network devices. + +use std::{ + borrow::{Borrow, BorrowMut}, + num::NonZeroU32, + os::fd::{AsFd, AsRawFd}, +}; + +use aya_obj::generated::bpf_devmap_val; + +use super::XdpMapError; +use crate::{ + maps::{check_bounds, check_kv_size, IterableMap, MapData, MapError}, + programs::ProgramFd, + sys::{bpf_map_lookup_elem, bpf_map_update_elem, SyscallError}, + Pod, FEATURES, +}; + +/// An array of network devices. +/// +/// XDP programs can use this map to redirect to other network +/// devices. +/// +/// # Minimum kernel version +/// +/// The minimum kernel version required to use this feature is 4.14. +/// +/// # Examples +/// ```no_run +/// # let mut bpf = aya::Bpf::load(&[])?; +/// use aya::maps::xdp::DevMap; +/// +/// let mut devmap = DevMap::try_from(bpf.map_mut("IFACES").unwrap())?; +/// // Lookups at index 2 will redirect packets to interface with index 3 (e.g. eth1) +/// devmap.set(2, 3, None, 0); +/// +/// # Ok::<(), aya::BpfError>(()) +/// ``` +/// +/// # See also +/// +/// Kernel documentation: +#[doc(alias = "BPF_MAP_TYPE_DEVMAP")] +pub struct DevMap { + pub(crate) inner: T, +} + +impl> DevMap { + pub(crate) fn new(map: T) -> Result { + let data = map.borrow(); + + if FEATURES.devmap_prog_id() { + check_kv_size::(data)?; + } else { + check_kv_size::(data)?; + } + + Ok(Self { inner: map }) + } + + /// Returns the number of elements in the array. + /// + /// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side. + pub fn len(&self) -> u32 { + self.inner.borrow().obj.max_entries() + } + + /// Returns the target interface index and optional program at a given index. + /// + /// # Errors + /// + /// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`] + /// if `bpf_map_lookup_elem` fails. + pub fn get(&self, index: u32, flags: u64) -> Result { + let data = self.inner.borrow(); + check_bounds(data, index)?; + let fd = data.fd().as_fd(); + + let value = if FEATURES.devmap_prog_id() { + bpf_map_lookup_elem::<_, bpf_devmap_val>(fd, &index, flags).map(|value| { + value.map(|value| DevMapValue { + if_index: value.ifindex, + // SAFETY: map writes use fd, map reads use id. + // https://github.com/torvalds/linux/blob/2dde18cd1d8fac735875f2e4987f11817cc0bc2c/include/uapi/linux/bpf.h#L6228 + prog_id: NonZeroU32::new(unsafe { value.bpf_prog.id }), + }) + }) + } else { + bpf_map_lookup_elem::<_, u32>(fd, &index, flags).map(|value| { + value.map(|ifindex| DevMapValue { + if_index: ifindex, + prog_id: None, + }) + }) + }; + value + .map_err(|(_, io_error)| SyscallError { + call: "bpf_map_lookup_elem", + io_error, + })? + .ok_or(MapError::KeyNotFound) + } + + /// An iterator over the elements of the array. + pub fn iter(&self) -> impl Iterator> + '_ { + (0..self.len()).map(move |i| self.get(i, 0)) + } +} + +impl> DevMap { + /// Sets the target interface index at index, and optionally a chained program. + /// + /// When redirecting using `index`, packets will be transmitted by the interface with + /// `target_if_index`. + /// + /// Starting from Linux kernel 5.8, another XDP program can be passed in that will be run before + /// actual transmission. It can be used to modify the packet before transmission with NIC + /// specific data (MAC address update, checksum computations, etc) or other purposes. + /// + /// The chained program must be loaded with the `BPF_XDP_DEVMAP` attach type. When using + /// `aya-ebpf`, that means XDP programs that specify the `map = "devmap"` argument. See the + /// kernel-space `aya_ebpf::xdp` for more information. + /// + /// # Errors + /// + /// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`] + /// if `bpf_map_update_elem` fails, [`MapError::ProgIdNotSupported`] if the kernel does not + /// support chained programs and one is provided. + pub fn set( + &mut self, + index: u32, + target_if_index: u32, + program: Option<&ProgramFd>, + flags: u64, + ) -> Result<(), XdpMapError> { + let data = self.inner.borrow_mut(); + check_bounds(data, index)?; + let fd = data.fd().as_fd(); + + let res = if FEATURES.devmap_prog_id() { + let mut value = unsafe { std::mem::zeroed::() }; + value.ifindex = target_if_index; + // Default is valid as the kernel will only consider fd > 0: + // https://github.com/torvalds/linux/blob/2dde18cd1d8fac735875f2e4987f11817cc0bc2c/kernel/bpf/devmap.c#L866 + // https://github.com/torvalds/linux/blob/2dde18cd1d8fac735875f2e4987f11817cc0bc2c/kernel/bpf/devmap.c#L918 + value.bpf_prog.fd = program + .map(|prog| prog.as_fd().as_raw_fd()) + .unwrap_or_default(); + bpf_map_update_elem(fd, Some(&index), &value, flags) + } else { + if program.is_some() { + return Err(XdpMapError::ChainedProgramNotSupported); + } + bpf_map_update_elem(fd, Some(&index), &target_if_index, flags) + }; + + res.map_err(|(_, io_error)| { + MapError::from(SyscallError { + call: "bpf_map_update_elem", + io_error, + }) + })?; + Ok(()) + } +} + +impl> IterableMap for DevMap { + fn map(&self) -> &MapData { + self.inner.borrow() + } + + fn get(&self, key: &u32) -> Result { + self.get(*key, 0) + } +} + +unsafe impl Pod for bpf_devmap_val {} + +#[derive(Clone, Copy, Debug)] +/// The value of a device map. +pub struct DevMapValue { + /// Target interface index to redirect to. + pub if_index: u32, + /// Chained XDP program ID. + pub prog_id: Option, +} diff --git a/aya/src/maps/xdp/dev_map_hash.rs b/aya/src/maps/xdp/dev_map_hash.rs new file mode 100644 index 00000000..63a93b02 --- /dev/null +++ b/aya/src/maps/xdp/dev_map_hash.rs @@ -0,0 +1,167 @@ +//! An hashmap of network devices. + +use std::{ + borrow::{Borrow, BorrowMut}, + num::NonZeroU32, + os::fd::{AsFd, AsRawFd}, +}; + +use aya_obj::generated::bpf_devmap_val; + +use super::{dev_map::DevMapValue, XdpMapError}; +use crate::{ + maps::{check_kv_size, hash_map, IterableMap, MapData, MapError, MapIter, MapKeys}, + programs::ProgramFd, + sys::{bpf_map_lookup_elem, SyscallError}, + FEATURES, +}; + +/// An hashmap of network devices. +/// +/// XDP programs can use this map to redirect to other network +/// devices. +/// +/// # Minimum kernel version +/// +/// The minimum kernel version required to use this feature is 5.4. +/// +/// # Examples +/// ```no_run +/// # let mut bpf = aya::Bpf::load(&[])?; +/// use aya::maps::xdp::DevMapHash; +/// +/// let mut devmap = DevMapHash::try_from(bpf.map_mut("IFACES").unwrap())?; +/// // Lookups with key 2 will redirect packets to interface with index 3 (e.g. eth1) +/// devmap.insert(2, 3, None, 0); +/// +/// # Ok::<(), aya::BpfError>(()) +/// ``` +/// +/// # See also +/// +/// Kernel documentation: +#[doc(alias = "BPF_MAP_TYPE_DEVMAP_HASH")] +pub struct DevMapHash { + pub(crate) inner: T, +} + +impl> DevMapHash { + pub(crate) fn new(map: T) -> Result { + let data = map.borrow(); + + if FEATURES.devmap_prog_id() { + check_kv_size::(data)?; + } else { + check_kv_size::(data)?; + } + + Ok(Self { inner: map }) + } + + /// Returns the target interface index and optional program for a given key. + /// + /// # Errors + /// + /// Returns [`MapError::SyscallError`] if `bpf_map_lookup_elem` fails. + pub fn get(&self, key: u32, flags: u64) -> Result { + let fd = self.inner.borrow().fd().as_fd(); + + let value = if FEATURES.devmap_prog_id() { + bpf_map_lookup_elem::<_, bpf_devmap_val>(fd, &key, flags).map(|value| { + value.map(|value| DevMapValue { + if_index: value.ifindex, + // SAFETY: map writes use fd, map reads use id. + // https://github.com/torvalds/linux/blob/2dde18cd1d8fac735875f2e4987f11817cc0bc2c/include/uapi/linux/bpf.h#L6228 + prog_id: NonZeroU32::new(unsafe { value.bpf_prog.id }), + }) + }) + } else { + bpf_map_lookup_elem::<_, u32>(fd, &key, flags).map(|value| { + value.map(|ifindex| DevMapValue { + if_index: ifindex, + prog_id: None, + }) + }) + }; + value + .map_err(|(_, io_error)| SyscallError { + call: "bpf_map_lookup_elem", + io_error, + })? + .ok_or(MapError::KeyNotFound) + } + + /// An iterator over the elements of the devmap in arbitrary order. + pub fn iter(&self) -> MapIter<'_, u32, DevMapValue, Self> { + MapIter::new(self) + } + + /// An iterator visiting all keys in arbitrary order. + pub fn keys(&self) -> MapKeys<'_, u32> { + MapKeys::new(self.inner.borrow()) + } +} + +impl> DevMapHash { + /// Inserts an ifindex and optionally a chained program in the map. + /// + /// When redirecting using `key`, packets will be transmitted by the interface with `ifindex`. + /// + /// Starting from Linux kernel 5.8, another XDP program can be passed in that will be run before + /// actual transmission. It can be used to modify the packet before transmission with NIC + /// specific data (MAC address update, checksum computations, etc) or other purposes. + /// + /// The chained program must be loaded with the `BPF_XDP_DEVMAP` attach type. When using + /// `aya-ebpf`, that means XDP programs that specify the `map = "devmap"` argument. See the + /// kernel-space `aya_ebpf::xdp` for more information. + /// + /// # Errors + /// + /// Returns [`MapError::SyscallError`] if `bpf_map_update_elem` fails, + /// [`MapError::ProgIdNotSupported`] if the kernel does not support chained programs and one is + /// provided. + pub fn insert( + &mut self, + key: u32, + target_if_index: u32, + program: Option<&ProgramFd>, + flags: u64, + ) -> Result<(), XdpMapError> { + if FEATURES.devmap_prog_id() { + let mut value = unsafe { std::mem::zeroed::() }; + value.ifindex = target_if_index; + // Default is valid as the kernel will only consider fd > 0: + // https://github.com/torvalds/linux/blob/2dde18cd1d8fac735875f2e4987f11817cc0bc2c/kernel/bpf/devmap.c#L866 + // https://github.com/torvalds/linux/blob/2dde18cd1d8fac735875f2e4987f11817cc0bc2c/kernel/bpf/devmap.c#L918 + value.bpf_prog.fd = program + .map(|prog| prog.as_fd().as_raw_fd()) + .unwrap_or_default(); + hash_map::insert(self.inner.borrow_mut(), &key, &value, flags)?; + } else { + if program.is_some() { + return Err(XdpMapError::ChainedProgramNotSupported); + } + hash_map::insert(self.inner.borrow_mut(), &key, &target_if_index, flags)?; + } + Ok(()) + } + + /// Removes a value from the map. + /// + /// # Errors + /// + /// Returns [`MapError::SyscallError`] if `bpf_map_delete_elem` fails. + pub fn remove(&mut self, key: u32) -> Result<(), MapError> { + hash_map::remove(self.inner.borrow_mut(), &key) + } +} + +impl> IterableMap for DevMapHash { + fn map(&self) -> &MapData { + self.inner.borrow() + } + + fn get(&self, key: &u32) -> Result { + self.get(*key, 0) + } +} diff --git a/aya/src/maps/xdp/mod.rs b/aya/src/maps/xdp/mod.rs new file mode 100644 index 00000000..2f00492c --- /dev/null +++ b/aya/src/maps/xdp/mod.rs @@ -0,0 +1,25 @@ +//! XDP maps. +mod cpu_map; +mod dev_map; +mod dev_map_hash; +mod xsk_map; + +pub use cpu_map::CpuMap; +pub use dev_map::DevMap; +pub use dev_map_hash::DevMapHash; +use thiserror::Error; +pub use xsk_map::XskMap; + +use super::MapError; + +#[derive(Error, Debug)] +/// Errors occuring from working with XDP maps. +pub enum XdpMapError { + /// Chained programs are not supported. + #[error("chained programs are not supported by the current kernel")] + ChainedProgramNotSupported, + + /// Map operation failed. + #[error(transparent)] + MapError(#[from] MapError), +} diff --git a/aya/src/maps/xdp/xsk_map.rs b/aya/src/maps/xdp/xsk_map.rs new file mode 100644 index 00000000..43924abf --- /dev/null +++ b/aya/src/maps/xdp/xsk_map.rs @@ -0,0 +1,81 @@ +//! An array of AF_XDP sockets. + +use std::{ + borrow::{Borrow, BorrowMut}, + os::fd::{AsFd, AsRawFd, RawFd}, +}; + +use crate::{ + maps::{check_bounds, check_kv_size, MapData, MapError}, + sys::{bpf_map_update_elem, SyscallError}, +}; + +/// An array of AF_XDP sockets. +/// +/// XDP programs can use this map to redirect packets to a target +/// AF_XDP socket using the `XDP_REDIRECT` action. +/// +/// # Minimum kernel version +/// +/// The minimum kernel version required to use this feature is 4.18. +/// +/// # Examples +/// ```no_run +/// # let mut bpf = aya::Bpf::load(&[])?; +/// # let socket_fd = 1; +/// use aya::maps::XskMap; +/// +/// let mut xskmap = XskMap::try_from(bpf.map_mut("SOCKETS").unwrap())?; +/// // socket_fd is the RawFd of an AF_XDP socket +/// xskmap.set(0, socket_fd, 0); +/// # Ok::<(), aya::BpfError>(()) +/// ``` +/// +/// # See also +/// +/// Kernel documentation: +#[doc(alias = "BPF_MAP_TYPE_XSKMAP")] +pub struct XskMap { + pub(crate) inner: T, +} + +impl> XskMap { + pub(crate) fn new(map: T) -> Result { + let data = map.borrow(); + check_kv_size::(data)?; + + Ok(Self { inner: map }) + } + + /// Returns the number of elements in the array. + /// + /// This corresponds to the value of `bpf_map_def::max_entries` on the eBPF side. + pub fn len(&self) -> u32 { + self.inner.borrow().obj.max_entries() + } +} + +impl> XskMap { + /// Sets the `AF_XDP` socket at a given index. + /// + /// When redirecting a packet, the `AF_XDP` socket at `index` will recieve the packet. Note + /// that it will do so only if the socket is bound to the same queue the packet was recieved + /// on. + /// + /// # Errors + /// + /// Returns [`MapError::OutOfBounds`] if `index` is out of bounds, [`MapError::SyscallError`] + /// if `bpf_map_update_elem` fails. + pub fn set(&mut self, index: u32, socket_fd: impl AsRawFd, flags: u64) -> Result<(), MapError> { + let data = self.inner.borrow_mut(); + check_bounds(data, index)?; + let fd = data.fd().as_fd(); + bpf_map_update_elem(fd, Some(&index), &socket_fd.as_raw_fd(), flags).map_err( + |(_, io_error)| SyscallError { + call: "bpf_map_update_elem", + io_error, + }, + )?; + Ok(()) + } +} diff --git a/aya/src/pin.rs b/aya/src/pin.rs index eda85bbc..28ff03c4 100644 --- a/aya/src/pin.rs +++ b/aya/src/pin.rs @@ -1,17 +1,12 @@ //! Pinning BPF objects to the BPF filesystem. -use crate::sys::SyscallError; use thiserror::Error; +use crate::sys::SyscallError; + /// An error ocurred working with a pinned BPF object. #[derive(Error, Debug)] pub enum PinError { - /// The object has already been pinned. - #[error("the BPF object `{name}` has already been pinned")] - AlreadyPinned { - /// Object name. - name: String, - }, /// The object FD is not known by Aya. #[error("the BPF object `{name}`'s FD is not known")] NoFd { @@ -19,10 +14,14 @@ pub enum PinError { name: String, }, /// The path for the BPF object is not valid. - #[error("invalid pin path `{error}`")] + #[error("invalid pin path `{}`", path.display())] InvalidPinPath { - /// The error message. - error: String, + /// The path. + path: std::path::PathBuf, + + #[source] + /// The source error. + error: std::ffi::NulError, }, /// An error ocurred making a syscall. #[error(transparent)] diff --git a/aya/src/programs/cgroup_device.rs b/aya/src/programs/cgroup_device.rs index 1244d27c..180d3757 100644 --- a/aya/src/programs/cgroup_device.rs +++ b/aya/src/programs/cgroup_device.rs @@ -1,14 +1,14 @@ //! Cgroup device programs. -use crate::util::KernelVersion; -use std::os::fd::{AsFd as _, AsRawFd}; +use std::os::fd::AsFd; use crate::{ generated::{bpf_attach_type::BPF_CGROUP_DEVICE, bpf_prog_type::BPF_PROG_TYPE_CGROUP_DEVICE}, programs::{ define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError, }, - sys::{bpf_link_create, bpf_prog_attach, SyscallError}, + sys::{bpf_link_create, LinkTarget, SyscallError}, + util::KernelVersion, }; /// A program used to watch or prevent device interaction from a cgroup. @@ -60,35 +60,35 @@ impl CgroupDevice { /// Attaches the program to the given cgroup. /// /// The returned value can be used to detach, see [CgroupDevice::detach] - pub fn attach(&mut self, cgroup: T) -> Result { + pub fn attach(&mut self, cgroup: T) -> Result { 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 cgroup_fd = cgroup.as_fd(); if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { - let link_fd = bpf_link_create(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE, None, 0).map_err( - |(_, io_error)| SyscallError { - call: "bpf_link_create", - io_error, - }, - )?; + let link_fd = bpf_link_create( + prog_fd, + LinkTarget::Fd(cgroup_fd), + BPF_CGROUP_DEVICE, + None, + 0, + ) + .map_err(|(_, io_error)| SyscallError { + call: "bpf_link_create", + io_error, + })?; self.data .links .insert(CgroupDeviceLink::new(CgroupDeviceLinkInner::Fd( FdLink::new(link_fd), ))) } else { - bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE).map_err(|(_, io_error)| { - SyscallError { - call: "bpf_prog_attach", - io_error, - } - })?; + let link = ProgAttachLink::attach(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE)?; + self.data .links .insert(CgroupDeviceLink::new(CgroupDeviceLinkInner::ProgAttach( - ProgAttachLink::new(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE), + link, ))) } } @@ -129,15 +129,15 @@ impl Link for CgroupDeviceLinkInner { fn id(&self) -> Self::Id { match self { - CgroupDeviceLinkInner::Fd(fd) => CgroupDeviceLinkIdInner::Fd(fd.id()), - CgroupDeviceLinkInner::ProgAttach(p) => CgroupDeviceLinkIdInner::ProgAttach(p.id()), + Self::Fd(fd) => CgroupDeviceLinkIdInner::Fd(fd.id()), + Self::ProgAttach(p) => CgroupDeviceLinkIdInner::ProgAttach(p.id()), } } fn detach(self) -> Result<(), ProgramError> { match self { - CgroupDeviceLinkInner::Fd(fd) => fd.detach(), - CgroupDeviceLinkInner::ProgAttach(p) => p.detach(), + Self::Fd(fd) => fd.detach(), + Self::ProgAttach(p) => p.detach(), } } } diff --git a/aya/src/programs/cgroup_skb.rs b/aya/src/programs/cgroup_skb.rs index 684fd18e..1f99835c 100644 --- a/aya/src/programs/cgroup_skb.rs +++ b/aya/src/programs/cgroup_skb.rs @@ -1,11 +1,6 @@ //! Cgroup skb programs. -use crate::util::KernelVersion; -use std::{ - hash::Hash, - os::fd::{AsFd as _, AsRawFd}, - path::Path, -}; +use std::{hash::Hash, os::fd::AsFd, path::Path}; use crate::{ generated::{ @@ -15,7 +10,8 @@ use crate::{ programs::{ define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError, }, - sys::{bpf_link_create, bpf_prog_attach, SyscallError}, + sys::{bpf_link_create, LinkTarget, SyscallError}, + util::KernelVersion, VerifierLogLevel, }; @@ -87,45 +83,36 @@ impl CgroupSkb { /// Attaches the program to the given cgroup. /// /// The returned value can be used to detach, see [CgroupSkb::detach]. - pub fn attach( + pub fn attach( &mut self, cgroup: T, attach_type: CgroupSkbAttachType, ) -> Result { 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 cgroup_fd = cgroup.as_fd(); let attach_type = match attach_type { CgroupSkbAttachType::Ingress => BPF_CGROUP_INET_INGRESS, CgroupSkbAttachType::Egress => BPF_CGROUP_INET_EGRESS, }; if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { - let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err( - |(_, io_error)| SyscallError { + let link_fd = bpf_link_create(prog_fd, LinkTarget::Fd(cgroup_fd), attach_type, None, 0) + .map_err(|(_, io_error)| SyscallError { call: "bpf_link_create", io_error, - }, - )?; + })?; self.data .links .insert(CgroupSkbLink::new(CgroupSkbLinkInner::Fd(FdLink::new( link_fd, )))) } else { - bpf_prog_attach(prog_fd, cgroup_fd, attach_type).map_err(|(_, io_error)| { - SyscallError { - call: "bpf_prog_attach", - io_error, - } - })?; + let link = ProgAttachLink::attach(prog_fd, cgroup_fd, attach_type)?; self.data .links - .insert(CgroupSkbLink::new(CgroupSkbLinkInner::ProgAttach( - ProgAttachLink::new(prog_fd, cgroup_fd, attach_type), - ))) + .insert(CgroupSkbLink::new(CgroupSkbLinkInner::ProgAttach(link))) } } @@ -179,15 +166,15 @@ impl Link for CgroupSkbLinkInner { fn id(&self) -> Self::Id { match self { - CgroupSkbLinkInner::Fd(fd) => CgroupSkbLinkIdInner::Fd(fd.id()), - CgroupSkbLinkInner::ProgAttach(p) => CgroupSkbLinkIdInner::ProgAttach(p.id()), + Self::Fd(fd) => CgroupSkbLinkIdInner::Fd(fd.id()), + Self::ProgAttach(p) => CgroupSkbLinkIdInner::ProgAttach(p.id()), } } fn detach(self) -> Result<(), ProgramError> { match self { - CgroupSkbLinkInner::Fd(fd) => fd.detach(), - CgroupSkbLinkInner::ProgAttach(p) => p.detach(), + Self::Fd(fd) => fd.detach(), + Self::ProgAttach(p) => p.detach(), } } } diff --git a/aya/src/programs/cgroup_sock.rs b/aya/src/programs/cgroup_sock.rs index c906ee6c..971ef9e9 100644 --- a/aya/src/programs/cgroup_sock.rs +++ b/aya/src/programs/cgroup_sock.rs @@ -1,20 +1,16 @@ //! Cgroup socket programs. -pub use aya_obj::programs::CgroupSockAttachType; +use std::{hash::Hash, os::fd::AsFd, path::Path}; -use crate::util::KernelVersion; -use std::{ - hash::Hash, - os::fd::{AsFd as _, AsRawFd}, - path::Path, -}; +pub use aya_obj::programs::CgroupSockAttachType; use crate::{ generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCK, programs::{ define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError, }, - sys::{bpf_link_create, bpf_prog_attach, SyscallError}, + sys::{bpf_link_create, LinkTarget, SyscallError}, + util::KernelVersion, VerifierLogLevel, }; @@ -70,37 +66,28 @@ impl CgroupSock { /// Attaches the program to the given cgroup. /// /// The returned value can be used to detach, see [CgroupSock::detach]. - pub fn attach(&mut self, cgroup: T) -> Result { + pub fn attach(&mut self, cgroup: T) -> Result { 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 cgroup_fd = cgroup.as_fd(); let attach_type = self.data.expected_attach_type.unwrap(); if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { - let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err( - |(_, io_error)| SyscallError { + let link_fd = bpf_link_create(prog_fd, LinkTarget::Fd(cgroup_fd), attach_type, None, 0) + .map_err(|(_, io_error)| SyscallError { call: "bpf_link_create", io_error, - }, - )?; + })?; self.data .links .insert(CgroupSockLink::new(CgroupSockLinkInner::Fd(FdLink::new( link_fd, )))) } else { - bpf_prog_attach(prog_fd, cgroup_fd, attach_type).map_err(|(_, io_error)| { - SyscallError { - call: "bpf_prog_attach", - io_error, - } - })?; + let link = ProgAttachLink::attach(prog_fd, cgroup_fd, attach_type)?; self.data .links - .insert(CgroupSockLink::new(CgroupSockLinkInner::ProgAttach( - ProgAttachLink::new(prog_fd, cgroup_fd, attach_type), - ))) + .insert(CgroupSockLink::new(CgroupSockLinkInner::ProgAttach(link))) } } @@ -151,15 +138,15 @@ impl Link for CgroupSockLinkInner { fn id(&self) -> Self::Id { match self { - CgroupSockLinkInner::Fd(fd) => CgroupSockLinkIdInner::Fd(fd.id()), - CgroupSockLinkInner::ProgAttach(p) => CgroupSockLinkIdInner::ProgAttach(p.id()), + Self::Fd(fd) => CgroupSockLinkIdInner::Fd(fd.id()), + Self::ProgAttach(p) => CgroupSockLinkIdInner::ProgAttach(p.id()), } } fn detach(self) -> Result<(), ProgramError> { match self { - CgroupSockLinkInner::Fd(fd) => fd.detach(), - CgroupSockLinkInner::ProgAttach(p) => p.detach(), + Self::Fd(fd) => fd.detach(), + Self::ProgAttach(p) => p.detach(), } } } diff --git a/aya/src/programs/cgroup_sock_addr.rs b/aya/src/programs/cgroup_sock_addr.rs index 98d60eb1..f9a2fb7f 100644 --- a/aya/src/programs/cgroup_sock_addr.rs +++ b/aya/src/programs/cgroup_sock_addr.rs @@ -1,20 +1,16 @@ //! Cgroup socket address programs. -pub use aya_obj::programs::CgroupSockAddrAttachType; +use std::{hash::Hash, os::fd::AsFd, path::Path}; -use crate::util::KernelVersion; -use std::{ - hash::Hash, - os::fd::{AsFd as _, AsRawFd}, - path::Path, -}; +pub use aya_obj::programs::CgroupSockAddrAttachType; use crate::{ generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCK_ADDR, programs::{ define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError, }, - sys::{bpf_link_create, bpf_prog_attach, SyscallError}, + sys::{bpf_link_create, LinkTarget, SyscallError}, + util::KernelVersion, VerifierLogLevel, }; @@ -71,38 +67,27 @@ impl CgroupSockAddr { /// Attaches the program to the given cgroup. /// /// The returned value can be used to detach, see [CgroupSockAddr::detach]. - pub fn attach(&mut self, cgroup: T) -> Result { + pub fn attach(&mut self, cgroup: T) -> Result { 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 cgroup_fd = cgroup.as_fd(); let attach_type = self.data.expected_attach_type.unwrap(); if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { - let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err( - |(_, io_error)| SyscallError { + let link_fd = bpf_link_create(prog_fd, LinkTarget::Fd(cgroup_fd), attach_type, None, 0) + .map_err(|(_, io_error)| SyscallError { call: "bpf_link_create", io_error, - }, - )?; + })?; self.data .links .insert(CgroupSockAddrLink::new(CgroupSockAddrLinkInner::Fd( FdLink::new(link_fd), ))) } else { - bpf_prog_attach(prog_fd, cgroup_fd, attach_type).map_err(|(_, io_error)| { - SyscallError { - call: "bpf_prog_attach", - io_error, - } - })?; + let link = ProgAttachLink::attach(prog_fd, cgroup_fd, attach_type)?; self.data.links.insert(CgroupSockAddrLink::new( - CgroupSockAddrLinkInner::ProgAttach(ProgAttachLink::new( - prog_fd, - cgroup_fd, - attach_type, - )), + CgroupSockAddrLinkInner::ProgAttach(link), )) } } @@ -157,15 +142,15 @@ impl Link for CgroupSockAddrLinkInner { fn id(&self) -> Self::Id { match self { - CgroupSockAddrLinkInner::Fd(fd) => CgroupSockAddrLinkIdInner::Fd(fd.id()), - CgroupSockAddrLinkInner::ProgAttach(p) => CgroupSockAddrLinkIdInner::ProgAttach(p.id()), + Self::Fd(fd) => CgroupSockAddrLinkIdInner::Fd(fd.id()), + Self::ProgAttach(p) => CgroupSockAddrLinkIdInner::ProgAttach(p.id()), } } fn detach(self) -> Result<(), ProgramError> { match self { - CgroupSockAddrLinkInner::Fd(fd) => fd.detach(), - CgroupSockAddrLinkInner::ProgAttach(p) => p.detach(), + Self::Fd(fd) => fd.detach(), + Self::ProgAttach(p) => p.detach(), } } } diff --git a/aya/src/programs/cgroup_sockopt.rs b/aya/src/programs/cgroup_sockopt.rs index c137d769..33ac84fe 100644 --- a/aya/src/programs/cgroup_sockopt.rs +++ b/aya/src/programs/cgroup_sockopt.rs @@ -1,20 +1,16 @@ //! Cgroup socket option programs. -pub use aya_obj::programs::CgroupSockoptAttachType; +use std::{hash::Hash, os::fd::AsFd, path::Path}; -use crate::util::KernelVersion; -use std::{ - hash::Hash, - os::fd::{AsFd as _, AsRawFd}, - path::Path, -}; +pub use aya_obj::programs::CgroupSockoptAttachType; use crate::{ generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCKOPT, programs::{ define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError, }, - sys::{bpf_link_create, bpf_prog_attach, SyscallError}, + sys::{bpf_link_create, LinkTarget, SyscallError}, + util::KernelVersion, VerifierLogLevel, }; @@ -68,36 +64,29 @@ impl CgroupSockopt { /// Attaches the program to the given cgroup. /// /// The returned value can be used to detach, see [CgroupSockopt::detach]. - pub fn attach(&mut self, cgroup: T) -> Result { + pub fn attach(&mut self, cgroup: T) -> Result { 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 cgroup_fd = cgroup.as_fd(); let attach_type = self.data.expected_attach_type.unwrap(); if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { - let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err( - |(_, io_error)| SyscallError { + let link_fd = bpf_link_create(prog_fd, LinkTarget::Fd(cgroup_fd), attach_type, None, 0) + .map_err(|(_, io_error)| SyscallError { call: "bpf_link_create", io_error, - }, - )?; + })?; self.data .links .insert(CgroupSockoptLink::new(CgroupSockoptLinkInner::Fd( FdLink::new(link_fd), ))) } else { - bpf_prog_attach(prog_fd, cgroup_fd, attach_type).map_err(|(_, io_error)| { - SyscallError { - call: "bpf_prog_attach", - io_error, - } - })?; + let link = ProgAttachLink::attach(prog_fd, cgroup_fd, attach_type)?; self.data .links .insert(CgroupSockoptLink::new(CgroupSockoptLinkInner::ProgAttach( - ProgAttachLink::new(prog_fd, cgroup_fd, attach_type), + link, ))) } } @@ -152,15 +141,15 @@ impl Link for CgroupSockoptLinkInner { fn id(&self) -> Self::Id { match self { - CgroupSockoptLinkInner::Fd(fd) => CgroupSockoptLinkIdInner::Fd(fd.id()), - CgroupSockoptLinkInner::ProgAttach(p) => CgroupSockoptLinkIdInner::ProgAttach(p.id()), + Self::Fd(fd) => CgroupSockoptLinkIdInner::Fd(fd.id()), + Self::ProgAttach(p) => CgroupSockoptLinkIdInner::ProgAttach(p.id()), } } fn detach(self) -> Result<(), ProgramError> { match self { - CgroupSockoptLinkInner::Fd(fd) => fd.detach(), - CgroupSockoptLinkInner::ProgAttach(p) => p.detach(), + Self::Fd(fd) => fd.detach(), + Self::ProgAttach(p) => p.detach(), } } } diff --git a/aya/src/programs/cgroup_sysctl.rs b/aya/src/programs/cgroup_sysctl.rs index d5325089..80c1e028 100644 --- a/aya/src/programs/cgroup_sysctl.rs +++ b/aya/src/programs/cgroup_sysctl.rs @@ -1,17 +1,14 @@ //! Cgroup sysctl programs. -use crate::util::KernelVersion; -use std::{ - hash::Hash, - os::fd::{AsFd as _, AsRawFd}, -}; +use std::{hash::Hash, os::fd::AsFd}; use crate::{ generated::{bpf_attach_type::BPF_CGROUP_SYSCTL, bpf_prog_type::BPF_PROG_TYPE_CGROUP_SYSCTL}, programs::{ define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError, }, - sys::{bpf_link_create, bpf_prog_attach, SyscallError}, + sys::{bpf_link_create, LinkTarget, SyscallError}, + util::KernelVersion, }; /// A program used to watch for sysctl changes. @@ -62,36 +59,35 @@ impl CgroupSysctl { /// Attaches the program to the given cgroup. /// /// The returned value can be used to detach, see [CgroupSysctl::detach]. - pub fn attach(&mut self, cgroup: T) -> Result { + pub fn attach(&mut self, cgroup: T) -> Result { 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 cgroup_fd = cgroup.as_fd(); if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { - let link_fd = bpf_link_create(prog_fd, cgroup_fd, BPF_CGROUP_SYSCTL, None, 0).map_err( - |(_, io_error)| SyscallError { - call: "bpf_link_create", - io_error, - }, - )?; + let link_fd = bpf_link_create( + prog_fd, + LinkTarget::Fd(cgroup_fd), + BPF_CGROUP_SYSCTL, + None, + 0, + ) + .map_err(|(_, io_error)| SyscallError { + call: "bpf_link_create", + io_error, + })?; self.data .links .insert(CgroupSysctlLink::new(CgroupSysctlLinkInner::Fd( FdLink::new(link_fd), ))) } else { - bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SYSCTL).map_err(|(_, io_error)| { - SyscallError { - call: "bpf_prog_attach", - io_error, - } - })?; + let link = ProgAttachLink::attach(prog_fd, cgroup_fd, BPF_CGROUP_SYSCTL)?; self.data .links .insert(CgroupSysctlLink::new(CgroupSysctlLinkInner::ProgAttach( - ProgAttachLink::new(prog_fd, cgroup_fd, BPF_CGROUP_SYSCTL), + link, ))) } } @@ -132,15 +128,15 @@ impl Link for CgroupSysctlLinkInner { fn id(&self) -> Self::Id { match self { - CgroupSysctlLinkInner::Fd(fd) => CgroupSysctlLinkIdInner::Fd(fd.id()), - CgroupSysctlLinkInner::ProgAttach(p) => CgroupSysctlLinkIdInner::ProgAttach(p.id()), + Self::Fd(fd) => CgroupSysctlLinkIdInner::Fd(fd.id()), + Self::ProgAttach(p) => CgroupSysctlLinkIdInner::ProgAttach(p.id()), } } fn detach(self) -> Result<(), ProgramError> { match self { - CgroupSysctlLinkInner::Fd(fd) => fd.detach(), - CgroupSysctlLinkInner::ProgAttach(p) => p.detach(), + Self::Fd(fd) => fd.detach(), + Self::ProgAttach(p) => p.detach(), } } } diff --git a/aya/src/programs/extension.rs b/aya/src/programs/extension.rs index e1aab2c2..3785a57c 100644 --- a/aya/src/programs/extension.rs +++ b/aya/src/programs/extension.rs @@ -1,8 +1,9 @@ //! Extension programs. -use std::os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, OwnedFd}; -use thiserror::Error; + +use std::os::fd::{AsFd as _, BorrowedFd, OwnedFd}; use object::Endianness; +use thiserror::Error; use crate::{ generated::{bpf_attach_type::BPF_CGROUP_INET_INGRESS, bpf_prog_type::BPF_PROG_TYPE_EXT}, @@ -10,7 +11,7 @@ use crate::{ programs::{ define_link_wrapper, load_program, FdLink, FdLinkId, ProgramData, ProgramError, ProgramFd, }, - sys::{self, bpf_link_create, SyscallError}, + sys::{self, bpf_link_create, LinkTarget, SyscallError}, Btf, }; @@ -88,21 +89,25 @@ impl Extension { pub fn attach(&mut self) -> Result { 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) - .map_err(|(_, io_error)| SyscallError { - call: "bpf_link_create", - io_error, - })?; + let link_fd = bpf_link_create( + prog_fd, + LinkTarget::Fd(target_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))) @@ -128,11 +133,10 @@ impl Extension { let (_, btf_id) = get_btf_info(target_fd, func_name)?; 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.as_raw_fd(), + LinkTarget::Fd(target_fd), BPF_CGROUP_INET_INGRESS, Some(btf_id), 0, diff --git a/aya/src/programs/kprobe.rs b/aya/src/programs/kprobe.rs index f9cbb667..8902c9eb 100644 --- a/aya/src/programs/kprobe.rs +++ b/aya/src/programs/kprobe.rs @@ -1,5 +1,11 @@ //! Kernel space probes. -use std::{io, os::fd::AsFd as _, path::Path}; +use std::{ + ffi::OsStr, + io, + os::fd::AsFd as _, + path::{Path, PathBuf}, +}; + use thiserror::Error; use crate::{ @@ -67,8 +73,12 @@ impl KProbe { /// target function. /// /// The returned value can be used to detach from the given function, see [KProbe::detach]. - pub fn attach(&mut self, fn_name: &str, offset: u64) -> Result { - attach(&mut self.data, self.kind, fn_name, offset, None) + pub fn attach>( + &mut self, + fn_name: T, + offset: u64, + ) -> Result { + attach(&mut self.data, self.kind, fn_name.as_ref(), offset, None) } /// Detaches the program. @@ -114,7 +124,7 @@ pub enum KProbeError { #[error("`{filename}`")] FileError { /// The file name - filename: String, + filename: PathBuf, /// The [`io::Error`] returned from the file operation #[source] io_error: io::Error, @@ -139,7 +149,7 @@ impl TryFrom for KProbeLink { fn try_from(fd_link: FdLink) -> Result { let info = bpf_link_get_info_by_fd(fd_link.fd.as_fd())?; if info.type_ == (bpf_link_type::BPF_LINK_TYPE_KPROBE_MULTI as u32) { - return Ok(KProbeLink::new(PerfLinkInner::FdLink(fd_link))); + return Ok(Self::new(PerfLinkInner::FdLink(fd_link))); } Err(LinkError::InvalidLink) } diff --git a/aya/src/programs/links.rs b/aya/src/programs/links.rs index 52aa60de..d947d64f 100644 --- a/aya/src/programs/links.rs +++ b/aya/src/programs/links.rs @@ -1,20 +1,19 @@ //! Program links. -use libc::{close, dup}; -use thiserror::Error; - use std::{ collections::{hash_map::Entry, HashMap}, ffi::CString, io, - os::fd::{AsRawFd as _, OwnedFd, RawFd}, + os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, OwnedFd, RawFd}, path::{Path, PathBuf}, }; +use thiserror::Error; + use crate::{ generated::bpf_attach_type, pin::PinError, - programs::ProgramError, - sys::{bpf_get_object, bpf_pin_object, bpf_prog_detach, SyscallError}, + programs::{ProgramError, ProgramFd}, + sys::{bpf_get_object, bpf_pin_object, bpf_prog_attach, bpf_prog_detach, SyscallError}, }; /// A Link. @@ -35,8 +34,8 @@ pub(crate) struct LinkMap { } impl LinkMap { - pub(crate) fn new() -> LinkMap { - LinkMap { + pub(crate) fn new() -> Self { + Self { links: HashMap::new(), } } @@ -112,8 +111,8 @@ pub struct FdLink { } impl FdLink { - pub(crate) fn new(fd: OwnedFd) -> FdLink { - FdLink { fd } + pub(crate) fn new(fd: OwnedFd) -> Self { + Self { fd } } /// Pins the link to a BPF file system. @@ -146,19 +145,20 @@ impl FdLink { /// # Ok::<(), Error>(()) /// ``` pub fn pin>(self, path: P) -> Result { - let path_string = - CString::new(path.as_ref().to_string_lossy().into_owned()).map_err(|e| { - PinError::InvalidPinPath { - error: e.to_string(), - } - })?; - bpf_pin_object(self.fd.as_raw_fd(), &path_string).map_err(|(_, io_error)| { - SyscallError { - call: "BPF_OBJ_PIN", - io_error, + use std::os::unix::ffi::OsStrExt as _; + + let path = path.as_ref(); + let path_string = CString::new(path.as_os_str().as_bytes()).map_err(|error| { + PinError::InvalidPinPath { + path: path.into(), + error, } })?; - Ok(PinnedLink::new(PathBuf::from(path.as_ref()), self)) + bpf_pin_object(self.fd.as_fd(), &path_string).map_err(|(_, io_error)| SyscallError { + call: "BPF_OBJ_PIN", + io_error, + })?; + Ok(PinnedLink::new(path.into(), self)) } } @@ -198,22 +198,22 @@ pub struct PinnedLink { impl PinnedLink { fn new(path: PathBuf, link: FdLink) -> Self { - PinnedLink { inner: link, path } + Self { inner: link, path } } /// Creates a [`crate::programs::links::PinnedLink`] from a valid path on bpffs. pub fn from_pin>(path: P) -> Result { - let path_string = CString::new(path.as_ref().to_string_lossy().to_string()).unwrap(); + use std::os::unix::ffi::OsStrExt as _; + + // TODO: avoid this unwrap by adding a new error variant. + let path_string = CString::new(path.as_ref().as_os_str().as_bytes()).unwrap(); let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| { LinkError::SyscallError(SyscallError { call: "BPF_OBJ_GET", io_error, }) })?; - Ok(PinnedLink::new( - path.as_ref().to_path_buf(), - FdLink::new(fd), - )) + Ok(Self::new(path.as_ref().to_path_buf(), FdLink::new(fd))) } /// Removes the pinned link from the filesystem and returns an [`FdLink`]. @@ -230,22 +230,31 @@ pub struct ProgAttachLinkId(RawFd, RawFd, bpf_attach_type); /// The Link type used by programs that are attached with `bpf_prog_attach`. #[derive(Debug)] pub struct ProgAttachLink { - prog_fd: RawFd, - target_fd: RawFd, + prog_fd: ProgramFd, + target_fd: OwnedFd, attach_type: bpf_attach_type, } impl ProgAttachLink { - pub(crate) fn new( - prog_fd: RawFd, - target_fd: RawFd, + pub(crate) fn attach( + prog_fd: BorrowedFd<'_>, + target_fd: BorrowedFd<'_>, attach_type: bpf_attach_type, - ) -> ProgAttachLink { - ProgAttachLink { + ) -> Result { + // The link is going to own this new file descriptor so we are + // going to need a duplicate whose lifetime we manage. Let's + // duplicate it prior to attaching it so the new file + // descriptor is closed at drop in case it fails to attach. + let prog_fd = prog_fd.try_clone_to_owned()?; + let target_fd = target_fd.try_clone_to_owned()?; + bpf_prog_attach(prog_fd.as_fd(), target_fd.as_fd(), attach_type)?; + + let prog_fd = ProgramFd(prog_fd); + Ok(Self { prog_fd, - target_fd: unsafe { dup(target_fd) }, + target_fd, attach_type, - } + }) } } @@ -253,13 +262,20 @@ impl Link for ProgAttachLink { type Id = ProgAttachLinkId; fn id(&self) -> Self::Id { - ProgAttachLinkId(self.prog_fd, self.target_fd, self.attach_type) + ProgAttachLinkId( + self.prog_fd.as_fd().as_raw_fd(), + self.target_fd.as_raw_fd(), + self.attach_type, + ) } fn detach(self) -> Result<(), ProgramError> { - let _ = bpf_prog_detach(self.prog_fd, self.target_fd, self.attach_type); - unsafe { close(self.target_fd) }; - Ok(()) + bpf_prog_detach( + self.prog_fd.as_fd(), + self.target_fd.as_fd(), + self.attach_type, + ) + .map_err(Into::into) } } @@ -300,7 +316,7 @@ macro_rules! define_link_wrapper { } } - impl crate::programs::Link for $wrapper { + impl $crate::programs::Link for $wrapper { type Id = $wrapper_id; fn id(&self) -> Self::Id { @@ -341,13 +357,13 @@ pub enum LinkError { #[cfg(test)] mod tests { - use assert_matches::assert_matches; use std::{cell::RefCell, fs::File, rc::Rc}; - use tempfile::tempdir; - use crate::{programs::ProgramError, sys::override_syscall}; + use assert_matches::assert_matches; + use tempfile::tempdir; use super::{FdLink, Link, LinkMap}; + use crate::{programs::ProgramError, sys::override_syscall}; #[derive(Debug, Hash, Eq, PartialEq)] struct TestLinkId(u8, u8); @@ -359,8 +375,8 @@ mod tests { } impl TestLink { - fn new(a: u8, b: u8) -> TestLink { - TestLink { + fn new(a: u8, b: u8) -> Self { + Self { id: (a, b), detached: Rc::new(RefCell::new(0)), } diff --git a/aya/src/programs/lirc_mode2.rs b/aya/src/programs/lirc_mode2.rs index 906eec96..6e62ce60 100644 --- a/aya/src/programs/lirc_mode2.rs +++ b/aya/src/programs/lirc_mode2.rs @@ -1,14 +1,12 @@ //! Lirc programs. -use std::os::fd::{AsFd as _, AsRawFd, BorrowedFd, IntoRawFd as _, RawFd}; +use std::os::fd::{AsFd, AsRawFd as _, OwnedFd, 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, SyscallError}, + programs::{load_program, query, Link, ProgramData, ProgramError, ProgramFd, ProgramInfo}, + sys::{bpf_prog_attach, bpf_prog_detach, bpf_prog_get_fd_by_id}, }; -use libc::{close, dup}; - /// A program used to decode IR into key events for a lirc device. /// /// [`LircMode2`] programs can be used to inspect infrared pulses, spaces, @@ -60,18 +58,17 @@ impl LircMode2 { /// Attaches the program to the given lirc device. /// /// The returned value can be used to detach, see [LircMode2::detach]. - pub fn attach(&mut self, lircdev: T) -> Result { + pub fn attach(&mut self, lircdev: T) -> Result { 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)| { - SyscallError { - call: "bpf_prog_attach", - io_error, - } - })?; + // The link is going to own this new file descriptor so we are + // going to need a duplicate whose lifetime we manage. Let's + // duplicate it prior to attaching it so the new file + // descriptor is closed at drop in case it fails to attach. + let prog_fd = prog_fd.try_clone()?; + let lircdev_fd = lircdev.as_fd().try_clone_to_owned()?; + + bpf_prog_attach(prog_fd.as_fd(), lircdev_fd.as_fd(), BPF_LIRC_MODE2)?; self.data.links.insert(LircLink::new(prog_fd, lircdev_fd)) } @@ -92,20 +89,19 @@ impl LircMode2 { } /// Queries the lirc device for attached programs. - pub fn query(target_fd: T) -> Result, ProgramError> { - let prog_ids = query(target_fd.as_raw_fd(), BPF_LIRC_MODE2, 0, &mut None)?; - - let mut prog_fds = Vec::with_capacity(prog_ids.len()); + pub fn query(target_fd: T) -> Result, ProgramError> { + let target_fd = target_fd.as_fd(); + let prog_ids = query(target_fd, BPF_LIRC_MODE2, 0, &mut None)?; - for id in prog_ids { - let fd = bpf_prog_get_fd_by_id(id)?; - prog_fds.push(fd); - } - - Ok(prog_fds + prog_ids .into_iter() - .map(|prog_fd| LircLink::new(prog_fd.into_raw_fd(), target_fd.as_raw_fd())) - .collect()) + .map(|prog_id| { + let prog_fd = bpf_prog_get_fd_by_id(prog_id)?; + let target_fd = target_fd.try_clone_to_owned()?; + let prog_fd = ProgramFd(prog_fd); + Ok(LircLink::new(prog_fd, target_fd)) + }) + .collect() } } @@ -116,23 +112,22 @@ pub struct LircLinkId(RawFd, RawFd); #[derive(Debug)] /// An LircMode2 Link pub struct LircLink { - prog_fd: RawFd, - target_fd: RawFd, + prog_fd: ProgramFd, + target_fd: OwnedFd, } impl LircLink { - pub(crate) fn new(prog_fd: RawFd, target_fd: RawFd) -> LircLink { - LircLink { - prog_fd, - target_fd: unsafe { dup(target_fd) }, - } + pub(crate) fn new(prog_fd: ProgramFd, target_fd: OwnedFd) -> Self { + Self { prog_fd, target_fd } } /// Get ProgramInfo from this link pub fn info(&self) -> Result { - // 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) + let Self { + prog_fd, + target_fd: _, + } = self; + ProgramInfo::new_from_fd(prog_fd.as_fd()) } } @@ -140,12 +135,11 @@ impl Link for LircLink { type Id = LircLinkId; fn id(&self) -> Self::Id { - LircLinkId(self.prog_fd, self.target_fd) + LircLinkId(self.prog_fd.as_fd().as_raw_fd(), self.target_fd.as_raw_fd()) } fn detach(self) -> Result<(), ProgramError> { - let _ = bpf_prog_detach(self.prog_fd, self.target_fd, BPF_LIRC_MODE2); - unsafe { close(self.target_fd) }; - Ok(()) + bpf_prog_detach(self.prog_fd.as_fd(), self.target_fd.as_fd(), BPF_LIRC_MODE2) + .map_err(Into::into) } } diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index b79627a8..fcbbce86 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -64,7 +64,6 @@ pub mod uprobe; mod utils; pub mod xdp; -use libc::ENOSPC; use std::{ ffi::CString, io, @@ -74,7 +73,6 @@ use std::{ sync::Arc, time::{Duration, SystemTime}, }; -use thiserror::Error; pub use cgroup_device::CgroupDevice; pub use cgroup_skb::{CgroupSkb, CgroupSkbAttachType}; @@ -86,6 +84,7 @@ pub use extension::{Extension, ExtensionError}; pub use fentry::FEntry; pub use fexit::FExit; pub use kprobe::{KProbe, KProbeError}; +use libc::ENOSPC; pub use links::Link; use links::*; pub use lirc_mode2::LircMode2; @@ -100,6 +99,7 @@ pub use sk_skb::{SkSkb, SkSkbKind}; pub use sock_ops::SockOps; pub use socket_filter::{SocketFilter, SocketFilterError}; pub use tc::{SchedClassifier, TcAttachType, TcError}; +use thiserror::Error; pub use tp_btf::BtfTracePoint; pub use trace_point::{TracePoint, TracePointError}; pub use uprobe::{UProbe, UProbeError}; @@ -108,7 +108,7 @@ pub use xdp::{Xdp, XdpError, XdpFlags}; use crate::{ generated::{bpf_attach_type, bpf_link_info, bpf_prog_info, bpf_prog_type}, maps::MapError, - obj::{self, btf::BtfError, Function, VerifierLog}, + obj::{self, btf::BtfError, VerifierLog}, pin::PinError, programs::utils::{boot_time, get_fdinfo}, sys::{ @@ -117,7 +117,7 @@ use crate::{ bpf_prog_query, iter_link_ids, iter_prog_ids, retry_with_verifier_logs, BpfLoadProgramAttrs, SyscallError, }, - util::KernelVersion, + util::{bytes_of_bpf_name, KernelVersion}, VerifierLogLevel, }; @@ -218,9 +218,8 @@ pub enum ProgramError { 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 { + /// Creates a new instance that shares the same underlying file description as [`self`]. + pub fn try_clone(&self) -> io::Result { let Self(inner) = self; let inner = inner.try_clone()?; Ok(Self(inner)) @@ -292,90 +291,90 @@ impl Program { pub fn prog_type(&self) -> bpf_prog_type { use crate::generated::bpf_prog_type::*; match self { - Program::KProbe(_) => BPF_PROG_TYPE_KPROBE, - Program::UProbe(_) => BPF_PROG_TYPE_KPROBE, - Program::TracePoint(_) => BPF_PROG_TYPE_TRACEPOINT, - Program::SocketFilter(_) => BPF_PROG_TYPE_SOCKET_FILTER, - Program::Xdp(_) => BPF_PROG_TYPE_XDP, - Program::SkMsg(_) => BPF_PROG_TYPE_SK_MSG, - Program::SkSkb(_) => BPF_PROG_TYPE_SK_SKB, - Program::SockOps(_) => BPF_PROG_TYPE_SOCK_OPS, - Program::SchedClassifier(_) => BPF_PROG_TYPE_SCHED_CLS, - Program::CgroupSkb(_) => BPF_PROG_TYPE_CGROUP_SKB, - Program::CgroupSysctl(_) => BPF_PROG_TYPE_CGROUP_SYSCTL, - Program::CgroupSockopt(_) => BPF_PROG_TYPE_CGROUP_SOCKOPT, - Program::LircMode2(_) => BPF_PROG_TYPE_LIRC_MODE2, - Program::PerfEvent(_) => BPF_PROG_TYPE_PERF_EVENT, - Program::RawTracePoint(_) => BPF_PROG_TYPE_RAW_TRACEPOINT, - Program::Lsm(_) => BPF_PROG_TYPE_LSM, - Program::BtfTracePoint(_) => BPF_PROG_TYPE_TRACING, - Program::FEntry(_) => BPF_PROG_TYPE_TRACING, - Program::FExit(_) => BPF_PROG_TYPE_TRACING, - Program::Extension(_) => BPF_PROG_TYPE_EXT, - Program::CgroupSockAddr(_) => BPF_PROG_TYPE_CGROUP_SOCK_ADDR, - Program::SkLookup(_) => BPF_PROG_TYPE_SK_LOOKUP, - Program::CgroupSock(_) => BPF_PROG_TYPE_CGROUP_SOCK, - Program::CgroupDevice(_) => BPF_PROG_TYPE_CGROUP_DEVICE, + Self::KProbe(_) => BPF_PROG_TYPE_KPROBE, + Self::UProbe(_) => BPF_PROG_TYPE_KPROBE, + Self::TracePoint(_) => BPF_PROG_TYPE_TRACEPOINT, + Self::SocketFilter(_) => BPF_PROG_TYPE_SOCKET_FILTER, + Self::Xdp(_) => BPF_PROG_TYPE_XDP, + Self::SkMsg(_) => BPF_PROG_TYPE_SK_MSG, + Self::SkSkb(_) => BPF_PROG_TYPE_SK_SKB, + Self::SockOps(_) => BPF_PROG_TYPE_SOCK_OPS, + Self::SchedClassifier(_) => BPF_PROG_TYPE_SCHED_CLS, + Self::CgroupSkb(_) => BPF_PROG_TYPE_CGROUP_SKB, + Self::CgroupSysctl(_) => BPF_PROG_TYPE_CGROUP_SYSCTL, + Self::CgroupSockopt(_) => BPF_PROG_TYPE_CGROUP_SOCKOPT, + Self::LircMode2(_) => BPF_PROG_TYPE_LIRC_MODE2, + Self::PerfEvent(_) => BPF_PROG_TYPE_PERF_EVENT, + Self::RawTracePoint(_) => BPF_PROG_TYPE_RAW_TRACEPOINT, + Self::Lsm(_) => BPF_PROG_TYPE_LSM, + Self::BtfTracePoint(_) => BPF_PROG_TYPE_TRACING, + Self::FEntry(_) => BPF_PROG_TYPE_TRACING, + Self::FExit(_) => BPF_PROG_TYPE_TRACING, + Self::Extension(_) => BPF_PROG_TYPE_EXT, + Self::CgroupSockAddr(_) => BPF_PROG_TYPE_CGROUP_SOCK_ADDR, + Self::SkLookup(_) => BPF_PROG_TYPE_SK_LOOKUP, + Self::CgroupSock(_) => BPF_PROG_TYPE_CGROUP_SOCK, + Self::CgroupDevice(_) => BPF_PROG_TYPE_CGROUP_DEVICE, } } /// Pin the program to the provided path pub fn pin>(&mut self, path: P) -> Result<(), PinError> { match self { - Program::KProbe(p) => p.pin(path), - Program::UProbe(p) => p.pin(path), - Program::TracePoint(p) => p.pin(path), - Program::SocketFilter(p) => p.pin(path), - Program::Xdp(p) => p.pin(path), - Program::SkMsg(p) => p.pin(path), - Program::SkSkb(p) => p.pin(path), - Program::SockOps(p) => p.pin(path), - Program::SchedClassifier(p) => p.pin(path), - Program::CgroupSkb(p) => p.pin(path), - Program::CgroupSysctl(p) => p.pin(path), - Program::CgroupSockopt(p) => p.pin(path), - Program::LircMode2(p) => p.pin(path), - Program::PerfEvent(p) => p.pin(path), - Program::RawTracePoint(p) => p.pin(path), - Program::Lsm(p) => p.pin(path), - Program::BtfTracePoint(p) => p.pin(path), - Program::FEntry(p) => p.pin(path), - Program::FExit(p) => p.pin(path), - Program::Extension(p) => p.pin(path), - Program::CgroupSockAddr(p) => p.pin(path), - Program::SkLookup(p) => p.pin(path), - Program::CgroupSock(p) => p.pin(path), - Program::CgroupDevice(p) => p.pin(path), + Self::KProbe(p) => p.pin(path), + Self::UProbe(p) => p.pin(path), + Self::TracePoint(p) => p.pin(path), + Self::SocketFilter(p) => p.pin(path), + Self::Xdp(p) => p.pin(path), + Self::SkMsg(p) => p.pin(path), + Self::SkSkb(p) => p.pin(path), + Self::SockOps(p) => p.pin(path), + Self::SchedClassifier(p) => p.pin(path), + Self::CgroupSkb(p) => p.pin(path), + Self::CgroupSysctl(p) => p.pin(path), + Self::CgroupSockopt(p) => p.pin(path), + Self::LircMode2(p) => p.pin(path), + Self::PerfEvent(p) => p.pin(path), + Self::RawTracePoint(p) => p.pin(path), + Self::Lsm(p) => p.pin(path), + Self::BtfTracePoint(p) => p.pin(path), + Self::FEntry(p) => p.pin(path), + Self::FExit(p) => p.pin(path), + Self::Extension(p) => p.pin(path), + Self::CgroupSockAddr(p) => p.pin(path), + Self::SkLookup(p) => p.pin(path), + Self::CgroupSock(p) => p.pin(path), + Self::CgroupDevice(p) => p.pin(path), } } /// Unloads the program from the kernel. pub fn unload(self) -> Result<(), ProgramError> { match self { - Program::KProbe(mut p) => p.unload(), - Program::UProbe(mut p) => p.unload(), - Program::TracePoint(mut p) => p.unload(), - Program::SocketFilter(mut p) => p.unload(), - Program::Xdp(mut p) => p.unload(), - Program::SkMsg(mut p) => p.unload(), - Program::SkSkb(mut p) => p.unload(), - Program::SockOps(mut p) => p.unload(), - Program::SchedClassifier(mut p) => p.unload(), - Program::CgroupSkb(mut p) => p.unload(), - Program::CgroupSysctl(mut p) => p.unload(), - Program::CgroupSockopt(mut p) => p.unload(), - Program::LircMode2(mut p) => p.unload(), - Program::PerfEvent(mut p) => p.unload(), - Program::RawTracePoint(mut p) => p.unload(), - Program::Lsm(mut p) => p.unload(), - Program::BtfTracePoint(mut p) => p.unload(), - Program::FEntry(mut p) => p.unload(), - Program::FExit(mut p) => p.unload(), - Program::Extension(mut p) => p.unload(), - Program::CgroupSockAddr(mut p) => p.unload(), - Program::SkLookup(mut p) => p.unload(), - Program::CgroupSock(mut p) => p.unload(), - Program::CgroupDevice(mut p) => p.unload(), + Self::KProbe(mut p) => p.unload(), + Self::UProbe(mut p) => p.unload(), + Self::TracePoint(mut p) => p.unload(), + Self::SocketFilter(mut p) => p.unload(), + Self::Xdp(mut p) => p.unload(), + Self::SkMsg(mut p) => p.unload(), + Self::SkSkb(mut p) => p.unload(), + Self::SockOps(mut p) => p.unload(), + Self::SchedClassifier(mut p) => p.unload(), + Self::CgroupSkb(mut p) => p.unload(), + Self::CgroupSysctl(mut p) => p.unload(), + Self::CgroupSockopt(mut p) => p.unload(), + Self::LircMode2(mut p) => p.unload(), + Self::PerfEvent(mut p) => p.unload(), + Self::RawTracePoint(mut p) => p.unload(), + Self::Lsm(mut p) => p.unload(), + Self::BtfTracePoint(mut p) => p.unload(), + Self::FEntry(mut p) => p.unload(), + Self::FExit(mut p) => p.unload(), + Self::Extension(mut p) => p.unload(), + Self::CgroupSockAddr(mut p) => p.unload(), + Self::SkLookup(mut p) => p.unload(), + Self::CgroupSock(mut p) => p.unload(), + Self::CgroupDevice(mut p) => p.unload(), } } @@ -384,30 +383,63 @@ impl Program { /// Can be used to add a program to a [`crate::maps::ProgramArray`] or attach an [`Extension`] program. pub fn fd(&self) -> Result<&ProgramFd, ProgramError> { match self { - Program::KProbe(p) => p.fd(), - Program::UProbe(p) => p.fd(), - Program::TracePoint(p) => p.fd(), - Program::SocketFilter(p) => p.fd(), - Program::Xdp(p) => p.fd(), - Program::SkMsg(p) => p.fd(), - Program::SkSkb(p) => p.fd(), - Program::SockOps(p) => p.fd(), - Program::SchedClassifier(p) => p.fd(), - Program::CgroupSkb(p) => p.fd(), - Program::CgroupSysctl(p) => p.fd(), - Program::CgroupSockopt(p) => p.fd(), - Program::LircMode2(p) => p.fd(), - Program::PerfEvent(p) => p.fd(), - Program::RawTracePoint(p) => p.fd(), - Program::Lsm(p) => p.fd(), - Program::BtfTracePoint(p) => p.fd(), - Program::FEntry(p) => p.fd(), - Program::FExit(p) => p.fd(), - Program::Extension(p) => p.fd(), - Program::CgroupSockAddr(p) => p.fd(), - Program::SkLookup(p) => p.fd(), - Program::CgroupSock(p) => p.fd(), - Program::CgroupDevice(p) => p.fd(), + Self::KProbe(p) => p.fd(), + Self::UProbe(p) => p.fd(), + Self::TracePoint(p) => p.fd(), + Self::SocketFilter(p) => p.fd(), + Self::Xdp(p) => p.fd(), + Self::SkMsg(p) => p.fd(), + Self::SkSkb(p) => p.fd(), + Self::SockOps(p) => p.fd(), + Self::SchedClassifier(p) => p.fd(), + Self::CgroupSkb(p) => p.fd(), + Self::CgroupSysctl(p) => p.fd(), + Self::CgroupSockopt(p) => p.fd(), + Self::LircMode2(p) => p.fd(), + Self::PerfEvent(p) => p.fd(), + Self::RawTracePoint(p) => p.fd(), + Self::Lsm(p) => p.fd(), + Self::BtfTracePoint(p) => p.fd(), + Self::FEntry(p) => p.fd(), + Self::FExit(p) => p.fd(), + Self::Extension(p) => p.fd(), + Self::CgroupSockAddr(p) => p.fd(), + Self::SkLookup(p) => p.fd(), + Self::CgroupSock(p) => p.fd(), + Self::CgroupDevice(p) => p.fd(), + } + } + + /// 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 get kernel details for a given [`Program`]. + pub fn info(&self) -> Result { + match self { + Self::KProbe(p) => p.info(), + Self::UProbe(p) => p.info(), + Self::TracePoint(p) => p.info(), + Self::SocketFilter(p) => p.info(), + Self::Xdp(p) => p.info(), + Self::SkMsg(p) => p.info(), + Self::SkSkb(p) => p.info(), + Self::SockOps(p) => p.info(), + Self::SchedClassifier(p) => p.info(), + Self::CgroupSkb(p) => p.info(), + Self::CgroupSysctl(p) => p.info(), + Self::CgroupSockopt(p) => p.info(), + Self::LircMode2(p) => p.info(), + Self::PerfEvent(p) => p.info(), + Self::RawTracePoint(p) => p.info(), + Self::Lsm(p) => p.info(), + Self::BtfTracePoint(p) => p.info(), + Self::FEntry(p) => p.info(), + Self::FExit(p) => p.info(), + Self::Extension(p) => p.info(), + Self::CgroupSockAddr(p) => p.info(), + Self::SkLookup(p) => p.info(), + Self::CgroupSock(p) => p.info(), + Self::CgroupDevice(p) => p.info(), } } } @@ -434,8 +466,8 @@ impl ProgramData { obj: (obj::Program, obj::Function), btf_fd: Option>, verifier_log_level: VerifierLogLevel, - ) -> ProgramData { - ProgramData { + ) -> Self { + Self { name, obj: Some(obj), fd: None, @@ -457,7 +489,7 @@ impl ProgramData { path: &Path, info: bpf_prog_info, verifier_log_level: VerifierLogLevel, - ) -> Result, ProgramError> { + ) -> Result { let attach_btf_id = if info.attach_btf_id > 0 { Some(info.attach_btf_id) } else { @@ -467,7 +499,7 @@ impl ProgramData { .then(|| bpf_btf_get_fd_by_id(info.attach_btf_obj_id)) .transpose()?; - Ok(ProgramData { + Ok(Self { name, obj: None, fd: Some(ProgramFd(fd)), @@ -486,10 +518,11 @@ impl ProgramData { pub(crate) fn from_pinned_path>( path: P, verifier_log_level: VerifierLogLevel, - ) -> Result, ProgramError> { - let path_string = - CString::new(path.as_ref().as_os_str().to_string_lossy().as_bytes()).unwrap(); + ) -> Result { + use std::os::unix::ffi::OsStrExt as _; + // TODO: avoid this unwrap by adding a new error variant. + let path_string = CString::new(path.as_ref().as_os_str().as_bytes()).unwrap(); let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError { call: "bpf_obj_get", io_error, @@ -497,7 +530,7 @@ impl ProgramData { 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) + Self::from_bpf_prog_info(name, fd, path.as_ref(), info.0, verifier_log_level) } } @@ -520,6 +553,8 @@ fn unload_program(data: &mut ProgramData) -> Result<(), ProgramError } fn pin_program>(data: &ProgramData, path: P) -> Result<(), PinError> { + use std::os::unix::ffi::OsStrExt as _; + let fd = data.fd.as_ref().ok_or(PinError::NoFd { name: data .name @@ -527,12 +562,13 @@ fn pin_program>(data: &ProgramData, path: P) -> Resul .unwrap_or("") .to_string(), })?; - let path_string = CString::new(path.as_ref().to_string_lossy().into_owned()).map_err(|e| { - PinError::InvalidPinPath { - error: e.to_string(), - } - })?; - bpf_pin_object(fd.as_fd().as_raw_fd(), &path_string).map_err(|(_, io_error)| SyscallError { + let path = path.as_ref(); + let path_string = + CString::new(path.as_os_str().as_bytes()).map_err(|error| PinError::InvalidPinPath { + path: path.into(), + error, + })?; + bpf_pin_object(fd.as_fd(), &path_string).map_err(|(_, io_error)| SyscallError { call: "BPF_OBJ_PIN", io_error, })?; @@ -571,7 +607,7 @@ fn load_program( kernel_version, .. }, - Function { + obj::Function { instructions, func_info, line_info, @@ -581,14 +617,8 @@ fn load_program( }, ) = obj; - let target_kernel_version = kernel_version.unwrap_or_else(|| { - let KernelVersion { - major, - minor, - patch, - } = KernelVersion::current().unwrap(); - (u32::from(major) << 16) + (u32::from(minor) << 8) + u32::from(patch) - }); + let target_kernel_version = + kernel_version.unwrap_or_else(|| KernelVersion::current().unwrap().code()); let prog_name = if let Some(name) = name { let mut name = name.clone(); @@ -636,8 +666,8 @@ fn load_program( } } -pub(crate) fn query( - target_fd: T, +pub(crate) fn query( + target_fd: BorrowedFd<'_>, attach_type: bpf_attach_type, query_flags: u32, attach_flags: &mut Option, @@ -649,7 +679,7 @@ pub(crate) fn query( loop { match bpf_prog_query( - target_fd.as_raw_fd(), + target_fd.as_fd().as_raw_fd(), attach_type, query_flags, attach_flags.as_mut(), @@ -843,7 +873,6 @@ macro_rules! impl_from_pin { impl_from_pin!( TracePoint, SocketFilter, - Xdp, SkMsg, CgroupSysctl, LircMode2, @@ -919,12 +948,12 @@ impl_try_from_program!( /// 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 { +macro_rules! impl_info { ($($struct_name:ident),+ $(,)?) => { $( impl $struct_name { /// Returns the file descriptor of this Program. - pub fn program_info(&self) -> Result { + pub fn info(&self) -> Result { let ProgramFd(fd) = self.fd()?; ProgramInfo::new_from_fd(fd.as_fd()) @@ -934,7 +963,7 @@ macro_rules! impl_program_info { } } -impl_program_info!( +impl_info!( KProbe, UProbe, TracePoint, @@ -973,17 +1002,7 @@ impl ProgramInfo { /// 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 - .0 - .name - .iter() - .rposition(|ch| *ch != 0) - .map(|pos| pos + 1) - .unwrap_or(0); - - // The name field is defined as [std::os::raw::c_char; 16]. c_char may be signed or - // unsigned depending on the platform; that's why we're using from_raw_parts here - unsafe { std::slice::from_raw_parts(self.0.name.as_ptr() as *const _, length) } + bytes_of_bpf_name(&self.0.name) } /// The name of the program as a &str. If the name was not valid unicode, None is returned. @@ -1072,15 +1091,18 @@ impl ProgramInfo { } /// Loads a program from a pinned path in bpffs. - pub fn from_pin>(path: P) -> Result { - let path_string = CString::new(path.as_ref().to_str().unwrap()).unwrap(); + pub fn from_pin>(path: P) -> Result { + use std::os::unix::ffi::OsStrExt as _; + + // TODO: avoid this unwrap by adding a new error variant. + let path_string = CString::new(path.as_ref().as_os_str().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_fd(), &mut [])?; - Ok(ProgramInfo(info)) + Ok(Self(info)) } } diff --git a/aya/src/programs/perf_attach.rs b/aya/src/programs/perf_attach.rs index e9be37d5..8cf04871 100644 --- a/aya/src/programs/perf_attach.rs +++ b/aya/src/programs/perf_attach.rs @@ -1,5 +1,5 @@ //! Perf attach links. -use std::os::fd::{AsFd as _, AsRawFd as _, OwnedFd, RawFd}; +use std::os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, OwnedFd, RawFd}; use crate::{ generated::bpf_attach_type::BPF_PERF_EVENT, @@ -7,7 +7,7 @@ use crate::{ probe::{detach_debug_fs, ProbeEvent}, FdLink, Link, ProgramError, }, - sys::{bpf_link_create, perf_event_ioctl, SysResult, SyscallError}, + sys::{bpf_link_create, perf_event_ioctl, LinkTarget, SysResult, SyscallError}, FEATURES, PERF_EVENT_IOC_DISABLE, PERF_EVENT_IOC_ENABLE, PERF_EVENT_IOC_SET_BPF, }; @@ -28,15 +28,15 @@ impl Link for PerfLinkInner { fn id(&self) -> Self::Id { match self { - PerfLinkInner::FdLink(link) => PerfLinkIdInner::FdLinkId(link.id()), - PerfLinkInner::PerfLink(link) => PerfLinkIdInner::PerfLinkId(link.id()), + Self::FdLink(link) => PerfLinkIdInner::FdLinkId(link.id()), + Self::PerfLink(link) => PerfLinkIdInner::PerfLinkId(link.id()), } } fn detach(self) -> Result<(), ProgramError> { match self { - PerfLinkInner::FdLink(link) => link.detach(), - PerfLinkInner::PerfLink(link) => link.detach(), + Self::FdLink(link) => link.detach(), + Self::PerfLink(link) => link.detach(), } } } @@ -70,14 +70,16 @@ impl Link for PerfLink { } } -pub(crate) fn perf_attach(prog_fd: RawFd, fd: OwnedFd) -> Result { +pub(crate) fn perf_attach( + prog_fd: BorrowedFd<'_>, + fd: OwnedFd, +) -> Result { if FEATURES.bpf_perf_link() { - let link_fd = bpf_link_create(prog_fd, fd.as_raw_fd(), BPF_PERF_EVENT, None, 0).map_err( - |(_, io_error)| SyscallError { + let link_fd = bpf_link_create(prog_fd, LinkTarget::Fd(fd.as_fd()), BPF_PERF_EVENT, None, 0) + .map_err(|(_, io_error)| SyscallError { call: "bpf_link_create", io_error, - }, - )?; + })?; Ok(PerfLinkInner::FdLink(FdLink::new(link_fd))) } else { perf_attach_either(prog_fd, fd, None) @@ -85,7 +87,7 @@ pub(crate) fn perf_attach(prog_fd: RawFd, fd: OwnedFd) -> Result, fd: OwnedFd, event: ProbeEvent, ) -> Result { @@ -93,16 +95,16 @@ pub(crate) fn perf_attach_debugfs( } fn perf_attach_either( - prog_fd: RawFd, + prog_fd: BorrowedFd<'_>, fd: OwnedFd, event: Option, ) -> Result { - perf_event_ioctl(fd.as_fd(), PERF_EVENT_IOC_SET_BPF, prog_fd).map_err(|(_, io_error)| { - SyscallError { + perf_event_ioctl(fd.as_fd(), PERF_EVENT_IOC_SET_BPF, prog_fd.as_raw_fd()).map_err( + |(_, io_error)| SyscallError { call: "PERF_EVENT_IOC_SET_BPF", io_error, - } - })?; + }, + )?; perf_event_ioctl(fd.as_fd(), PERF_EVENT_IOC_ENABLE, 0).map_err(|(_, io_error)| { SyscallError { call: "PERF_EVENT_IOC_ENABLE", diff --git a/aya/src/programs/perf_event.rs b/aya/src/programs/perf_event.rs index bb60f082..b7b233cf 100644 --- a/aya/src/programs/perf_event.rs +++ b/aya/src/programs/perf_event.rs @@ -1,11 +1,10 @@ //! Perf event programs. -use std::os::fd::{AsFd as _, AsRawFd as _}; +use std::os::fd::AsFd as _; pub use crate::generated::{ perf_hw_cache_id, perf_hw_cache_op_id, perf_hw_cache_op_result_id, perf_hw_id, perf_sw_ids, }; - use crate::{ generated::{ bpf_link_type, @@ -148,7 +147,6 @@ impl PerfEvent { ) -> 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)), @@ -213,7 +211,7 @@ impl TryFrom for PerfEventLink { fn try_from(fd_link: FdLink) -> Result { let info = bpf_link_get_info_by_fd(fd_link.fd.as_fd())?; if info.type_ == (bpf_link_type::BPF_LINK_TYPE_PERF_EVENT as u32) { - return Ok(PerfEventLink::new(PerfLinkInner::FdLink(fd_link))); + return Ok(Self::new(PerfLinkInner::FdLink(fd_link))); } Err(LinkError::InvalidLink) } diff --git a/aya/src/programs/probe.rs b/aya/src/programs/probe.rs index 151c87ef..f36c8cf9 100644 --- a/aya/src/programs/probe.rs +++ b/aya/src/programs/probe.rs @@ -1,14 +1,16 @@ -use crate::util::KernelVersion; -use libc::pid_t; use std::{ + ffi::{OsStr, OsString}, + fmt::Write as _, fs::{self, OpenOptions}, io::{self, Write}, - os::fd::{AsFd as _, AsRawFd as _, OwnedFd}, - path::Path, + os::fd::{AsFd as _, OwnedFd}, + path::{Path, PathBuf}, process, sync::atomic::{AtomicUsize, Ordering}, }; +use libc::pid_t; + use crate::{ programs::{ kprobe::KProbeError, perf_attach, perf_attach::PerfLinkInner, perf_attach_debugfs, @@ -16,6 +18,7 @@ use crate::{ Link, ProgramData, ProgramError, }, sys::{perf_event_open_probe, perf_event_open_trace_point, SyscallError}, + util::KernelVersion, }; static PROBE_NAME_INDEX: AtomicUsize = AtomicUsize::new(0); @@ -36,22 +39,76 @@ pub enum ProbeKind { impl ProbeKind { fn pmu(&self) -> &'static str { match *self { - ProbeKind::KProbe | ProbeKind::KRetProbe => "kprobe", - ProbeKind::UProbe | ProbeKind::URetProbe => "uprobe", + Self::KProbe | Self::KRetProbe => "kprobe", + Self::UProbe | Self::URetProbe => "uprobe", + } + } +} + +pub(crate) fn lines(bytes: &[u8]) -> impl Iterator { + use std::os::unix::ffi::OsStrExt as _; + + bytes.as_ref().split(|b| b == &b'\n').map(|mut line| { + while let [stripped @ .., c] = line { + if c.is_ascii_whitespace() { + line = stripped; + continue; + } + break; } + OsStr::from_bytes(line) + }) +} + +pub(crate) trait OsStringExt { + fn starts_with(&self, needle: &OsStr) -> bool; + fn ends_with(&self, needle: &OsStr) -> bool; + fn strip_prefix(&self, prefix: &OsStr) -> Option<&OsStr>; + fn strip_suffix(&self, suffix: &OsStr) -> Option<&OsStr>; +} + +impl OsStringExt for OsStr { + fn starts_with(&self, needle: &OsStr) -> bool { + use std::os::unix::ffi::OsStrExt as _; + self.as_bytes().starts_with(needle.as_bytes()) + } + + fn ends_with(&self, needle: &OsStr) -> bool { + use std::os::unix::ffi::OsStrExt as _; + self.as_bytes().ends_with(needle.as_bytes()) + } + + fn strip_prefix(&self, prefix: &OsStr) -> Option<&OsStr> { + use std::os::unix::ffi::OsStrExt as _; + self.as_bytes() + .strip_prefix(prefix.as_bytes()) + .map(Self::from_bytes) + } + + fn strip_suffix(&self, suffix: &OsStr) -> Option<&OsStr> { + use std::os::unix::ffi::OsStrExt as _; + self.as_bytes() + .strip_suffix(suffix.as_bytes()) + .map(Self::from_bytes) } } #[derive(Debug)] pub(crate) struct ProbeEvent { kind: ProbeKind, - event_alias: String, + event_alias: OsString, } pub(crate) fn attach>( program_data: &mut ProgramData, kind: ProbeKind, - fn_name: &str, + // NB: the meaning of this argument is different for kprobe/kretprobe and uprobe/uretprobe; in + // the kprobe case it is the name of the function to attach to, in the uprobe case it is a path + // to the binary or library. + // + // TODO: consider encoding the type and the argument in the [`ProbeKind`] enum instead of a + // separate argument. + fn_name: &OsStr, offset: u64, pid: Option, ) -> Result { @@ -59,7 +116,6 @@ pub(crate) fn attach>( // Use debugfs to create probe 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)?; perf_attach_debugfs(prog_fd, fd, ProbeEvent { kind, event_alias }) @@ -90,7 +146,7 @@ pub(crate) fn detach_debug_fs(event: ProbeEvent) -> Result<(), ProgramError> { fn create_as_probe( kind: ProbeKind, - fn_name: &str, + fn_name: &OsStr, offset: u64, pid: Option, ) -> Result { @@ -126,10 +182,10 @@ fn create_as_probe( fn create_as_trace_point( kind: ProbeKind, - name: &str, + name: &OsStr, offset: u64, pid: Option, -) -> Result<(OwnedFd, String), ProgramError> { +) -> Result<(OwnedFd, OsString), ProgramError> { use ProbeKind::*; let tracefs = find_tracefs_path()?; @@ -142,7 +198,7 @@ fn create_as_trace_point( }; let category = format!("{}s", kind.pmu()); - let tpid = read_sys_fs_trace_point_id(tracefs, &category, &event_alias)?; + let tpid = read_sys_fs_trace_point_id(tracefs, &category, event_alias.as_ref())?; let fd = perf_event_open_trace_point(tpid, pid).map_err(|(_code, io_error)| SyscallError { call: "perf_event_open", io_error, @@ -154,9 +210,11 @@ fn create_as_trace_point( fn create_probe_event( tracefs: &Path, kind: ProbeKind, - fn_name: &str, + fn_name: &OsStr, offset: u64, -) -> Result { +) -> Result { + use std::os::unix::ffi::OsStrExt as _; + use ProbeKind::*; let events_file_name = tracefs.join(format!("{}_events", kind.pmu())); @@ -165,93 +223,127 @@ fn create_probe_event( KRetProbe | URetProbe => 'r', }; - let fixed_fn_name = fn_name.replace(['.', '/', '-'], "_"); - - let event_alias = format!( - "aya_{}_{}_{}_{:#x}_{}", + let mut event_alias = OsString::new(); + write!( + &mut event_alias, + "aya_{}_{}_", process::id(), probe_type_prefix, - fixed_fn_name, + ) + .unwrap(); + for b in fn_name.as_bytes() { + let b = match *b { + b'.' | b'/' | b'-' => b'_', + b => b, + }; + event_alias.push(OsStr::from_bytes(&[b])); + } + write!( + &mut event_alias, + "_{:#x}_{}", offset, PROBE_NAME_INDEX.fetch_add(1, Ordering::AcqRel) - ); - let offset_suffix = match kind { - KProbe => format!("+{offset}"), - UProbe | URetProbe => format!(":{offset:#x}"), - _ => String::new(), + ) + .unwrap(); + + let mut probe = OsString::new(); + write!(&mut probe, "{}:{}s/", probe_type_prefix, kind.pmu(),).unwrap(); + probe.push(&event_alias); + probe.push(" "); + probe.push(fn_name); + match kind { + KProbe => write!(&mut probe, "+{offset}").unwrap(), + UProbe | URetProbe => write!(&mut probe, ":{offset:#x}").unwrap(), + _ => {} }; - let probe = format!( - "{}:{}s/{} {}{}\n", - probe_type_prefix, - kind.pmu(), - event_alias, - fn_name, - offset_suffix - ); + probe.push("\n"); - let mut events_file = OpenOptions::new() + OpenOptions::new() .append(true) .open(&events_file_name) - .map_err(|e| (events_file_name.display().to_string(), e))?; - - events_file - .write_all(probe.as_bytes()) - .map_err(|e| (events_file_name.display().to_string(), e))?; + .and_then(|mut events_file| events_file.write_all(probe.as_bytes())) + .map_err(|e| (events_file_name, e))?; Ok(event_alias) } -fn delete_probe_event(tracefs: &Path, event: ProbeEvent) -> Result<(), (String, io::Error)> { +fn delete_probe_event(tracefs: &Path, event: ProbeEvent) -> Result<(), (PathBuf, io::Error)> { + use std::os::unix::ffi::OsStrExt as _; + let ProbeEvent { kind, event_alias } = event; let events_file_name = tracefs.join(format!("{}_events", kind.pmu())); - let events = fs::read_to_string(&events_file_name) - .map_err(|e| (events_file_name.display().to_string(), e))?; - - let found = events.lines().any(|line| line.contains(&event_alias)); - - if found { - let mut events_file = OpenOptions::new() - .append(true) - .open(&events_file_name) - .map_err(|e| (events_file_name.display().to_string(), e))?; - - let rm = format!("-:{event_alias}\n"); - - events_file - .write_all(rm.as_bytes()) - .map_err(|e| (events_file_name.display().to_string(), e))?; - } - - Ok(()) + fs::read(&events_file_name) + .and_then(|events| { + let found = lines(&events).any(|line| { + let mut line = line.as_bytes(); + // See [`create_probe_event`] and the documentation: + // + // https://docs.kernel.org/trace/kprobetrace.html + // + // https://docs.kernel.org/trace/uprobetracer.html + loop { + match line.split_first() { + None => break false, + Some((b, rest)) => { + line = rest; + if *b == b'/' { + break line.starts_with(event_alias.as_bytes()); + } + } + } + } + }); + + if found { + OpenOptions::new() + .append(true) + .open(&events_file_name) + .and_then(|mut events_file| { + let mut rm = OsString::new(); + rm.push("-:"); + rm.push(event_alias); + rm.push("\n"); + + events_file.write_all(rm.as_bytes()) + }) + } else { + Ok(()) + } + }) + .map_err(|e| (events_file_name, e)) } -fn read_sys_fs_perf_type(pmu: &str) -> Result { - let file = format!("/sys/bus/event_source/devices/{pmu}/type"); - - let perf_ty = fs::read_to_string(&file).map_err(|e| (file.clone(), e))?; - let perf_ty = perf_ty - .trim() - .parse::() - .map_err(|e| (file, io::Error::new(io::ErrorKind::Other, e)))?; - - Ok(perf_ty) +fn read_sys_fs_perf_type(pmu: &str) -> Result { + let file = Path::new("/sys/bus/event_source/devices") + .join(pmu) + .join("type"); + + fs::read_to_string(&file) + .and_then(|perf_ty| { + perf_ty + .trim() + .parse::() + .map_err(|e| io::Error::new(io::ErrorKind::Other, e)) + }) + .map_err(|e| (file, e)) } -fn read_sys_fs_perf_ret_probe(pmu: &str) -> Result { - let file = format!("/sys/bus/event_source/devices/{pmu}/format/retprobe"); - - let data = fs::read_to_string(&file).map_err(|e| (file.clone(), e))?; - - let mut parts = data.trim().splitn(2, ':').skip(1); - let config = parts.next().ok_or_else(|| { - ( - file.clone(), - io::Error::new(io::ErrorKind::Other, "invalid format"), - ) - })?; - - config - .parse::() - .map_err(|e| (file, io::Error::new(io::ErrorKind::Other, e))) +fn read_sys_fs_perf_ret_probe(pmu: &str) -> Result { + let file = Path::new("/sys/bus/event_source/devices") + .join(pmu) + .join("format/retprobe"); + + fs::read_to_string(&file) + .and_then(|data| { + let mut parts = data.trim().splitn(2, ':').skip(1); + let config = parts + .next() + .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "invalid format"))?; + + config + .parse::() + .map_err(|e| io::Error::new(io::ErrorKind::Other, e)) + }) + .map_err(|e| (file, e)) } diff --git a/aya/src/programs/sk_lookup.rs b/aya/src/programs/sk_lookup.rs index bbcdc3a3..42feb33d 100644 --- a/aya/src/programs/sk_lookup.rs +++ b/aya/src/programs/sk_lookup.rs @@ -1,13 +1,12 @@ -use std::os::fd::{AsFd as _, AsRawFd}; +use std::os::fd::AsFd; +use super::links::FdLink; use crate::{ generated::{bpf_attach_type::BPF_SK_LOOKUP, bpf_prog_type::BPF_PROG_TYPE_SK_LOOKUP}, programs::{define_link_wrapper, load_program, FdLinkId, ProgramData, ProgramError}, - sys::{bpf_link_create, SyscallError}, + sys::{bpf_link_create, LinkTarget, SyscallError}, }; -use super::links::FdLink; - /// A program used to redirect incoming packets to a local socket. /// /// [`SkLookup`] programs are attached to network namespaces to provide programmable @@ -60,18 +59,16 @@ impl SkLookup { /// Attaches the program to the given network namespace. /// /// The returned value can be used to detach, see [SkLookup::detach]. - pub fn attach(&mut self, netns: T) -> Result { + pub fn attach(&mut self, netns: T) -> Result { 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 netns_fd = netns.as_fd(); - let link_fd = bpf_link_create(prog_fd, netns_fd, BPF_SK_LOOKUP, None, 0).map_err( - |(_, io_error)| SyscallError { + let link_fd = bpf_link_create(prog_fd, LinkTarget::Fd(netns_fd), BPF_SK_LOOKUP, None, 0) + .map_err(|(_, io_error)| SyscallError { call: "bpf_link_create", io_error, - }, - )?; + })?; self.data .links .insert(SkLookupLink::new(FdLink::new(link_fd))) diff --git a/aya/src/programs/sk_msg.rs b/aya/src/programs/sk_msg.rs index 7a03b8e3..f169447b 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::{AsFd as _, AsRawFd as _}; +use std::os::fd::AsFd as _; use crate::{ generated::{bpf_attach_type::BPF_SK_MSG_VERDICT, bpf_prog_type::BPF_PROG_TYPE_SK_MSG}, @@ -9,7 +9,6 @@ use crate::{ define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData, ProgramError, }, - sys::{bpf_prog_attach, SyscallError}, }; /// A program used to intercept messages sent with `sendmsg()`/`sendfile()`. @@ -44,11 +43,11 @@ use crate::{ /// use aya::programs::SkMsg; /// /// let intercept_egress: SockHash<_, u32> = bpf.map("INTERCEPT_EGRESS").unwrap().try_into()?; -/// let map_fd = intercept_egress.fd()?; +/// let map_fd = intercept_egress.fd().try_clone()?; /// /// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?; /// prog.load()?; -/// prog.attach(map_fd)?; +/// prog.attach(&map_fd)?; /// /// let mut client = TcpStream::connect("127.0.0.1:1234")?; /// let mut intercept_egress: SockHash<_, u32> = bpf.map_mut("INTERCEPT_EGRESS").unwrap().try_into()?; @@ -78,23 +77,12 @@ impl SkMsg { /// Attaches the program to the given sockmap. /// /// The returned value can be used to detach, see [SkMsg::detach]. - pub fn attach(&mut self, map: SockMapFd) -> Result { + pub fn attach(&mut self, map: &SockMapFd) -> Result { 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 link = ProgAttachLink::attach(prog_fd, map.as_fd(), BPF_SK_MSG_VERDICT)?; - bpf_prog_attach(prog_fd, map_fd, BPF_SK_MSG_VERDICT).map_err(|(_, io_error)| { - SyscallError { - call: "bpf_prog_attach", - io_error, - } - })?; - self.data.links.insert(SkMsgLink::new(ProgAttachLink::new( - prog_fd, - map_fd, - BPF_SK_MSG_VERDICT, - ))) + self.data.links.insert(SkMsgLink::new(link)) } /// Detaches the program from a sockmap. diff --git a/aya/src/programs/sk_skb.rs b/aya/src/programs/sk_skb.rs index a4c5de63..81bc9534 100644 --- a/aya/src/programs/sk_skb.rs +++ b/aya/src/programs/sk_skb.rs @@ -1,9 +1,6 @@ //! Skskb programs. -use std::{ - os::fd::{AsFd as _, AsRawFd as _}, - path::Path, -}; +use std::{os::fd::AsFd as _, path::Path}; use crate::{ generated::{ @@ -15,7 +12,6 @@ use crate::{ define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData, ProgramError, }, - sys::{bpf_prog_attach, SyscallError}, VerifierLogLevel, }; @@ -41,18 +37,29 @@ pub enum SkSkbKind { /// # Examples /// /// ```no_run +/// # #[derive(Debug, thiserror::Error)] +/// # enum Error { +/// # #[error(transparent)] +/// # IO(#[from] std::io::Error), +/// # #[error(transparent)] +/// # Map(#[from] aya::maps::MapError), +/// # #[error(transparent)] +/// # Program(#[from] aya::programs::ProgramError), +/// # #[error(transparent)] +/// # Bpf(#[from] aya::BpfError) +/// # } /// # let mut bpf = aya::Bpf::load(&[])?; /// use aya::maps::SockMap; /// use aya::programs::SkSkb; /// /// let intercept_ingress: SockMap<_> = bpf.map("INTERCEPT_INGRESS").unwrap().try_into()?; -/// let map_fd = intercept_ingress.fd()?; +/// let map_fd = intercept_ingress.fd().try_clone()?; /// /// let prog: &mut SkSkb = bpf.program_mut("intercept_ingress_packet").unwrap().try_into()?; /// prog.load()?; -/// prog.attach(map_fd)?; +/// prog.attach(&map_fd)?; /// -/// # Ok::<(), aya::BpfError>(()) +/// # Ok::<(), Error>(()) /// ``` /// /// [socket maps]: crate::maps::sock @@ -74,25 +81,18 @@ impl SkSkb { /// Attaches the program to the given socket map. /// /// The returned value can be used to detach, see [SkSkb::detach]. - pub fn attach(&mut self, map: SockMapFd) -> Result { + pub fn attach(&mut self, map: &SockMapFd) -> Result { 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 { SkSkbKind::StreamParser => BPF_SK_SKB_STREAM_PARSER, SkSkbKind::StreamVerdict => BPF_SK_SKB_STREAM_VERDICT, }; - bpf_prog_attach(prog_fd, map_fd, attach_type).map_err(|(_, io_error)| SyscallError { - call: "bpf_prog_attach", - io_error, - })?; - self.data.links.insert(SkSkbLink::new(ProgAttachLink::new( - prog_fd, - map_fd, - attach_type, - ))) + + let link = ProgAttachLink::attach(prog_fd, map.as_fd(), attach_type)?; + + self.data.links.insert(SkSkbLink::new(link)) } /// Detaches the program. diff --git a/aya/src/programs/sock_ops.rs b/aya/src/programs/sock_ops.rs index 2a469048..d8cb1383 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::{AsFd as _, AsRawFd}; +use std::os::fd::AsFd; use crate::{ generated::{bpf_attach_type::BPF_CGROUP_SOCK_OPS, bpf_prog_type::BPF_PROG_TYPE_SOCK_OPS}, @@ -7,7 +7,6 @@ use crate::{ define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData, ProgramError, }, - sys::{bpf_prog_attach, SyscallError}, }; /// A program used to work with sockets. @@ -58,23 +57,11 @@ impl SockOps { /// Attaches the program to the given cgroup. /// /// The returned value can be used to detach, see [SockOps::detach]. - pub fn attach(&mut self, cgroup: T) -> Result { + pub fn attach(&mut self, cgroup: T) -> Result { 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)| { - SyscallError { - call: "bpf_prog_attach", - io_error, - } - })?; - self.data.links.insert(SockOpsLink::new(ProgAttachLink::new( - prog_fd, - cgroup_fd, - BPF_CGROUP_SOCK_OPS, - ))) + let link = ProgAttachLink::attach(prog_fd.as_fd(), cgroup.as_fd(), BPF_CGROUP_SOCK_OPS)?; + self.data.links.insert(SockOpsLink::new(link)) } /// Detaches the program. diff --git a/aya/src/programs/socket_filter.rs b/aya/src/programs/socket_filter.rs index e737d8ae..abf6e7ed 100644 --- a/aya/src/programs/socket_filter.rs +++ b/aya/src/programs/socket_filter.rs @@ -1,9 +1,10 @@ //! Socket filter programs. -use libc::{setsockopt, SOL_SOCKET}; use std::{ io, mem, - os::fd::{AsFd as _, AsRawFd, RawFd}, + os::fd::{AsFd, AsRawFd, RawFd}, }; + +use libc::{setsockopt, SOL_SOCKET}; use thiserror::Error; use crate::{ @@ -48,13 +49,12 @@ pub enum SocketFilterError { /// # } /// # let mut bpf = aya::Bpf::load(&[])?; /// use std::net::TcpStream; -/// use std::os::fd::AsRawFd; /// use aya::programs::SocketFilter; /// /// let mut client = TcpStream::connect("127.0.0.1:1234")?; /// let prog: &mut SocketFilter = bpf.program_mut("filter_packets").unwrap().try_into()?; /// prog.load()?; -/// prog.attach(client.as_raw_fd())?; +/// prog.attach(&client)?; /// # Ok::<(), Error>(()) /// ``` #[derive(Debug)] @@ -72,10 +72,11 @@ impl SocketFilter { /// Attaches the filter on the given socket. /// /// The returned value can be used to detach from the socket, see [SocketFilter::detach]. - pub fn attach(&mut self, socket: T) -> Result { + pub fn attach(&mut self, socket: T) -> Result { let prog_fd = self.fd()?; let prog_fd = prog_fd.as_fd(); let prog_fd = prog_fd.as_raw_fd(); + let socket = socket.as_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 f0da530c..12c00043 100644 --- a/aya/src/programs/tc.rs +++ b/aya/src/programs/tc.rs @@ -1,13 +1,13 @@ //! Network traffic control programs. -use thiserror::Error; - use std::{ ffi::{CStr, CString}, io, - os::fd::{AsFd as _, AsRawFd as _}, + os::fd::AsFd as _, path::Path, }; +use thiserror::Error; + use crate::{ generated::{ bpf_prog_type::BPF_PROG_TYPE_SCHED_CLS, TC_H_CLSACT, TC_H_MIN_EGRESS, TC_H_MIN_INGRESS, @@ -74,7 +74,6 @@ pub enum TcAttachType { #[doc(alias = "BPF_PROG_TYPE_SCHED_CLS")] pub struct SchedClassifier { pub(crate) data: ProgramData, - pub(crate) name: Box, } /// Errors from TC programs @@ -95,9 +94,9 @@ pub enum TcError { impl TcAttachType { pub(crate) fn parent(&self) -> u32 { match self { - TcAttachType::Custom(parent) => *parent, - TcAttachType::Ingress => tc_handler_make(TC_H_CLSACT, TC_H_MIN_INGRESS), - TcAttachType::Egress => tc_handler_make(TC_H_CLSACT, TC_H_MIN_EGRESS), + Self::Custom(parent) => *parent, + Self::Ingress => tc_handler_make(TC_H_CLSACT, TC_H_MIN_INGRESS), + Self::Egress => tc_handler_make(TC_H_CLSACT, TC_H_MIN_EGRESS), } } } @@ -155,15 +154,17 @@ impl SchedClassifier { ) -> Result { 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 name = self.data.name.as_deref().unwrap_or_default(); + // TODO: avoid this unwrap by adding a new error variant. + let name = CString::new(name).unwrap(); let (priority, handle) = unsafe { netlink_qdisc_attach( if_index as i32, &attach_type, prog_fd, - &self.name, + &name, options.priority, options.handle, ) @@ -204,10 +205,7 @@ impl SchedClassifier { /// the program being unloaded from the kernel if it is still pinned. pub fn from_pin>(path: P) -> Result { let data = ProgramData::from_pinned_path(path, VerifierLogLevel::default())?; - let cname = CString::new(data.name.clone().unwrap_or_default()) - .unwrap() - .into_boxed_c_str(); - Ok(Self { data, name: cname }) + Ok(Self { data }) } } @@ -284,9 +282,9 @@ impl SchedClassifierLink { attach_type: TcAttachType, priority: u16, handle: u32, - ) -> Result { + ) -> Result { let if_index = ifindex_from_ifname(if_name)?; - Ok(SchedClassifierLink(Some(TcLink { + Ok(Self(Some(TcLink { if_index: if_index as i32, attach_type, priority, diff --git a/aya/src/programs/trace_point.rs b/aya/src/programs/trace_point.rs index 4c5d38db..2096f1cb 100644 --- a/aya/src/programs/trace_point.rs +++ b/aya/src/programs/trace_point.rs @@ -1,9 +1,6 @@ //! Tracepoint programs. -use std::{ - fs, io, - os::fd::{AsFd as _, AsRawFd as _}, - path::Path, -}; +use std::{fs, io, os::fd::AsFd as _, path::Path}; + use thiserror::Error; use crate::{ @@ -84,9 +81,8 @@ impl TracePoint { 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 id = read_sys_fs_trace_point_id(tracefs, category, name.as_ref())?; let fd = perf_event_open_trace_point(id, None).map_err(|(_code, io_error)| SyscallError { call: "perf_event_open_trace_point", @@ -140,7 +136,7 @@ impl TryFrom for TracePointLink { fn try_from(fd_link: FdLink) -> Result { let info = bpf_link_get_info_by_fd(fd_link.fd.as_fd())?; if info.type_ == (bpf_link_type::BPF_LINK_TYPE_TRACING as u32) { - return Ok(TracePointLink::new(PerfLinkInner::FdLink(fd_link))); + return Ok(Self::new(PerfLinkInner::FdLink(fd_link))); } Err(LinkError::InvalidLink) } @@ -149,7 +145,7 @@ impl TryFrom for TracePointLink { pub(crate) fn read_sys_fs_trace_point_id( tracefs: &Path, category: &str, - name: &str, + name: &Path, ) -> Result { let file = tracefs.join("events").join(category).join(name).join("id"); diff --git a/aya/src/programs/uprobe.rs b/aya/src/programs/uprobe.rs index e40bada2..1c0a0ce0 100644 --- a/aya/src/programs/uprobe.rs +++ b/aya/src/programs/uprobe.rs @@ -1,10 +1,8 @@ //! User space probes. -use libc::pid_t; -use object::{Object, ObjectSection, ObjectSymbol}; use std::{ borrow::Cow, error::Error, - ffi::CStr, + ffi::{CStr, OsStr, OsString}, fs, io::{self, BufRead, Cursor, Read}, mem, @@ -12,6 +10,9 @@ use std::{ path::{Path, PathBuf}, sync::Arc, }; + +use libc::pid_t; +use object::{Object, ObjectSection, ObjectSymbol}; use thiserror::Error; use crate::{ @@ -19,7 +20,7 @@ use crate::{ programs::{ define_link_wrapper, load_program, perf_attach::{PerfLinkIdInner, PerfLinkInner}, - probe::{attach, ProbeKind}, + probe::{attach, OsStringExt as _, ProbeKind}, FdLink, LinkError, ProgramData, ProgramError, }, sys::bpf_link_get_info_by_fd, @@ -28,7 +29,7 @@ use crate::{ const LD_SO_CACHE_FILE: &str = "/etc/ld.so.cache"; -lazy_static! { +lazy_static::lazy_static! { static ref LD_SO_CACHE: Result> = LdSoCache::load(LD_SO_CACHE_FILE).map_err(Arc::new); } @@ -83,7 +84,7 @@ impl UProbe { target: T, pid: Option, ) -> Result { - let path = resolve_attach_path(&target, pid)?; + let path = resolve_attach_path(target.as_ref(), pid)?; let sym_offset = if let Some(fn_name) = fn_name { resolve_symbol(&path, fn_name).map_err(|error| UProbeError::SymbolError { @@ -94,7 +95,8 @@ impl UProbe { 0 }; - attach(&mut self.data, self.kind, &path, sym_offset + offset, pid) + let fn_name = path.as_os_str(); + attach(&mut self.data, self.kind, fn_name, sym_offset + offset, pid) } /// Detaches the program. @@ -124,37 +126,33 @@ impl UProbe { } } -fn resolve_attach_path>( - target: &T, - pid: Option, -) -> Result, UProbeError> { +fn resolve_attach_path(target: &Path, pid: Option) -> Result, UProbeError> { // Look up the path for the target. If it there is a pid, and the target is a library name // that is in the process's memory map, use the path of that library. Otherwise, use the target as-is. - let target = target.as_ref(); - let invalid_target = || UProbeError::InvalidTarget { - path: target.to_owned(), - }; - let target_str = target.to_str().ok_or_else(invalid_target)?; pid.and_then(|pid| { - find_lib_in_proc_maps(pid, target_str) + find_lib_in_proc_maps(pid, target) .map_err(|io_error| UProbeError::FileError { - filename: format!("/proc/{pid}/maps"), + filename: Path::new("/proc").join(pid.to_string()).join("maps"), io_error, }) .map(|v| v.map(Cow::Owned)) .transpose() }) - .or_else(|| target.is_absolute().then(|| Ok(Cow::Borrowed(target_str)))) + .or_else(|| target.is_absolute().then(|| Ok(Cow::Borrowed(target)))) .or_else(|| { LD_SO_CACHE .as_ref() .map_err(|error| UProbeError::InvalidLdSoCache { io_error: error.clone(), }) - .map(|cache| cache.resolve(target_str).map(Cow::Borrowed)) + .map(|cache| cache.resolve(target).map(Cow::Borrowed)) .transpose() }) - .unwrap_or_else(|| Err(invalid_target())) + .unwrap_or_else(|| { + Err(UProbeError::InvalidTarget { + path: target.to_owned(), + }) + }) } // Only run this test on linux with glibc because only in that configuration do we know that we'll @@ -171,7 +169,8 @@ fn test_resolve_attach_path() { // Now let's resolve the path to libc. It should exist in the current process's memory map and // then in the ld.so.cache. - let libc_path = resolve_attach_path(&"libc", Some(pid)).unwrap(); + let libc_path = resolve_attach_path("libc".as_ref(), Some(pid)).unwrap(); + let libc_path = libc_path.to_str().unwrap(); // Make sure we got a path that contains libc. assert!(libc_path.contains("libc"), "libc_path: {}", libc_path); @@ -204,7 +203,7 @@ impl TryFrom for UProbeLink { fn try_from(fd_link: FdLink) -> Result { let info = bpf_link_get_info_by_fd(fd_link.fd.as_fd())?; if info.type_ == (bpf_link_type::BPF_LINK_TYPE_TRACING as u32) { - return Ok(UProbeLink::new(PerfLinkInner::FdLink(fd_link))); + return Ok(Self::new(PerfLinkInner::FdLink(fd_link))); } Err(LinkError::InvalidLink) } @@ -242,52 +241,60 @@ pub enum UProbeError { #[error("`{filename}`")] FileError { /// The file name - filename: String, + filename: PathBuf, /// The [`io::Error`] returned from the file operation #[source] io_error: io::Error, }, } -fn proc_maps_libs(pid: pid_t) -> Result, io::Error> { +fn proc_maps_libs(pid: pid_t) -> Result, io::Error> { + use std::os::unix::ffi::OsStrExt as _; + let maps_file = format!("/proc/{pid}/maps"); - let data = fs::read_to_string(maps_file)?; - - Ok(data - .lines() - .filter_map(|line| { - let line = line.split_whitespace().last()?; - if line.starts_with('/') { - let path = PathBuf::from(line); - let key = path.file_name().unwrap().to_string_lossy().into_owned(); - Some((key, path.to_string_lossy().to_string())) - } else { - None + let data = fs::read(maps_file)?; + + let libs = data + .split(|b| b == &b'\n') + .filter_map(|mut line| { + while let [stripped @ .., c] = line { + if c.is_ascii_whitespace() { + line = stripped; + continue; + } + break; } + let path = line.split(|b| b.is_ascii_whitespace()).last()?; + let path = Path::new(OsStr::from_bytes(path)); + path.is_absolute() + .then(|| { + path.file_name() + .map(|file_name| (file_name.to_owned(), path.to_owned())) + }) + .flatten() }) - .collect()) + .collect(); + Ok(libs) } -fn find_lib_in_proc_maps(pid: pid_t, lib: &str) -> Result, io::Error> { +fn find_lib_in_proc_maps(pid: pid_t, lib: &Path) -> Result, io::Error> { let libs = proc_maps_libs(pid)?; - let ret = if lib.contains(".so") { - libs.into_iter().find(|(k, _)| k.as_str().starts_with(lib)) - } else { - libs.into_iter().find(|(k, _)| { - k.strip_prefix(lib) - .map(|k| k.starts_with(".so") || k.starts_with('-')) - .unwrap_or_default() - }) - }; + let lib = lib.as_os_str(); + let lib = lib.strip_suffix(OsStr::new(".so")).unwrap_or(lib); - Ok(ret.map(|(_, v)| v)) + Ok(libs.into_iter().find_map(|(file_name, path)| { + file_name.strip_prefix(lib).and_then(|suffix| { + (suffix.starts_with(OsStr::new(".so")) || suffix.starts_with(OsStr::new("-"))) + .then_some(path) + }) + })) } #[derive(Debug)] pub(crate) struct CacheEntry { - key: String, - value: String, + key: OsString, + value: OsString, _flags: i32, } @@ -297,7 +304,7 @@ pub(crate) struct LdSoCache { } impl LdSoCache { - pub fn load>(path: T) -> Result { + fn load>(path: T) -> Result { let data = fs::read(path)?; Self::parse(&data) } @@ -368,11 +375,16 @@ impl LdSoCache { } let read_str = |pos| { - unsafe { - CStr::from_ptr(cursor.get_ref()[offset + pos..].as_ptr() as *const c_char) - } - .to_string_lossy() - .into_owned() + use std::os::unix::ffi::OsStrExt as _; + OsStr::from_bytes( + unsafe { + CStr::from_ptr( + cursor.get_ref()[offset + pos..].as_ptr() as *const c_char + ) + } + .to_bytes(), + ) + .to_owned() }; let key = read_str(k_pos); @@ -386,19 +398,21 @@ impl LdSoCache { }) .collect::>()?; - Ok(LdSoCache { entries }) + Ok(Self { entries }) } - pub fn resolve(&self, lib: &str) -> Option<&str> { - let lib = if !lib.contains(".so") { - lib.to_string() + ".so" - } else { - lib.to_string() - }; + fn resolve(&self, lib: &Path) -> Option<&Path> { + let lib = lib.as_os_str(); + let lib = lib.strip_suffix(OsStr::new(".so")).unwrap_or(lib); self.entries .iter() - .find(|entry| entry.key.starts_with(&lib)) - .map(|entry| entry.value.as_str()) + .find_map(|CacheEntry { key, value, _flags }| { + key.strip_prefix(lib).and_then(|suffix| { + suffix + .starts_with(OsStr::new(".so")) + .then_some(Path::new(value.as_os_str())) + }) + }) } } @@ -420,7 +434,7 @@ enum ResolveSymbolError { SectionFileRangeNone(String, Result), } -fn resolve_symbol(path: &str, symbol: &str) -> Result { +fn resolve_symbol(path: &Path, symbol: &str) -> Result { let data = fs::read(path)?; let obj = object::read::File::parse(&*data)?; diff --git a/aya/src/programs/utils.rs b/aya/src/programs/utils.rs index beb9b5f5..0930e62b 100644 --- a/aya/src/programs/utils.rs +++ b/aya/src/programs/utils.rs @@ -20,7 +20,6 @@ pub(crate) fn attach_raw_tracepoint>( ) -> Result { 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", @@ -75,15 +74,15 @@ pub(crate) fn boot_time() -> SystemTime { }; let since_boot = get_time(libc::CLOCK_BOOTTIME); let since_epoch = get_time(libc::CLOCK_REALTIME); - UNIX_EPOCH + since_boot - since_epoch + UNIX_EPOCH + since_epoch - since_boot } /// Get the specified information from a file descriptor's fdinfo. -pub(crate) fn get_fdinfo(fd: BorrowedFd, key: &str) -> Result { +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)?; + let line = line?; if !line.contains(key) { continue; } diff --git a/aya/src/programs/xdp.rs b/aya/src/programs/xdp.rs index 36eec7d6..c9efb062 100644 --- a/aya/src/programs/xdp.rs +++ b/aya/src/programs/xdp.rs @@ -1,29 +1,33 @@ //! eXpress Data Path (XDP) programs. -use crate::{sys::SyscallError, util::KernelVersion}; -use bitflags; -use libc::if_nametoindex; use std::{ convert::TryFrom, ffi::CString, hash::Hash, io, - os::fd::{AsFd as _, AsRawFd as _, RawFd}, + os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, RawFd}, + path::Path, }; + +use bitflags; +use libc::if_nametoindex; use thiserror::Error; use crate::{ generated::{ - bpf_attach_type::{self, BPF_XDP}, - bpf_link_type, - bpf_prog_type::BPF_PROG_TYPE_XDP, - XDP_FLAGS_DRV_MODE, XDP_FLAGS_HW_MODE, XDP_FLAGS_REPLACE, XDP_FLAGS_SKB_MODE, - XDP_FLAGS_UPDATE_IF_NOEXIST, + bpf_link_type, bpf_prog_type, XDP_FLAGS_DRV_MODE, XDP_FLAGS_HW_MODE, XDP_FLAGS_REPLACE, + XDP_FLAGS_SKB_MODE, XDP_FLAGS_UPDATE_IF_NOEXIST, }, + obj::programs::XdpAttachType, programs::{ define_link_wrapper, load_program, FdLink, Link, LinkError, ProgramData, ProgramError, }, - sys::{bpf_link_create, bpf_link_get_info_by_fd, bpf_link_update, netlink_set_xdp_fd}, + sys::{ + bpf_link_create, bpf_link_get_info_by_fd, bpf_link_update, netlink_set_xdp_fd, LinkTarget, + SyscallError, + }, + util::KernelVersion, + VerifierLogLevel, }; /// The type returned when attaching an [`Xdp`] program fails on kernels `< 5.9`. @@ -38,7 +42,7 @@ pub enum XdpError { }, } -bitflags! { +bitflags::bitflags! { /// Flags passed to [`Xdp::attach()`]. #[derive(Clone, Copy, Debug, Default)] pub struct XdpFlags: u32 { @@ -80,13 +84,14 @@ bitflags! { #[doc(alias = "BPF_PROG_TYPE_XDP")] pub struct Xdp { pub(crate) data: ProgramData, + pub(crate) attach_type: XdpAttachType, } impl Xdp { /// Loads the program inside the kernel. pub fn load(&mut self) -> Result<(), ProgramError> { - self.data.expected_attach_type = Some(bpf_attach_type::BPF_XDP); - load_program(BPF_PROG_TYPE_XDP, &mut self.data) + self.data.expected_attach_type = Some(self.attach_type.into()); + load_program(bpf_prog_type::BPF_PROG_TYPE_XDP, &mut self.data) } /// Attaches the program to the given `interface`. @@ -103,6 +108,7 @@ impl Xdp { /// [`XdpError::NetlinkError`] is returned for older /// kernels. pub fn attach(&mut self, interface: &str, flags: XdpFlags) -> Result { + // TODO: avoid this unwrap by adding a new error variant. let c_interface = CString::new(interface).unwrap(); let if_index = unsafe { if_nametoindex(c_interface.as_ptr()) }; if if_index == 0 { @@ -130,23 +136,36 @@ impl Xdp { ) -> Result { 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) { - let link_fd = bpf_link_create(prog_fd, if_index, BPF_XDP, None, flags.bits()).map_err( - |(_, io_error)| SyscallError { - call: "bpf_link_create", - io_error, - }, - )?; + // Unwrap safety: the function starts with `self.fd()?` that will succeed if and only + // if the program has been loaded, i.e. there is an fd. We get one by: + // - Using `Xdp::from_pin` that sets `expected_attach_type` + // - Calling `Xdp::attach` that sets `expected_attach_type`, as geting an `Xdp` + // instance trhough `Xdp:try_from(Program)` does not set any fd. + // So, in all cases where we have an fd, we have an expected_attach_type. Thus, if we + // reach this point, expected_attach_type is guaranteed to be Some(_). + let attach_type = self.data.expected_attach_type.unwrap(); + let link_fd = bpf_link_create( + prog_fd, + LinkTarget::IfIndex(if_index), + attach_type, + None, + flags.bits(), + ) + .map_err(|(_, io_error)| SyscallError { + call: "bpf_link_create", + io_error, + })?; self.data .links .insert(XdpLink::new(XdpLinkInner::FdLink(FdLink::new(link_fd)))) } else { - unsafe { netlink_set_xdp_fd(if_index, prog_fd, None, flags.bits()) } + let if_index = if_index as i32; + unsafe { netlink_set_xdp_fd(if_index, Some(prog_fd), None, flags.bits()) } .map_err(|io_error| XdpError::NetlinkError { io_error })?; + let prog_fd = prog_fd.as_raw_fd(); self.data .links .insert(XdpLink::new(XdpLinkInner::NlLink(NlLink { @@ -157,6 +176,21 @@ impl Xdp { } } + /// Creates a program from a pinned entry on a bpffs. + /// + /// Existing links will not be populated. To work with existing links you should use [`crate::programs::links::PinnedLink`]. + /// + /// On drop, any managed links are detached and the program is unloaded. This will not result in + /// the program being unloaded from the kernel if it is still pinned. + pub fn from_pin>( + path: P, + attach_type: XdpAttachType, + ) -> Result { + let mut data = ProgramData::from_pinned_path(path, VerifierLogLevel::default())?; + data.expected_attach_type = Some(attach_type.into()); + Ok(Self { data, attach_type }) + } + /// Detaches the program. /// /// See [Xdp::attach]. @@ -178,7 +212,6 @@ impl Xdp { pub fn attach_to_link(&mut self, link: XdpLink) -> Result { 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; @@ -196,13 +229,21 @@ impl Xdp { XdpLinkInner::NlLink(nl_link) => { let if_index = nl_link.if_index; let old_prog_fd = nl_link.prog_fd; + // SAFETY: TODO(https://github.com/aya-rs/aya/issues/612): make this safe by not holding `RawFd`s. + let old_prog_fd = unsafe { BorrowedFd::borrow_raw(old_prog_fd) }; let flags = nl_link.flags; let replace_flags = flags | XdpFlags::REPLACE; unsafe { - netlink_set_xdp_fd(if_index, prog_fd, Some(old_prog_fd), replace_flags.bits()) - .map_err(|io_error| XdpError::NetlinkError { io_error })?; + netlink_set_xdp_fd( + if_index, + Some(prog_fd), + Some(old_prog_fd), + replace_flags.bits(), + ) + .map_err(|io_error| XdpError::NetlinkError { io_error })?; } + let prog_fd = prog_fd.as_raw_fd(); self.data .links .insert(XdpLink::new(XdpLinkInner::NlLink(NlLink { @@ -235,7 +276,9 @@ impl Link for NlLink { } else { self.flags.bits() }; - let _ = unsafe { netlink_set_xdp_fd(self.if_index, -1, Some(self.prog_fd), flags) }; + // 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) }; + let _ = unsafe { netlink_set_xdp_fd(self.if_index, None, Some(prog_fd), flags) }; Ok(()) } } @@ -257,15 +300,15 @@ impl Link for XdpLinkInner { fn id(&self) -> Self::Id { match self { - XdpLinkInner::FdLink(link) => XdpLinkIdInner::FdLinkId(link.id()), - XdpLinkInner::NlLink(link) => XdpLinkIdInner::NlLinkId(link.id()), + Self::FdLink(link) => XdpLinkIdInner::FdLinkId(link.id()), + Self::NlLink(link) => XdpLinkIdInner::NlLinkId(link.id()), } } fn detach(self) -> Result<(), ProgramError> { match self { - XdpLinkInner::FdLink(link) => link.detach(), - XdpLinkInner::NlLink(link) => link.detach(), + Self::FdLink(link) => link.detach(), + Self::NlLink(link) => link.detach(), } } } @@ -289,7 +332,7 @@ impl TryFrom for XdpLink { // unwrap of fd_link.fd will not panic since it's only None when being dropped. let info = bpf_link_get_info_by_fd(fd_link.fd.as_fd())?; if info.type_ == (bpf_link_type::BPF_LINK_TYPE_XDP as u32) { - return Ok(XdpLink::new(XdpLinkInner::FdLink(fd_link))); + return Ok(Self::new(XdpLinkInner::FdLink(fd_link))); } Err(LinkError::InvalidLink) } diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index 23fcf8e3..a971234f 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -1,14 +1,14 @@ use std::{ - cmp::{self, min}, - ffi::{CStr, CString}, + cmp, + ffi::{c_char, c_long, CStr, CString}, io, iter, mem::{self, MaybeUninit}, os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, FromRawFd as _, OwnedFd, RawFd}, slice, }; -use crate::util::KernelVersion; -use libc::{c_char, c_long, ENOENT, ENOSPC}; +use assert_matches::assert_matches; +use libc::{ENOENT, ENOSPC}; use obj::{ btf::{BtfEnum64, Enum64}, maps::{bpf_map_def, LegacyMap}, @@ -30,6 +30,7 @@ use crate::{ copy_instructions, }, sys::{syscall, SysResult, Syscall, SyscallError}, + util::KernelVersion, Btf, Pod, VerifierLogLevel, BPF_OBJ_NAME_LEN, }; @@ -38,7 +39,7 @@ pub(crate) fn bpf_create_map( def: &obj::Map, btf_fd: Option>, kernel_version: KernelVersion, -) -> SysResult { +) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_1 }; @@ -91,13 +92,14 @@ pub(crate) fn bpf_create_map( .copy_from_slice(unsafe { slice::from_raw_parts(name.as_ptr(), name_len) }); } - sys_bpf(bpf_cmd::BPF_MAP_CREATE, &mut attr) + // SAFETY: BPF_MAP_CREATE returns a new file descriptor. + unsafe { fd_sys_bpf(bpf_cmd::BPF_MAP_CREATE, &mut attr) } } -pub(crate) fn bpf_pin_object(fd: RawFd, path: &CStr) -> SysResult { +pub(crate) fn bpf_pin_object(fd: BorrowedFd<'_>, path: &CStr) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_4 }; - u.bpf_fd = fd as u32; + u.bpf_fd = fd.as_raw_fd() as u32; u.pathname = path.as_ptr() as u64; sys_bpf(bpf_cmd::BPF_OBJ_PIN, &mut attr) } @@ -129,7 +131,7 @@ pub(crate) struct BpfLoadProgramAttrs<'a> { } pub(crate) fn bpf_load_program( - aya_attr: &BpfLoadProgramAttrs, + aya_attr: &BpfLoadProgramAttrs<'_>, log_buf: &mut [u8], verifier_log_level: VerifierLogLevel, ) -> SysResult { @@ -140,7 +142,7 @@ pub(crate) fn bpf_load_program( if let Some(prog_name) = &aya_attr.name { let mut name: [c_char; 16] = [0; 16]; let name_bytes = prog_name.to_bytes(); - let len = min(name.len(), name_bytes.len()); + let len = cmp::min(name.len(), name_bytes.len()); name[..len].copy_from_slice(unsafe { slice::from_raw_parts(name_bytes.as_ptr() as *const c_char, len) }); @@ -194,7 +196,7 @@ pub(crate) fn bpf_load_program( } fn lookup( - fd: RawFd, + fd: BorrowedFd<'_>, key: Option<&K>, flags: u64, cmd: bpf_cmd, @@ -203,7 +205,7 @@ fn lookup( let mut value = MaybeUninit::zeroed(); let u = unsafe { &mut attr.__bindgen_anon_2 }; - u.map_fd = fd as u32; + u.map_fd = fd.as_raw_fd() as u32; if let Some(key) = key { u.key = key as *const _ as u64; } @@ -218,7 +220,7 @@ fn lookup( } pub(crate) fn bpf_map_lookup_elem( - fd: RawFd, + fd: BorrowedFd<'_>, key: &K, flags: u64, ) -> Result, (c_long, io::Error)> { @@ -226,7 +228,7 @@ pub(crate) fn bpf_map_lookup_elem( } pub(crate) fn bpf_map_lookup_and_delete_elem( - fd: RawFd, + fd: BorrowedFd<'_>, key: Option<&K>, flags: u64, ) -> Result, (c_long, io::Error)> { @@ -234,7 +236,7 @@ pub(crate) fn bpf_map_lookup_and_delete_elem( } pub(crate) fn bpf_map_lookup_elem_per_cpu( - fd: RawFd, + fd: BorrowedFd<'_>, key: &K, flags: u64, ) -> Result>, (c_long, io::Error)> { @@ -247,7 +249,7 @@ pub(crate) fn bpf_map_lookup_elem_per_cpu( } pub(crate) fn bpf_map_lookup_elem_ptr( - fd: RawFd, + fd: BorrowedFd<'_>, key: Option<&K>, value: *mut V, flags: u64, @@ -255,7 +257,7 @@ pub(crate) fn bpf_map_lookup_elem_ptr( let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_2 }; - u.map_fd = fd as u32; + u.map_fd = fd.as_raw_fd() as u32; if let Some(key) = key { u.key = key as *const _ as u64; } @@ -270,7 +272,7 @@ pub(crate) fn bpf_map_lookup_elem_ptr( } pub(crate) fn bpf_map_update_elem( - fd: RawFd, + fd: BorrowedFd<'_>, key: Option<&K>, value: &V, flags: u64, @@ -278,7 +280,7 @@ pub(crate) fn bpf_map_update_elem( let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_2 }; - u.map_fd = fd as u32; + u.map_fd = fd.as_raw_fd() as u32; if let Some(key) = key { u.key = key as *const _ as u64; } @@ -288,11 +290,15 @@ pub(crate) fn bpf_map_update_elem( sys_bpf(bpf_cmd::BPF_MAP_UPDATE_ELEM, &mut attr) } -pub(crate) fn bpf_map_push_elem(fd: RawFd, value: &V, flags: u64) -> SysResult { +pub(crate) fn bpf_map_push_elem( + fd: BorrowedFd<'_>, + value: &V, + flags: u64, +) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_2 }; - u.map_fd = fd as u32; + u.map_fd = fd.as_raw_fd() as u32; u.__bindgen_anon_1.value = value as *const _ as u64; u.flags = flags; @@ -300,7 +306,7 @@ pub(crate) fn bpf_map_push_elem(fd: RawFd, value: &V, flags: u64) -> Sys } pub(crate) fn bpf_map_update_elem_ptr( - fd: RawFd, + fd: BorrowedFd<'_>, key: *const K, value: *mut V, flags: u64, @@ -308,7 +314,7 @@ pub(crate) fn bpf_map_update_elem_ptr( let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_2 }; - u.map_fd = fd as u32; + u.map_fd = fd.as_raw_fd() as u32; u.key = key as u64; u.__bindgen_anon_1.value = value as u64; u.flags = flags; @@ -317,7 +323,7 @@ pub(crate) fn bpf_map_update_elem_ptr( } pub(crate) fn bpf_map_update_elem_per_cpu( - fd: RawFd, + fd: BorrowedFd<'_>, key: &K, values: &PerCpuValues, flags: u64, @@ -326,25 +332,25 @@ pub(crate) fn bpf_map_update_elem_per_cpu( bpf_map_update_elem_ptr(fd, key, mem.as_mut_ptr(), flags) } -pub(crate) fn bpf_map_delete_elem(fd: RawFd, key: &K) -> SysResult { +pub(crate) fn bpf_map_delete_elem(fd: BorrowedFd<'_>, key: &K) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_2 }; - u.map_fd = fd as u32; + u.map_fd = fd.as_raw_fd() as u32; u.key = key as *const _ as u64; sys_bpf(bpf_cmd::BPF_MAP_DELETE_ELEM, &mut attr) } pub(crate) fn bpf_map_get_next_key( - fd: RawFd, + fd: BorrowedFd<'_>, key: Option<&K>, ) -> Result, (c_long, io::Error)> { let mut attr = unsafe { mem::zeroed::() }; let mut next_key = MaybeUninit::uninit(); let u = unsafe { &mut attr.__bindgen_anon_2 }; - u.map_fd = fd as u32; + u.map_fd = fd.as_raw_fd() as u32; if let Some(key) = key { u.key = key as *const _ as u64; } @@ -358,25 +364,38 @@ pub(crate) fn bpf_map_get_next_key( } // since kernel 5.2 -pub(crate) fn bpf_map_freeze(fd: RawFd) -> SysResult { +pub(crate) fn bpf_map_freeze(fd: BorrowedFd<'_>) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_2 }; - u.map_fd = fd as u32; + u.map_fd = fd.as_raw_fd() as u32; sys_bpf(bpf_cmd::BPF_MAP_FREEZE, &mut attr) } +pub(crate) enum LinkTarget<'f> { + Fd(BorrowedFd<'f>), + IfIndex(u32), +} + // since kernel 5.7 pub(crate) fn bpf_link_create( - prog_fd: RawFd, - target_fd: RawFd, + prog_fd: BorrowedFd<'_>, + target: LinkTarget<'_>, attach_type: bpf_attach_type, btf_id: Option, flags: u32, ) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; - attr.link_create.__bindgen_anon_1.prog_fd = prog_fd as u32; - attr.link_create.__bindgen_anon_2.target_fd = target_fd as u32; + attr.link_create.__bindgen_anon_1.prog_fd = prog_fd.as_raw_fd() as u32; + + match target { + LinkTarget::Fd(fd) => { + attr.link_create.__bindgen_anon_2.target_fd = fd.as_raw_fd() as u32; + } + LinkTarget::IfIndex(ifindex) => { + attr.link_create.__bindgen_anon_2.target_ifindex = ifindex; + } + }; attr.link_create.attach_type = attach_type as u32; attr.link_create.flags = flags; if let Some(btf_id) = btf_id { @@ -390,14 +409,14 @@ pub(crate) fn bpf_link_create( // since kernel 5.7 pub(crate) fn bpf_link_update( link_fd: BorrowedFd<'_>, - new_prog_fd: RawFd, + new_prog_fd: BorrowedFd<'_>, old_prog_fd: Option, flags: u32, ) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; attr.link_update.link_fd = link_fd.as_raw_fd() as u32; - attr.link_update.__bindgen_anon_1.new_prog_fd = new_prog_fd as u32; + attr.link_update.__bindgen_anon_1.new_prog_fd = new_prog_fd.as_raw_fd() as u32; if let Some(fd) = old_prog_fd { attr.link_update.__bindgen_anon_2.old_prog_fd = fd as u32; attr.link_update.flags = flags | BPF_F_REPLACE; @@ -409,31 +428,47 @@ pub(crate) fn bpf_link_update( } pub(crate) fn bpf_prog_attach( - prog_fd: RawFd, - target_fd: RawFd, + prog_fd: BorrowedFd<'_>, + target_fd: BorrowedFd<'_>, attach_type: bpf_attach_type, -) -> SysResult { +) -> Result<(), SyscallError> { let mut attr = unsafe { mem::zeroed::() }; - attr.__bindgen_anon_5.attach_bpf_fd = prog_fd as u32; - attr.__bindgen_anon_5.target_fd = target_fd as u32; + attr.__bindgen_anon_5.attach_bpf_fd = prog_fd.as_raw_fd() as u32; + attr.__bindgen_anon_5.target_fd = target_fd.as_raw_fd() as u32; attr.__bindgen_anon_5.attach_type = attach_type as u32; - sys_bpf(bpf_cmd::BPF_PROG_ATTACH, &mut attr) + let ret = sys_bpf(bpf_cmd::BPF_PROG_ATTACH, &mut attr).map_err(|(code, io_error)| { + assert_eq!(code, -1); + SyscallError { + call: "bpf_prog_attach", + io_error, + } + })?; + assert_eq!(ret, 0); + Ok(()) } pub(crate) fn bpf_prog_detach( - prog_fd: RawFd, - map_fd: RawFd, + prog_fd: BorrowedFd<'_>, + target_fd: BorrowedFd<'_>, attach_type: bpf_attach_type, -) -> SysResult { +) -> Result<(), SyscallError> { let mut attr = unsafe { mem::zeroed::() }; - attr.__bindgen_anon_5.attach_bpf_fd = prog_fd as u32; - attr.__bindgen_anon_5.target_fd = map_fd as u32; + attr.__bindgen_anon_5.attach_bpf_fd = prog_fd.as_raw_fd() as u32; + attr.__bindgen_anon_5.target_fd = target_fd.as_raw_fd() as u32; attr.__bindgen_anon_5.attach_type = attach_type as u32; - sys_bpf(bpf_cmd::BPF_PROG_DETACH, &mut attr) + let ret = sys_bpf(bpf_cmd::BPF_PROG_DETACH, &mut attr).map_err(|(code, io_error)| { + assert_eq!(code, -1); + SyscallError { + call: "bpf_prog_detach", + io_error, + } + })?; + assert_eq!(ret, 0); + Ok(()) } pub(crate) fn bpf_prog_query( @@ -515,6 +550,21 @@ pub(crate) fn bpf_prog_get_info_by_fd( }) } +pub(crate) fn bpf_map_get_fd_by_id(map_id: u32) -> Result { + let mut attr = unsafe { mem::zeroed::() }; + + attr.__bindgen_anon_6.__bindgen_anon_1.map_id = map_id; + + // SAFETY: BPF_MAP_GET_FD_BY_ID returns a new file descriptor. + unsafe { fd_sys_bpf(bpf_cmd::BPF_MAP_GET_FD_BY_ID, &mut attr) }.map_err(|(code, io_error)| { + assert_eq!(code, -1); + SyscallError { + call: "bpf_map_get_fd_by_id", + io_error, + } + }) +} + pub(crate) fn bpf_map_get_info_by_fd(fd: BorrowedFd<'_>) -> Result { bpf_obj_get_info_by_fd(fd, |_| {}) } @@ -547,14 +597,17 @@ pub(crate) fn btf_obj_get_info_by_fd( }) } -pub(crate) fn bpf_raw_tracepoint_open(name: Option<&CStr>, prog_fd: RawFd) -> SysResult { +pub(crate) fn bpf_raw_tracepoint_open( + name: Option<&CStr>, + prog_fd: BorrowedFd<'_>, +) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; attr.raw_tracepoint.name = match name { Some(n) => n.as_ptr() as u64, None => 0, }; - attr.raw_tracepoint.prog_fd = prog_fd as u32; + attr.raw_tracepoint.prog_fd = prog_fd.as_raw_fd() as u32; // SAFETY: BPF_RAW_TRACEPOINT_OPEN returns a new file descriptor. unsafe { fd_sys_bpf(bpf_cmd::BPF_RAW_TRACEPOINT_OPEN, &mut attr) } @@ -613,7 +666,7 @@ pub(crate) fn is_prog_name_supported() -> bool { let mut name: [c_char; 16] = [0; 16]; let cstring = CString::new("aya_name_check").unwrap(); let name_bytes = cstring.to_bytes(); - let len = min(name.len(), name_bytes.len()); + let len = cmp::min(name.len(), name_bytes.len()); name[..len].copy_from_slice(unsafe { slice::from_raw_parts(name_bytes.as_ptr() as *const c_char, len) }); @@ -678,10 +731,9 @@ pub(crate) fn is_perf_link_supported() -> bool { 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, -1, bpf_attach_type::BPF_PERF_EVENT, None, 0), + bpf_link_create(fd, LinkTarget::IfIndex(u32::MAX), bpf_attach_type::BPF_PERF_EVENT, None, 0), // Returns EINVAL if unsupported. EBADF if supported. Err((_, e)) if e.raw_os_error() == Some(libc::EBADF), ) @@ -723,7 +775,7 @@ pub(crate) fn is_bpf_global_data_supported() -> bool { ); if let Ok(map) = map { - insns[0].imm = map.fd; + insns[0].imm = map.fd().as_fd().as_raw_fd(); let gpl = b"GPL\0"; u.license = gpl.as_ptr() as u64; @@ -757,6 +809,28 @@ pub(crate) fn is_bpf_cookie_supported() -> bool { bpf_prog_load(&mut attr).is_ok() } +/// Tests whether CpuMap, DevMap and DevMapHash support program ids +pub(crate) fn is_prog_id_supported(map_type: bpf_map_type) -> bool { + assert_matches!( + map_type, + bpf_map_type::BPF_MAP_TYPE_CPUMAP + | bpf_map_type::BPF_MAP_TYPE_DEVMAP + | bpf_map_type::BPF_MAP_TYPE_DEVMAP_HASH + ); + + let mut attr = unsafe { mem::zeroed::() }; + let u = unsafe { &mut attr.__bindgen_anon_1 }; + + u.map_type = map_type as u32; + u.key_size = 4; + u.value_size = 8; // 4 for CPU ID, 8 for CPU ID + prog ID + u.max_entries = 1; + u.map_flags = 0; + + // SAFETY: BPF_MAP_CREATE returns a new file descriptor. + unsafe { fd_sys_bpf(bpf_cmd::BPF_MAP_CREATE, &mut attr) }.is_ok() +} + pub(crate) fn is_btf_supported() -> bool { let mut btf = Btf::new(); let name_offset = btf.add_string("int"); @@ -975,12 +1049,16 @@ pub(crate) fn iter_link_ids() -> impl Iterator> iter_obj_ids(bpf_cmd::BPF_LINK_GET_NEXT_ID, "bpf_link_get_next_id") } +pub(crate) fn iter_map_ids() -> impl Iterator> { + iter_obj_ids(bpf_cmd::BPF_MAP_GET_NEXT_ID, "bpf_map_get_next_id") +} + pub(crate) fn retry_with_verifier_logs( max_retries: usize, f: impl Fn(&mut [u8]) -> SysResult, ) -> (SysResult, VerifierLog) { const MIN_LOG_BUF_SIZE: usize = 1024 * 10; - const MAX_LOG_BUF_SIZE: usize = (std::u32::MAX >> 8) as usize; + const MAX_LOG_BUF_SIZE: usize = (u32::MAX >> 8) as usize; let mut log_buf = Vec::new(); let mut retries = 0; @@ -1010,9 +1088,10 @@ pub(crate) fn retry_with_verifier_logs( #[cfg(test)] mod tests { + use libc::{EBADF, EINVAL}; + use super::*; use crate::sys::override_syscall; - use libc::{EBADF, EINVAL}; #[test] fn test_perf_link_supported() { @@ -1036,4 +1115,28 @@ mod tests { let supported = is_perf_link_supported(); assert!(!supported); } + + #[test] + fn test_prog_id_supported() { + override_syscall(|_call| Ok(42)); + + // Ensure that the three map types we can check are accepted + let supported = is_prog_id_supported(bpf_map_type::BPF_MAP_TYPE_CPUMAP); + assert!(supported); + let supported = is_prog_id_supported(bpf_map_type::BPF_MAP_TYPE_DEVMAP); + assert!(supported); + let supported = is_prog_id_supported(bpf_map_type::BPF_MAP_TYPE_DEVMAP_HASH); + assert!(supported); + + override_syscall(|_call| Err((-1, io::Error::from_raw_os_error(EINVAL)))); + let supported = is_prog_id_supported(bpf_map_type::BPF_MAP_TYPE_CPUMAP); + assert!(!supported); + } + + #[test] + #[should_panic = "assertion failed: `BPF_MAP_TYPE_HASH` does not match `bpf_map_type::BPF_MAP_TYPE_CPUMAP | bpf_map_type::BPF_MAP_TYPE_DEVMAP | +bpf_map_type::BPF_MAP_TYPE_DEVMAP_HASH`"] + fn test_prog_id_supported_reject_types() { + is_prog_id_supported(bpf_map_type::BPF_MAP_TYPE_HASH); + } } diff --git a/aya/src/sys/fake.rs b/aya/src/sys/fake.rs index 6cac51b6..cfd06e4d 100644 --- a/aya/src/sys/fake.rs +++ b/aya/src/sys/fake.rs @@ -1,10 +1,12 @@ -use std::{cell::RefCell, ffi::c_long, io, ptr}; - -use libc::c_void; +use std::{ + cell::RefCell, + ffi::{c_long, c_void}, + io, ptr, +}; use super::{SysResult, Syscall}; -type SyscallFn = unsafe fn(Syscall) -> SysResult; +type SyscallFn = unsafe fn(Syscall<'_>) -> SysResult; #[cfg(test)] thread_local! { @@ -13,11 +15,11 @@ thread_local! { } #[cfg(test)] -unsafe fn test_syscall(_call: Syscall) -> SysResult { +unsafe fn test_syscall(_call: Syscall<'_>) -> SysResult { Err((-1, io::Error::from_raw_os_error(libc::EINVAL))) } #[cfg(test)] -pub(crate) fn override_syscall(call: unsafe fn(Syscall) -> SysResult) { +pub(crate) fn override_syscall(call: unsafe fn(Syscall<'_>) -> SysResult) { TEST_SYSCALL.with(|test_impl| *test_impl.borrow_mut() = call); } diff --git a/aya/src/sys/mod.rs b/aya/src/sys/mod.rs index ef2a0edf..0b22463a 100644 --- a/aya/src/sys/mod.rs +++ b/aya/src/sys/mod.rs @@ -5,20 +5,21 @@ mod perf_event; #[cfg(test)] mod fake; -use libc::{c_int, c_long, pid_t, SYS_bpf, SYS_perf_event_open}; use std::{ + ffi::{c_int, c_long, c_void}, io, mem, os::fd::{AsRawFd as _, BorrowedFd}, }; -use thiserror::Error; pub(crate) use bpf::*; #[cfg(test)] pub(crate) use fake::*; +use libc::{pid_t, SYS_bpf, SYS_perf_event_open}; #[doc(hidden)] pub use netlink::netlink_set_link_up; pub(crate) use netlink::*; pub(crate) use perf_event::*; +use thiserror::Error; use crate::generated::{bpf_attr, bpf_cmd, perf_event_attr}; @@ -85,7 +86,7 @@ impl std::fmt::Debug for Syscall<'_> { } } -fn syscall(call: Syscall) -> SysResult { +fn syscall(call: Syscall<'_>) -> SysResult { #[cfg(test)] return TEST_SYSCALL.with(|test_impl| unsafe { test_impl.borrow()(call) }); @@ -103,7 +104,10 @@ fn syscall(call: Syscall) -> SysResult { flags, } => libc::syscall(SYS_perf_event_open, &attr, pid, cpu, group, flags), Syscall::PerfEventIoctl { fd, request, arg } => { - libc::ioctl(fd.as_raw_fd(), request.try_into().unwrap(), arg) as libc::c_long + let int = libc::ioctl(fd.as_raw_fd(), request.try_into().unwrap(), arg); + #[allow(trivial_numeric_casts)] + let int = int as c_long; + int } } } { @@ -111,3 +115,19 @@ fn syscall(call: Syscall) -> SysResult { ret => Err((ret, io::Error::last_os_error())), } } + +#[cfg_attr(test, allow(unused_variables))] +pub(crate) unsafe fn mmap( + addr: *mut c_void, + len: usize, + prot: c_int, + flags: c_int, + fd: BorrowedFd<'_>, + offset: libc::off_t, +) -> *mut c_void { + #[cfg(not(test))] + return libc::mmap(addr, len, prot, flags, fd.as_raw_fd(), offset); + + #[cfg(test)] + TEST_MMAP_RET.with(|ret| *ret.borrow()) +} diff --git a/aya/src/sys/netlink.rs b/aya/src/sys/netlink.rs index b003d86f..d6758cb7 100644 --- a/aya/src/sys/netlink.rs +++ b/aya/src/sys/netlink.rs @@ -3,18 +3,18 @@ use std::{ ffi::CStr, io, mem::{self}, - os::fd::RawFd, + os::fd::{RawFd, BorrowedFd}, ptr, slice, }; use thiserror::Error; - use libc::{ - close, getsockname, nlattr, nlmsgerr, nlmsghdr, recv, send, setsockopt, sockaddr_nl, socket, + getsockname, nlattr, nlmsgerr, nlmsghdr, recv, send, setsockopt, sockaddr_nl, socket, AF_NETLINK, AF_UNSPEC, ETH_P_ALL, IFF_UP, IFLA_XDP, NETLINK_EXT_ACK, NETLINK_ROUTE, NLA_ALIGNTO, NLA_F_NESTED, NLA_TYPE_MASK, NLMSG_DONE, NLMSG_ERROR, NLM_F_ACK, NLM_F_CREATE, NLM_F_DUMP, NLM_F_ECHO, NLM_F_EXCL, NLM_F_MULTI, NLM_F_REQUEST, RTM_DELTFILTER, RTM_GETQDISC, RTM_GETTFILTER, RTM_NEWQDISC, RTM_NEWTFILTER, RTM_SETLINK, SOCK_RAW, SOL_NETLINK, }; +use thiserror::Error; use crate::{ generated::{ @@ -32,8 +32,8 @@ const NLA_HDR_LEN: usize = align_to(mem::size_of::(), NLA_ALIGNTO as usi // netlink alignments pub(crate) unsafe fn netlink_set_xdp_fd( if_index: i32, - fd: RawFd, - old_fd: Option, + fd: Option>, + old_fd: Option>, flags: u32, ) -> Result<(), io::Error> { let sock = NetlinkSocket::open()?; @@ -55,14 +55,20 @@ pub(crate) unsafe fn netlink_set_xdp_fd( // write the attrs let attrs_buf = request_attributes(&mut req, nlmsg_len); let mut attrs = NestedAttrs::new(attrs_buf, IFLA_XDP); - attrs.write_attr(IFLA_XDP_FD as u16, fd)?; + attrs.write_attr( + IFLA_XDP_FD as u16, + fd.map(|fd| fd.as_raw_fd()).unwrap_or(-1), + )?; if flags > 0 { attrs.write_attr(IFLA_XDP_FLAGS as u16, flags)?; } if flags & XDP_FLAGS_REPLACE != 0 { - attrs.write_attr(IFLA_XDP_EXPECTED_FD as u16, old_fd.unwrap())?; + attrs.write_attr( + IFLA_XDP_EXPECTED_FD as u16, + old_fd.map(|fd| fd.as_raw_fd()).unwrap(), + )?; } let nla_len = attrs.finish()?; @@ -148,7 +154,7 @@ pub(crate) unsafe fn netlink_qdisc_add_clsact(if_index: i32) -> Result<(), io::E pub(crate) unsafe fn netlink_qdisc_attach( if_index: i32, attach_type: &TcAttachType, - prog_fd: RawFd, + prog_fd: BorrowedFd<'_>, prog_name: &CStr, priority: u16, handle: u32, @@ -331,23 +337,25 @@ struct TcRequest { } struct NetlinkSocket { - sock: RawFd, + sock: OwnedFd, _nl_pid: u32, } impl NetlinkSocket { - fn open() -> Result { + fn open() -> Result { // Safety: libc wrapper let sock = unsafe { socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE) }; if sock < 0 { return Err(io::Error::last_os_error()); } + // SAFETY: `socket` returns a file descriptor. + let sock = unsafe { OwnedFd::from_raw_fd(sock) }; let enable = 1i32; // Safety: libc wrapper unsafe { setsockopt( - sock, + sock.as_raw_fd(), SOL_NETLINK, NETLINK_EXT_ACK, &enable as *const _ as *const _, @@ -360,19 +368,33 @@ impl NetlinkSocket { addr.nl_family = AF_NETLINK as u16; let mut addr_len = mem::size_of::() as u32; // Safety: libc wrapper - if unsafe { getsockname(sock, &mut addr as *mut _ as *mut _, &mut addr_len as *mut _) } < 0 + if unsafe { + getsockname( + sock.as_raw_fd(), + &mut addr as *mut _ as *mut _, + &mut addr_len as *mut _, + ) + } < 0 { return Err(io::Error::last_os_error()); } - Ok(NetlinkSocket { + Ok(Self { sock, _nl_pid: addr.nl_pid, }) } fn send(&self, msg: &[u8]) -> Result<(), io::Error> { - if unsafe { send(self.sock, msg.as_ptr() as *const _, msg.len(), 0) } < 0 { + if unsafe { + send( + self.sock.as_raw_fd(), + msg.as_ptr() as *const _, + msg.len(), + 0, + ) + } < 0 + { return Err(io::Error::last_os_error()); } Ok(()) @@ -385,7 +407,14 @@ impl NetlinkSocket { 'out: while multipart { multipart = false; // Safety: libc wrapper - let len = unsafe { recv(self.sock, buf.as_mut_ptr() as *mut _, buf.len(), 0) }; + let len = unsafe { + recv( + self.sock.as_raw_fd(), + buf.as_mut_ptr() as *mut _, + buf.len(), + 0, + ) + }; if len < 0 { return Err(io::Error::last_os_error()); } @@ -425,7 +454,7 @@ struct NetlinkMessage { } impl NetlinkMessage { - fn read(buf: &[u8]) -> Result { + fn read(buf: &[u8]) -> Result { if mem::size_of::() > buf.len() { return Err(io::Error::new( io::ErrorKind::Other, @@ -463,7 +492,7 @@ impl NetlinkMessage { (buf[data_offset..msg_len].to_vec(), None) }; - Ok(NetlinkMessage { + Ok(Self { header, data, error, @@ -471,13 +500,6 @@ impl NetlinkMessage { } } -impl Drop for NetlinkSocket { - fn drop(&mut self) { - // Safety: libc wrapper - unsafe { close(self.sock) }; - } -} - const fn align_to(v: usize, align: usize) -> usize { (v + (align - 1)) & !(align - 1) } @@ -493,8 +515,8 @@ struct NestedAttrs<'a> { } impl<'a> NestedAttrs<'a> { - fn new(buf: &mut [u8], top_attr_type: u16) -> NestedAttrs<'_> { - NestedAttrs { + fn new(buf: &'a mut [u8], top_attr_type: u16) -> Self { + Self { buf, top_attr_type, offset: NLA_HDR_LEN, @@ -578,8 +600,8 @@ struct NlAttrsIterator<'a> { } impl<'a> NlAttrsIterator<'a> { - fn new(attrs: &[u8]) -> NlAttrsIterator { - NlAttrsIterator { attrs, offset: 0 } + fn new(attrs: &'a [u8]) -> Self { + Self { attrs, offset: 0 } } } @@ -620,7 +642,7 @@ impl<'a> Iterator for NlAttrsIterator<'a> { } } -fn parse_attrs(buf: &[u8]) -> Result, NlAttrError> { +fn parse_attrs(buf: &[u8]) -> Result>, NlAttrError> { let mut attrs = HashMap::new(); for attr in NlAttrsIterator::new(buf) { let attr = attr?; @@ -645,8 +667,8 @@ enum NlAttrError { } impl From for io::Error { - fn from(e: NlAttrError) -> io::Error { - io::Error::new(io::ErrorKind::Other, e) + fn from(e: NlAttrError) -> Self { + Self::new(io::ErrorKind::Other, e) } } @@ -792,6 +814,6 @@ mod tests { TCA_BPF_NAME as u16 ); let name = CStr::from_bytes_with_nul(inner.data).unwrap(); - assert_eq!(name.to_string_lossy(), "foo"); + assert_eq!(name.to_str().unwrap(), "foo"); } } diff --git a/aya/src/sys/perf_event.rs b/aya/src/sys/perf_event.rs index dad86a45..b06f4fba 100644 --- a/aya/src/sys/perf_event.rs +++ b/aya/src/sys/perf_event.rs @@ -1,11 +1,12 @@ use std::{ - ffi::{c_long, CString}, + ffi::{c_int, c_long, CString, OsStr}, io, mem, os::fd::{BorrowedFd, FromRawFd as _, OwnedFd}, }; -use libc::{c_int, pid_t}; +use libc::pid_t; +use super::{syscall, SysResult, Syscall}; use crate::generated::{ perf_event_attr, perf_event_sample_format::PERF_SAMPLE_RAW, @@ -14,8 +15,6 @@ use crate::generated::{ PERF_FLAG_FD_CLOEXEC, }; -use super::{syscall, SysResult, Syscall}; - #[allow(clippy::too_many_arguments)] pub(crate) fn perf_event_open( perf_type: u32, @@ -62,17 +61,19 @@ pub(crate) fn perf_event_open_bpf(cpu: c_int) -> SysResult { pub(crate) fn perf_event_open_probe( ty: u32, ret_bit: Option, - name: &str, + name: &OsStr, offset: u64, pid: Option, ) -> SysResult { + use std::os::unix::ffi::OsStrExt as _; + let mut attr = unsafe { mem::zeroed::() }; if let Some(ret_bit) = ret_bit { attr.config = 1 << ret_bit; } - let c_name = CString::new(name).unwrap(); + let c_name = CString::new(name.as_bytes()).unwrap(); attr.size = mem::size_of::() as u32; attr.type_ = ty; diff --git a/aya/src/util.rs b/aya/src/util.rs index 65bcb415..4e91d081 100644 --- a/aya/src/util.rs +++ b/aya/src/util.rs @@ -11,13 +11,13 @@ use std::{ str::{FromStr, Utf8Error}, }; +use libc::{if_nametoindex, sysconf, uname, utsname, _SC_PAGESIZE}; + use crate::{ generated::{TC_H_MAJ_MASK, TC_H_MIN_MASK}, Pod, }; -use libc::{if_nametoindex, sysconf, uname, utsname, _SC_PAGESIZE}; - /// Represents a kernel version, in major.minor.release version. // Adapted from https://docs.rs/procfs/latest/procfs/sys/kernel/struct.Version.html. #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd)] @@ -49,23 +49,43 @@ impl KernelVersion { /// Returns the kernel version of the currently running kernel. pub fn current() -> Result { - let kernel_version = Self::get_kernel_version(); + Self::get_kernel_version() + } - // The kernel version is clamped to 4.19.255 on kernels 4.19.222 and above. - // - // See https://github.com/torvalds/linux/commit/a256aac. - const CLAMPED_KERNEL_MAJOR: u8 = 4; - const CLAMPED_KERNEL_MINOR: u8 = 19; - if let Ok(Self { - major: CLAMPED_KERNEL_MAJOR, - minor: CLAMPED_KERNEL_MINOR, - patch: 222.., - }) = kernel_version - { - return Ok(Self::new(CLAMPED_KERNEL_MAJOR, CLAMPED_KERNEL_MINOR, 255)); + /// The equivalent of LINUX_VERSION_CODE. + pub fn code(self) -> u32 { + let Self { + major, + minor, + mut patch, + } = self; + + // Certain LTS kernels went above the "max" 255 patch so + // backports were done to cap the patch version + let max_patch = match (major, minor) { + // On 4.4 + 4.9, any patch 257 or above was hardcoded to 255. + // See: https://github.com/torvalds/linux/commit/a15813a + + // https://github.com/torvalds/linux/commit/42efb098 + (4, 4 | 9) => 257, + // On 4.14, any patch 252 or above was hardcoded to 255. + // See: https://github.com/torvalds/linux/commit/e131e0e + (4, 14) => 252, + // On 4.19, any patch 222 or above was hardcoded to 255. + // See: https://github.com/torvalds/linux/commit/a256aac + (4, 19) => 222, + // For other kernels (i.e., newer LTS kernels as other + // ones won't reach 255+ patches) clamp it to 255. See: + // https://github.com/torvalds/linux/commit/9b82f13e + _ => 255, + }; + + // anything greater or equal to `max_patch` is hardcoded to + // 255. + if patch >= max_patch { + patch = 255; } - kernel_version + (u32::from(major) << 16) + (u32::from(minor) << 8) + u32::from(patch) } // This is ported from https://github.com/torvalds/linux/blob/3f01e9f/tools/lib/bpf/libbpf_probes.c#L21-L101. @@ -133,10 +153,10 @@ impl KernelVersion { } fn parse_kernel_version_string(s: &str) -> Result { - fn parse>(s: Option<&str>) -> Option { + fn parse>(s: Option<&str>) -> Option { match s.map(str::parse).transpose() { Ok(option) => option, - Err(std::num::ParseIntError { .. }) => None, + Err(ParseIntError { .. }) => None, } } let error = || CurrentKernelVersionError::ParseError(s.to_string()); @@ -245,6 +265,13 @@ fn parse_kernel_symbols(reader: impl BufRead) -> Result, i /// # Errors /// /// Returns [`std::io::ErrorKind::NotFound`] if the prefix can't be guessed. Returns other [`std::io::Error`] kinds if `/proc/kallsyms` can't be opened or is somehow invalid. +#[deprecated( + since = "0.12.0", + note = "On some systems - commonly on 64 bit kernels that support running \ + 32 bit applications - the syscall prefix depends on what architecture an \ + application is compiled for, therefore attaching to only one prefix is \ + incorrect and can lead to security issues." +)] pub fn syscall_prefix() -> Result<&'static str, io::Error> { const PREFIXES: [&str; 7] = [ "sys_", @@ -337,11 +364,21 @@ pub(crate) fn bytes_of_slice(val: &[T]) -> &[u8] { unsafe { slice::from_raw_parts(val.as_ptr().cast(), size) } } +pub(crate) fn bytes_of_bpf_name(bpf_name: &[core::ffi::c_char; 16]) -> &[u8] { + let length = bpf_name + .iter() + .rposition(|ch| *ch != 0) + .map(|pos| pos + 1) + .unwrap_or(0); + unsafe { std::slice::from_raw_parts(bpf_name.as_ptr() as *const _, length) } +} + #[cfg(test)] mod tests { - use super::*; use assert_matches::assert_matches; + use super::*; + #[test] fn test_parse_kernel_version_string() { // WSL. diff --git a/bpf/aya-bpf-bindings/src/lib.rs b/bpf/aya-bpf-bindings/src/lib.rs index 1528e4f8..1129fa75 100644 --- a/bpf/aya-bpf-bindings/src/lib.rs +++ b/bpf/aya-bpf-bindings/src/lib.rs @@ -14,17 +14,14 @@ mod aarch64; mod riscv64; mod gen { - #[cfg(bpf_target_arch = "x86_64")] - pub use super::x86_64::*; - - #[cfg(bpf_target_arch = "arm")] - pub use super::armv7::*; - #[cfg(bpf_target_arch = "aarch64")] pub use super::aarch64::*; - + #[cfg(bpf_target_arch = "arm")] + pub use super::armv7::*; #[cfg(bpf_target_arch = "riscv64")] pub use super::riscv64::*; + #[cfg(bpf_target_arch = "x86_64")] + pub use super::x86_64::*; } pub use gen::helpers; diff --git a/bpf/aya-bpf-cty/README.md b/bpf/aya-bpf-cty/README.md index f5d09bd4..122e7b69 100644 --- a/bpf/aya-bpf-cty/README.md +++ b/bpf/aya-bpf-cty/README.md @@ -1,17 +1,16 @@ +# `cty` + [![crates.io](https://img.shields.io/crates/v/cty.svg)](https://crates.io/crates/cty) [![crates.io](https://img.shields.io/crates/d/cty.svg)](https://crates.io/crates/cty) -# `cty` - > Type aliases to C types like c_int for use with bindgen ## License Licensed under either of -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) +- Apache License, Version 2.0 [LICENSE-APACHE](./LICENSE-APACHE) or +- MIT license [LICENSE-MIT](./LICENSE-MIT) at your option. diff --git a/bpf/aya-bpf-cty/src/lib.rs b/bpf/aya-bpf-cty/src/lib.rs index e40645f5..4a62a0d9 100644 --- a/bpf/aya-bpf-cty/src/lib.rs +++ b/bpf/aya-bpf-cty/src/lib.rs @@ -12,8 +12,6 @@ pub use ad::*; // OD = OS dependent pub use od::*; -// PWD = Pointer Width Dependent -pub use pwd::*; #[cfg(target_arch = "bpf")] mod ad { @@ -106,12 +104,6 @@ mod od { pub type c_ulong = u64; } -#[cfg(target_pointer_width = "32")] -mod pwd {} - -#[cfg(target_pointer_width = "64")] -mod pwd {} - pub type int8_t = i8; pub type int16_t = i16; pub type int32_t = i32; diff --git a/bpf/aya-bpf/Cargo.toml b/bpf/aya-bpf/Cargo.toml index 0af23767..b586d9c5 100644 --- a/bpf/aya-bpf/Cargo.toml +++ b/bpf/aya-bpf/Cargo.toml @@ -8,6 +8,14 @@ edition = "2021" aya-bpf-cty = { path = "../aya-bpf-cty" } aya-bpf-macros = { path = "../../aya-bpf-macros" } aya-bpf-bindings = { path = "../aya-bpf-bindings" } +const-assert = { workspace = true, optional = true } [build-dependencies] rustversion = { workspace = true } + +[features] +default = [] +# TODO(https://github.com/rust-lang/rust/issues/76560): Always utilize the +# logic gated behind this feature. This is not currently possible because the +# underlying `const_generic_exprs` language feature is still incomplete. +const_assert = ["const-assert"] diff --git a/bpf/aya-bpf/src/args.rs b/bpf/aya-bpf/src/args.rs index 437fe329..7cee97a8 100644 --- a/bpf/aya-bpf/src/args.rs +++ b/bpf/aya-bpf/src/args.rs @@ -1,14 +1,11 @@ -use crate::{cty::c_void, helpers::bpf_probe_read}; - // aarch64 uses user_pt_regs instead of pt_regs #[cfg(not(any(bpf_target_arch = "aarch64", bpf_target_arch = "riscv64")))] use crate::bindings::pt_regs; - #[cfg(bpf_target_arch = "aarch64")] use crate::bindings::user_pt_regs as pt_regs; - #[cfg(bpf_target_arch = "riscv64")] use crate::bindings::user_regs_struct as pt_regs; +use crate::{cty::c_void, helpers::bpf_probe_read}; /// A trait that indicates a valid type for an argument which can be coerced from a BTF /// context. diff --git a/bpf/aya-bpf/src/lib.rs b/bpf/aya-bpf/src/lib.rs index 517e23fa..d482de0c 100644 --- a/bpf/aya-bpf/src/lib.rs +++ b/bpf/aya-bpf/src/lib.rs @@ -8,6 +8,11 @@ html_logo_url = "https://aya-rs.dev/assets/images/crabby.svg", html_favicon_url = "https://aya-rs.dev/assets/images/crabby.svg" )] +#![cfg_attr( + feature = "const_assert", + allow(incomplete_features), + feature(generic_const_exprs) +)] #![cfg_attr(unstable, feature(never_type))] #![cfg_attr(target_arch = "bpf", feature(asm_experimental_arch))] #![allow(clippy::missing_safety_doc)] @@ -22,13 +27,12 @@ pub mod helpers; pub mod maps; pub mod programs; -pub use aya_bpf_cty as cty; - use core::ffi::c_void; -use cty::{c_int, c_long}; -use helpers::{bpf_get_current_comm, bpf_get_current_pid_tgid, bpf_get_current_uid_gid}; +pub use aya_bpf_cty as cty; pub use aya_bpf_macros as macros; +use cty::{c_int, c_long}; +use helpers::{bpf_get_current_comm, bpf_get_current_pid_tgid, bpf_get_current_uid_gid}; pub const TASK_COMM_LEN: usize = 16; diff --git a/bpf/aya-bpf/src/maps/mod.rs b/bpf/aya-bpf/src/maps/mod.rs index 8fa375dd..ead24dc3 100644 --- a/bpf/aya-bpf/src/maps/mod.rs +++ b/bpf/aya-bpf/src/maps/mod.rs @@ -13,10 +13,12 @@ pub mod per_cpu_array; pub mod perf; pub mod program_array; pub mod queue; +pub mod ring_buf; pub mod sock_hash; pub mod sock_map; pub mod stack; pub mod stack_trace; +pub mod xdp; pub use array::Array; pub use bloom_filter::BloomFilter; @@ -26,7 +28,9 @@ pub use per_cpu_array::PerCpuArray; pub use perf::{PerfEventArray, PerfEventByteArray}; pub use program_array::ProgramArray; pub use queue::Queue; +pub use ring_buf::RingBuf; pub use sock_hash::SockHash; pub use sock_map::SockMap; pub use stack::Stack; pub use stack_trace::StackTrace; +pub use xdp::{CpuMap, DevMap, DevMapHash, XskMap}; diff --git a/bpf/aya-bpf/src/maps/ring_buf.rs b/bpf/aya-bpf/src/maps/ring_buf.rs new file mode 100644 index 00000000..ee544efe --- /dev/null +++ b/bpf/aya-bpf/src/maps/ring_buf.rs @@ -0,0 +1,163 @@ +use core::{ + cell::UnsafeCell, + mem, + mem::MaybeUninit, + ops::{Deref, DerefMut}, +}; + +#[cfg(feature = "const_assert")] +use const_assert::{Assert, IsTrue}; + +use crate::{ + bindings::{bpf_map_def, bpf_map_type::BPF_MAP_TYPE_RINGBUF}, + helpers::{ + bpf_ringbuf_discard, bpf_ringbuf_output, bpf_ringbuf_query, bpf_ringbuf_reserve, + bpf_ringbuf_submit, + }, + maps::PinningType, +}; + +#[repr(transparent)] +pub struct RingBuf { + def: UnsafeCell, +} + +unsafe impl Sync for RingBuf {} + +/// A ring buffer entry, returned from [`RingBuf::reserve`]. +/// +/// You must [`submit`] or [`discard`] this entry before it gets dropped. +/// +/// [`submit`]: RingBufEntry::submit +/// [`discard`]: RingBufEntry::discard +#[must_use = "eBPF verifier requires ring buffer entries to be either submitted or discarded"] +pub struct RingBufEntry(&'static mut MaybeUninit); + +impl Deref for RingBufEntry { + type Target = MaybeUninit; + + fn deref(&self) -> &Self::Target { + self.0 + } +} + +impl DerefMut for RingBufEntry { + fn deref_mut(&mut self) -> &mut Self::Target { + self.0 + } +} + +impl RingBufEntry { + /// Discard this ring buffer entry. The entry will be skipped by the userspace reader. + pub fn discard(self, flags: u64) { + unsafe { bpf_ringbuf_discard(self.0.as_mut_ptr() as *mut _, flags) }; + } + + /// Commit this ring buffer entry. The entry will be made visible to the userspace reader. + pub fn submit(self, flags: u64) { + unsafe { bpf_ringbuf_submit(self.0.as_mut_ptr() as *mut _, flags) }; + } +} + +impl RingBuf { + /// Declare an eBPF ring buffer. + /// + /// The linux kernel requires that `byte_size` be a power-of-2 multiple of the page size. The + /// loading program may coerce the size when loading the map. + pub const fn with_byte_size(byte_size: u32, flags: u32) -> Self { + Self::new(byte_size, flags, PinningType::None) + } + + /// Declare a pinned eBPF ring buffer. + /// + /// The linux kernel requires that `byte_size` be a power-of-2 multiple of the page size. The + /// loading program may coerce the size when loading the map. + pub const fn pinned(byte_size: u32, flags: u32) -> Self { + Self::new(byte_size, flags, PinningType::ByName) + } + + const fn new(byte_size: u32, flags: u32, pinning_type: PinningType) -> Self { + Self { + def: UnsafeCell::new(bpf_map_def { + type_: BPF_MAP_TYPE_RINGBUF, + key_size: 0, + value_size: 0, + max_entries: byte_size, + map_flags: flags, + id: 0, + pinning: pinning_type as u32, + }), + } + } + + /// Reserve memory in the ring buffer that can fit `T`. + /// + /// Returns `None` if the ring buffer is full. + #[cfg(feature = "const_assert")] + pub fn reserve(&self, flags: u64) -> Option> + where + Assert<{ 8 % mem::align_of::() == 0 }>: IsTrue, + { + self.reserve_impl(flags) + } + + /// Reserve memory in the ring buffer that can fit `T`. + /// + /// Returns `None` if the ring buffer is full. + /// + /// The kernel will reserve memory at an 8-bytes aligned boundary, so `mem::align_of()` must + /// be equal or smaller than 8. If you use this with a `T` that isn't properly aligned, this + /// function will be compiled to a panic; depending on your panic_handler, this may make + /// the eBPF program fail to load, or it may make it have undefined behavior. + #[cfg(not(feature = "const_assert"))] + pub fn reserve(&self, flags: u64) -> Option> { + assert_eq!(8 % mem::align_of::(), 0); + self.reserve_impl(flags) + } + + fn reserve_impl(&self, flags: u64) -> Option> { + let ptr = unsafe { + bpf_ringbuf_reserve(self.def.get() as *mut _, mem::size_of::() as _, flags) + } as *mut MaybeUninit; + unsafe { ptr.as_mut() }.map(|ptr| RingBufEntry(ptr)) + } + + /// Copy `data` to the ring buffer output. + /// + /// Consider using [`reserve`] and [`submit`] if `T` is statically sized and you want to save a + /// copy from either a map buffer or the stack. + /// + /// Unlike [`reserve`], this function can handle dynamically sized types (which is hard to + /// create in eBPF but still possible, e.g. by slicing an array). + /// + /// Note: `T` must be aligned to no more than 8 bytes; it's not possible to fulfill larger + /// alignment requests. If you use this with a `T` that isn't properly aligned, this function will + /// be compiled to a panic and silently make your eBPF program fail to load. + /// See [here](https://github.com/torvalds/linux/blob/3f01e9fed/kernel/bpf/ringbuf.c#L418). + /// + /// [`reserve`]: RingBuf::reserve + /// [`submit`]: RingBufEntry::submit + pub fn output(&self, data: &T, flags: u64) -> Result<(), i64> { + assert_eq!(8 % mem::align_of_val(data), 0); + let ret = unsafe { + bpf_ringbuf_output( + self.def.get() as *mut _, + data as *const _ as *mut _, + mem::size_of_val(data) as _, + flags, + ) + }; + if ret < 0 { + Err(ret) + } else { + Ok(()) + } + } + + /// Query various information about the ring buffer. + /// + /// Consult `bpf_ringbuf_query` documentation for a list of allowed flags. + pub fn query(&self, flags: u64) -> u64 { + unsafe { bpf_ringbuf_query(self.def.get() as *mut _, flags) } + } +} diff --git a/bpf/aya-bpf/src/maps/xdp/cpu_map.rs b/bpf/aya-bpf/src/maps/xdp/cpu_map.rs new file mode 100644 index 00000000..0ada7010 --- /dev/null +++ b/bpf/aya-bpf/src/maps/xdp/cpu_map.rs @@ -0,0 +1,119 @@ +use core::{cell::UnsafeCell, mem}; + +use aya_bpf_bindings::bindings::bpf_cpumap_val; + +use super::try_redirect_map; +use crate::{ + bindings::{bpf_map_def, bpf_map_type::BPF_MAP_TYPE_CPUMAP}, + maps::PinningType, +}; + +/// An array of available CPUs. +/// +/// XDP programs can use this map to redirect packets to a target CPU for processing. +/// +/// # Minimum kernel version +/// +/// The minimum kernel version required to use this feature is 4.15. +/// +/// # Examples +/// +/// ```rust,no_run +/// use aya_bpf::{bindings::xdp_action, macros::{map, xdp}, maps::CpuMap, programs::XdpContext}; +/// +/// #[map] +/// static MAP: CpuMap = CpuMap::with_max_entries(8, 0); +/// +/// #[xdp] +/// fn xdp(_ctx: XdpContext) -> i32 { +/// // Redirect to CPU 7 or drop packet if no entry found. +/// MAP.redirect(7, xdp_action::XDP_DROP as u64) +/// } +/// ``` +#[repr(transparent)] +pub struct CpuMap { + def: UnsafeCell, +} + +unsafe impl Sync for CpuMap {} + +impl CpuMap { + /// Creates a [`CpuMap`] with a set maximum number of elements. + /// + /// In a CPU map, an entry represents a CPU core. Thus there should be as many entries as there + /// are CPU cores on the system. `max_entries` can be set to zero here, and updated by userspace + /// at runtime. Refer to the userspace documentation for more information. + /// + /// # Examples + /// + /// ```rust,no_run + /// use aya_bpf::{macros::map, maps::CpuMap}; + /// + /// #[map] + /// static MAP: CpuMap = CpuMap::with_max_entries(8, 0); + /// ``` + pub const fn with_max_entries(max_entries: u32, flags: u32) -> CpuMap { + CpuMap { + def: UnsafeCell::new(bpf_map_def { + type_: BPF_MAP_TYPE_CPUMAP, + key_size: mem::size_of::() as u32, + value_size: mem::size_of::() as u32, + max_entries, + map_flags: flags, + id: 0, + pinning: PinningType::None as u32, + }), + } + } + + /// Creates a [`CpuMap`] with a set maximum number of elements that can be pinned to the BPF + /// File System (bpffs). + /// + /// See [`CpuMap::with_max_entries`] for more information. + /// + /// # Examples + /// + /// ```rust,no_run + /// use aya_bpf::{macros::map, maps::CpuMap}; + /// + /// #[map] + /// static MAP: CpuMap = CpuMap::pinned(8, 0); + /// ``` + pub const fn pinned(max_entries: u32, flags: u32) -> CpuMap { + CpuMap { + def: UnsafeCell::new(bpf_map_def { + type_: BPF_MAP_TYPE_CPUMAP, + key_size: mem::size_of::() as u32, + value_size: mem::size_of::() as u32, + max_entries, + map_flags: flags, + id: 0, + pinning: PinningType::ByName as u32, + }), + } + } + + /// Redirects the current packet on the CPU at `index`. + /// + /// The lower two bits of `flags` are used for the return code if the map lookup fails, which + /// can be used as the XDP program's return code if a CPU cannot be found. + /// + /// # Examples + /// + /// ```rust,no_run + /// use aya_bpf::{bindings::xdp_action, macros::{map, xdp}, maps::CpuMap, programs::XdpContext}; + /// + /// #[map] + /// static MAP: CpuMap = CpuMap::with_max_entries(8, 0); + /// + /// #[xdp] + /// fn xdp(_ctx: XdpContext) -> u32 { + /// // Redirect to CPU 7 or drop packet if no entry found. + /// MAP.redirect(7, 0).unwrap_or(xdp_action::XDP_DROP) + /// } + /// ``` + #[inline(always)] + pub fn redirect(&self, index: u32, flags: u64) -> Result { + try_redirect_map(&self.def, index, flags) + } +} diff --git a/bpf/aya-bpf/src/maps/xdp/dev_map.rs b/bpf/aya-bpf/src/maps/xdp/dev_map.rs new file mode 100644 index 00000000..d7e62dd0 --- /dev/null +++ b/bpf/aya-bpf/src/maps/xdp/dev_map.rs @@ -0,0 +1,154 @@ +use core::{cell::UnsafeCell, mem, num::NonZeroU32, ptr::NonNull}; + +use aya_bpf_bindings::bindings::bpf_devmap_val; +use aya_bpf_cty::c_void; + +use super::try_redirect_map; +use crate::{ + bindings::{bpf_map_def, bpf_map_type::BPF_MAP_TYPE_DEVMAP}, + helpers::bpf_map_lookup_elem, + maps::PinningType, +}; + +/// An array of network devices. +/// +/// XDP programs can use this map to redirect packets to other network deviecs. +/// +/// # Minimum kernel version +/// +/// The minimum kernel version required to use this feature is 4.14. +/// +/// # Examples +/// +/// ```rust,no_run +/// use aya_bpf::{bindings::xdp_action, macros::{map, xdp}, maps::DevMap, programs::XdpContext}; +/// +/// #[map] +/// static MAP: DevMap = DevMap::with_max_entries(1, 0); +/// +/// #[xdp] +/// fn xdp(_ctx: XdpContext) -> i32 { +/// MAP.redirect(0, xdp_action::XDP_PASS as u64) +/// } +/// ``` +#[repr(transparent)] +pub struct DevMap { + def: UnsafeCell, +} + +unsafe impl Sync for DevMap {} + +impl DevMap { + /// Creates a [`DevMap`] with a set maximum number of elements. + /// + /// # Examples + /// + /// ```rust,no_run + /// use aya_bpf::{macros::map, maps::DevMap}; + /// + /// #[map] + /// static MAP: DevMap = DevMap::with_max_entries(8, 0); + /// ``` + pub const fn with_max_entries(max_entries: u32, flags: u32) -> DevMap { + DevMap { + def: UnsafeCell::new(bpf_map_def { + type_: BPF_MAP_TYPE_DEVMAP, + key_size: mem::size_of::() as u32, + value_size: mem::size_of::() as u32, + max_entries, + map_flags: flags, + id: 0, + pinning: PinningType::None as u32, + }), + } + } + + /// Creates a [`DevMap`] with a set maximum number of elements that can be pinned to the BPF + /// File System (bpffs). + /// + /// # Examples + /// + /// ```rust,no_run + /// use aya_bpf::{macros::map, maps::DevMap}; + /// + /// #[map] + /// static MAP: DevMap = DevMap::pinned(8, 0); + /// ``` + pub const fn pinned(max_entries: u32, flags: u32) -> DevMap { + DevMap { + def: UnsafeCell::new(bpf_map_def { + type_: BPF_MAP_TYPE_DEVMAP, + key_size: mem::size_of::() as u32, + value_size: mem::size_of::() as u32, + max_entries, + map_flags: flags, + id: 0, + pinning: PinningType::ByName as u32, + }), + } + } + + /// Retrieves the interface index at `index` in the array. + /// + /// To actually redirect a packet, see [`DevMap::redirect`]. + /// + /// # Examples + /// + /// ```rust,no_run + /// use aya_bpf::{macros::map, maps::DevMap}; + /// + /// #[map] + /// static MAP: DevMap = DevMap::with_max_entries(1, 0); + /// + /// let target_if_index = MAP.get(0).target_if_index; + /// + /// // redirect to if_index + /// ``` + #[inline(always)] + pub fn get(&self, index: u32) -> Option { + unsafe { + let value = bpf_map_lookup_elem( + self.def.get() as *mut _, + &index as *const _ as *const c_void, + ); + NonNull::new(value as *mut bpf_devmap_val).map(|p| DevMapValue { + if_index: p.as_ref().ifindex, + // SAFETY: map writes use fd, map reads use id. + // https://elixir.bootlin.com/linux/v6.2/source/include/uapi/linux/bpf.h#L6136 + prog_id: NonZeroU32::new(p.as_ref().bpf_prog.id), + }) + } + } + + /// Redirects the current packet on the interface at `index`. + /// + /// The lower two bits of `flags` are used for the return code if the map lookup fails, which + /// can be used as the XDP program's return code if a CPU cannot be found. + /// + /// # Examples + /// + /// ```rust,no_run + /// use aya_bpf::{bindings::xdp_action, macros::{map, xdp}, maps::DevMap, programs::XdpContext}; + /// + /// #[map] + /// static MAP: DevMap = DevMap::with_max_entries(8, 0); + /// + /// #[xdp] + /// fn xdp(_ctx: XdpContext) -> u32 { + /// MAP.redirect(7, 0).unwrap_or(xdp_action::XDP_DROP) + /// } + /// ``` + #[inline(always)] + pub fn redirect(&self, index: u32, flags: u64) -> Result { + try_redirect_map(&self.def, index, flags) + } +} + +#[derive(Clone, Copy)] +/// The value of a device map. +pub struct DevMapValue { + /// Target interface index to redirect to. + pub if_index: u32, + /// Chained XDP program ID. + pub prog_id: Option, +} diff --git a/bpf/aya-bpf/src/maps/xdp/dev_map_hash.rs b/bpf/aya-bpf/src/maps/xdp/dev_map_hash.rs new file mode 100644 index 00000000..809215aa --- /dev/null +++ b/bpf/aya-bpf/src/maps/xdp/dev_map_hash.rs @@ -0,0 +1,145 @@ +use core::{cell::UnsafeCell, mem, num::NonZeroU32, ptr::NonNull}; + +use aya_bpf_bindings::bindings::bpf_devmap_val; +use aya_bpf_cty::c_void; + +use super::{dev_map::DevMapValue, try_redirect_map}; +use crate::{ + bindings::{bpf_map_def, bpf_map_type::BPF_MAP_TYPE_DEVMAP_HASH}, + helpers::bpf_map_lookup_elem, + maps::PinningType, +}; + +/// A map of network devices. +/// +/// XDP programs can use this map to redirect packets to other network devices. It is similar to +/// [`DevMap`](super::DevMap), but is an hash map rather than an array. Keys do not need to be +/// contiguous nor start at zero, but there is a hashing cost to every lookup. +/// +/// # Minimum kernel version +/// +/// The minimum kernel version required to use this feature is 5.4. +/// +/// # Examples +/// +/// ```rust,no_run +/// use aya_bpf::{bindings::xdp_action, macros::{map, xdp}, maps::DevMapHash, programs::XdpContext}; +/// +/// #[map] +/// static MAP: DevMapHash = DevMapHash::with_max_entries(1, 0); +/// +/// #[xdp] +/// fn xdp(_ctx: XdpContext) -> i32 { +/// MAP.redirect(42, xdp_action::XDP_PASS as u64) +/// } +/// ``` +#[repr(transparent)] +pub struct DevMapHash { + def: UnsafeCell, +} + +unsafe impl Sync for DevMapHash {} + +impl DevMapHash { + /// Creates a [`DevMapHash`] with a set maximum number of elements. + /// + /// # Examples + /// + /// ```rust,no_run + /// use aya_bpf::{macros::map, maps::DevMapHash}; + /// + /// #[map] + /// static MAP: DevMapHash = DevMapHash::with_max_entries(8, 0); + /// ``` + pub const fn with_max_entries(max_entries: u32, flags: u32) -> DevMapHash { + DevMapHash { + def: UnsafeCell::new(bpf_map_def { + type_: BPF_MAP_TYPE_DEVMAP_HASH, + key_size: mem::size_of::() as u32, + value_size: mem::size_of::() as u32, + max_entries, + map_flags: flags, + id: 0, + pinning: PinningType::None as u32, + }), + } + } + + /// Creates a [`DevMapHash`] with a set maximum number of elements that can be pinned to the BPF + /// File System (bpffs). + /// + /// # Examples + /// + /// ```rust,no_run + /// use aya_bpf::{macros::map, maps::DevMapHash}; + /// + /// #[map] + /// static MAP: DevMapHash = DevMapHash::pinned(8, 0); + /// ``` + pub const fn pinned(max_entries: u32, flags: u32) -> DevMapHash { + DevMapHash { + def: UnsafeCell::new(bpf_map_def { + type_: BPF_MAP_TYPE_DEVMAP_HASH, + key_size: mem::size_of::() as u32, + value_size: mem::size_of::() as u32, + max_entries, + map_flags: flags, + id: 0, + pinning: PinningType::ByName as u32, + }), + } + } + + /// Retrieves the interface index with `key` in the map. + /// + /// To actually redirect a packet, see [`DevMapHash::redirect`]. + /// + /// # Examples + /// + /// ```rust,no_run + /// use aya_bpf::{macros::map, maps::DevMapHash}; + /// + /// #[map] + /// static MAP: DevMapHash = DevMapHash::with_max_entries(1, 0); + /// + /// let target_if_index = MAP.get(42).target_if_index; + /// + /// // redirect to ifindex + /// ``` + #[inline(always)] + pub fn get(&self, key: u32) -> Option { + unsafe { + let value = + bpf_map_lookup_elem(self.def.get() as *mut _, &key as *const _ as *const c_void); + NonNull::new(value as *mut bpf_devmap_val).map(|p| DevMapValue { + if_index: p.as_ref().ifindex, + // SAFETY: map writes use fd, map reads use id. + // https://elixir.bootlin.com/linux/v6.2/source/include/uapi/linux/bpf.h#L6136 + prog_id: NonZeroU32::new(p.as_ref().bpf_prog.id), + }) + } + } + + /// Redirects the current packet on the interface at `key`. + /// + /// The lower two bits of `flags` are used for the return code if the map lookup fails, which + /// can be used as the XDP program's return code if a CPU cannot be found. + /// + /// # Examples + /// + /// ```rust,no_run + /// use aya_bpf::{bindings::xdp_action, macros::{map, xdp}, maps::DevMapHash, programs::XdpContext}; + /// + /// #[map] + /// static MAP: DevMapHash = DevMapHash::with_max_entries(8, 0); + /// + /// #[xdp] + /// fn xdp(_ctx: XdpContext) -> u32 { + /// MAP.redirect(7, 0).unwrap_or(xdp_action::XDP_DROP) + /// } + /// ``` + #[inline(always)] + pub fn redirect(&self, key: u32, flags: u64) -> Result { + try_redirect_map(&self.def, key, flags) + } +} diff --git a/bpf/aya-bpf/src/maps/xdp/mod.rs b/bpf/aya-bpf/src/maps/xdp/mod.rs new file mode 100644 index 00000000..5c8df0e5 --- /dev/null +++ b/bpf/aya-bpf/src/maps/xdp/mod.rs @@ -0,0 +1,33 @@ +mod cpu_map; +mod dev_map; +mod dev_map_hash; +mod xsk_map; + +use core::cell::UnsafeCell; + +use aya_bpf_bindings::{ + bindings::{bpf_map_def, xdp_action::XDP_REDIRECT}, + helpers::bpf_redirect_map, +}; +pub use cpu_map::CpuMap; +pub use dev_map::DevMap; +pub use dev_map_hash::DevMapHash; +pub use xsk_map::XskMap; + +/// Wrapper aroung the `bpf_redirect_map` function. +/// +/// # Return value +/// +/// - `Ok(XDP_REDIRECT)` on success. +/// - `Err(_)` of the lowest two bits of `flags` on failure. +#[inline(always)] +fn try_redirect_map(def: &UnsafeCell, key: u32, flags: u64) -> Result { + // Return XDP_REDIRECT on success, or the value of the two lower bits of the flags argument on + // error. Thus I have no idea why it returns a long (i64) instead of something saner, hence the + // unsigned_abs. + let ret = unsafe { bpf_redirect_map(def.get() as *mut _, key.into(), flags) }; + match ret.unsigned_abs() as u32 { + XDP_REDIRECT => Ok(XDP_REDIRECT), + ret => Err(ret), + } +} diff --git a/bpf/aya-bpf/src/maps/xdp/xsk_map.rs b/bpf/aya-bpf/src/maps/xdp/xsk_map.rs new file mode 100644 index 00000000..934785c1 --- /dev/null +++ b/bpf/aya-bpf/src/maps/xdp/xsk_map.rs @@ -0,0 +1,163 @@ +use core::{cell::UnsafeCell, mem, ptr::NonNull}; + +use aya_bpf_bindings::bindings::bpf_xdp_sock; +use aya_bpf_cty::c_void; + +use super::try_redirect_map; +use crate::{ + bindings::{bpf_map_def, bpf_map_type::BPF_MAP_TYPE_XSKMAP}, + helpers::bpf_map_lookup_elem, + maps::PinningType, +}; + +/// An array of AF_XDP sockets. +/// +/// XDP programs can use this map to redirect packets to a target AF_XDP socket using the +/// `XDP_REDIRECT` action. +/// +/// # Minimum kernel version +/// +/// The minimum kernel version required to use this feature is 4.18. +/// +/// # Examples +/// +/// ```rust,no_run +/// use aya_bpf::{bindings::xdp_action, macros::{map, xdp}, maps::XskMap, programs::XdpContext}; +/// +/// #[map] +/// static SOCKS: XskMap = XskMap::with_max_entries(8, 0); +/// +/// #[xdp] +/// fn xdp(ctx, XdpContext) -> i32 { +/// let queue_id = unsafe { (*ctx.ctx).rx_queue_index }; +/// MAP.redirect(queue_id, xdp_action::XDP_DROP as u64) +/// } +/// ``` +/// +/// # Queue management +/// +/// Packets received on a RX queue can only be redirected to sockets bound on the same queue. Most +/// hardware NICs have multiple RX queue to spread the load across multiple CPU cores using RSS. +/// +/// Three strategies are possible: +/// +/// - Reduce the RX queue count to a single one. This option is great for development, but is +/// detrimental for performance as the single CPU core recieving packets will get overwhelmed. +/// Setting the queue count for a NIC can be achieved using `ethtool -L combined 1`. +/// - Create a socket for every RX queue. Most modern NICs will have an RX queue per CPU thread, so +/// a socket per CPU thread is best for performance. To dynamically size the map depending on the +/// recieve queue count, see the userspace documentation of `CpuMap`. +/// - Create a single socket and use a [`CpuMap`](super::CpuMap) to redirect the packet to the +/// correct CPU core. This way, the packet is sent to another CPU, and a chained XDP program can +/// the redirect to the AF_XDP socket. Using a single socket simplifies the userspace code but +/// will not perform great unless not a lot of traffic is redirected to the socket. Regular +/// traffic however will not be impacted, contrary to reducing the queue count. +#[repr(transparent)] +pub struct XskMap { + def: UnsafeCell, +} + +unsafe impl Sync for XskMap {} + +impl XskMap { + /// Creates a [`XskMap`] with a set maximum number of elements. + /// + /// # Examples + /// + /// ```rust,no_run + /// use aya_bpf::{macros::map, maps::XskMap}; + /// + /// #[map] + /// static SOCKS: XskMap::with_max_entries(8, 0); + /// ``` + pub const fn with_max_entries(max_entries: u32, flags: u32) -> XskMap { + XskMap { + def: UnsafeCell::new(bpf_map_def { + type_: BPF_MAP_TYPE_XSKMAP, + key_size: mem::size_of::() as u32, + value_size: mem::size_of::() as u32, + max_entries, + map_flags: flags, + id: 0, + pinning: PinningType::None as u32, + }), + } + } + + /// Creates a [`XskMap`] with a set maximum number of elements that can be pinned to the BPF + /// filesystem (bpffs). + /// + /// # Examples + /// + /// ```rust,no_run + /// use aya_bpf::{macros::map, maps::XskMap}; + /// + /// #[map] + /// static SOCKS: XskMap::pinned(8, 0); + /// ``` + pub const fn pinned(max_entries: u32, flags: u32) -> XskMap { + XskMap { + def: UnsafeCell::new(bpf_map_def { + type_: BPF_MAP_TYPE_XSKMAP, + key_size: mem::size_of::() as u32, + value_size: mem::size_of::() as u32, + max_entries, + map_flags: flags, + id: 0, + pinning: PinningType::ByName as u32, + }), + } + } + + /// Retrieves the queue to which the socket is bound at `index` in the array. + /// + /// To actually redirect a packet, see [`XskMap::redirect`]. + /// + /// # Examples + /// + /// ```rust,no_run + /// use aya_bpf::{macros::map, maps::XskMap}; + /// + /// #[map] + /// static SOCKS: XskMap = XskMap::with_max_entries(8, 0); + /// + /// let queue_id = SOCKS.get(0); + /// ``` + #[inline(always)] + pub fn get(&self, index: u32) -> Option { + unsafe { + let value = bpf_map_lookup_elem( + self.def.get() as *mut _, + &index as *const _ as *const c_void, + ); + NonNull::new(value as *mut bpf_xdp_sock).map(|p| p.as_ref().queue_id) + } + } + + /// Redirects the current packet to the AF_XDP socket at `index`. + /// + /// The lower two bits of `flags` are used for the return code if the map lookup fails, which + /// can be used as the XDP program's return code if a matching socket cannot be found. + /// + /// However, if the socket at `index` is bound to a RX queue which is not the current RX queue, + /// the packet will be dropped. + /// + /// # Examples + /// + /// ```rust,no_run + /// use aya_bpf::{bindings::xdp_action, macros::{map, xdp}, maps::XskMap, programs::XdpContext}; + /// + /// #[map] + /// static SOCKS: XskMap = XskMap::with_max_entries(8, 0); + /// + /// #[xdp] + /// fn xdp(ctx, XdpContext) -> u32 { + /// let queue_id = unsafe { (*ctx.ctx).rx_queue_index }; + /// MAP.redirect(queue_id, 0).unwrap_or(xdp_action::XDP_DROP) + /// } + /// ``` + #[inline(always)] + pub fn redirect(&self, index: u32, flags: u64) -> Result { + try_redirect_map(&self.def, index, flags) + } +} diff --git a/bpf/aya-bpf/src/programs/perf_event.rs b/bpf/aya-bpf/src/programs/perf_event.rs index d24ed737..f303b28d 100644 --- a/bpf/aya-bpf/src/programs/perf_event.rs +++ b/bpf/aya-bpf/src/programs/perf_event.rs @@ -1,6 +1,7 @@ -use crate::BpfContext; use core::ffi::c_void; +use crate::BpfContext; + pub struct PerfEventContext { ctx: *mut c_void, } diff --git a/bpf/aya-bpf/src/programs/probe.rs b/bpf/aya-bpf/src/programs/probe.rs index 25694845..9566c814 100644 --- a/bpf/aya-bpf/src/programs/probe.rs +++ b/bpf/aya-bpf/src/programs/probe.rs @@ -1,15 +1,12 @@ use core::ffi::c_void; -use crate::{args::FromPtRegs, BpfContext}; - #[cfg(not(any(bpf_target_arch = "aarch64", bpf_target_arch = "riscv64")))] use crate::bindings::pt_regs; - #[cfg(bpf_target_arch = "aarch64")] use crate::bindings::user_pt_regs as pt_regs; - #[cfg(bpf_target_arch = "riscv64")] use crate::bindings::user_regs_struct as pt_regs; +use crate::{args::FromPtRegs, BpfContext}; pub struct ProbeContext { pub regs: *mut pt_regs, diff --git a/bpf/aya-bpf/src/programs/tracepoint.rs b/bpf/aya-bpf/src/programs/tracepoint.rs index 29db68b4..4087b7b8 100644 --- a/bpf/aya-bpf/src/programs/tracepoint.rs +++ b/bpf/aya-bpf/src/programs/tracepoint.rs @@ -1,6 +1,7 @@ -use crate::{helpers::bpf_probe_read, BpfContext}; use core::ffi::c_void; +use crate::{helpers::bpf_probe_read, BpfContext}; + pub struct TracePointContext { ctx: *mut c_void, } diff --git a/rustfmt.toml b/rustfmt.toml index 1cdefeb0..53f7b6d7 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,3 +1,4 @@ -unstable_features = true -reorder_imports = true +group_imports = "StdExternalCrate" imports_granularity = "Crate" +reorder_imports = true +unstable_features = true diff --git a/test/README.md b/test/README.md index 82e41da0..5a0db31b 100644 --- a/test/README.md +++ b/test/README.md @@ -1,5 +1,4 @@ -Aya Integration Tests -===================== +# Aya Integration Tests The aya integration test suite is a set of tests to ensure that common usage behaviours work on real Linux distros @@ -19,13 +18,13 @@ From the root of this repository: ### Native -``` +```bash cargo xtask integration-test local ``` ### Virtualized -``` +```bash cargo xtask integration-test vm ``` @@ -41,5 +40,5 @@ Tests should follow these guidelines: constants in `integration-test/src/lib.rs` using `include_bytes_aligned!`. - Tests should be added to `integration-test/tests`. - You may add a new module, or use an existing one. -- Test functions should not return `anyhow::Result<()>` since this produces errors without stack - traces. Prefer to `panic!` instead. +- Test functions should not return `anyhow::Result<()>` since this produces + errors without stack traces. Prefer to `panic!` instead. diff --git a/test/integration-ebpf/Cargo.toml b/test/integration-ebpf/Cargo.toml index 6994cac1..eb6615b2 100644 --- a/test/integration-ebpf/Cargo.toml +++ b/test/integration-ebpf/Cargo.toml @@ -9,6 +9,7 @@ aya-bpf = { path = "../../bpf/aya-bpf" } aya-log-ebpf = { path = "../../bpf/aya-log-ebpf" } [build-dependencies] +which = { workspace = true } xtask = { path = "../../xtask" } [[bin]] @@ -46,3 +47,15 @@ path = "src/two_progs.rs" [[bin]] name = "tc_name_limit" path = "src/tc_name_limit.rs" + +[[bin]] +name = "redirect" +path = "src/redirect.rs" + +[[bin]] +name = "xdp_sec" +path = "src/xdp_sec.rs" + +[[bin]] +name = "ring_buf" +path = "src/ring_buf.rs" diff --git a/test/integration-ebpf/build.rs b/test/integration-ebpf/build.rs index dd4a6501..d339e195 100644 --- a/test/integration-ebpf/build.rs +++ b/test/integration-ebpf/build.rs @@ -1,6 +1,7 @@ -use std::{env, path::PathBuf}; +use std::env; -use xtask::{create_symlink_to_binary, AYA_BUILD_INTEGRATION_BPF}; +use which::which; +use xtask::AYA_BUILD_INTEGRATION_BPF; /// Building this crate has an undeclared dependency on the `bpf-linker` binary. This would be /// better expressed by [artifact-dependencies][bindeps] but issues such as @@ -24,12 +25,7 @@ fn main() { .unwrap_or_default(); if build_integration_bpf { - let out_dir = env::var_os("OUT_DIR").unwrap(); - let out_dir = PathBuf::from(out_dir); - let bpf_linker_symlink = create_symlink_to_binary(&out_dir, "bpf-linker").unwrap(); - println!( - "cargo:rerun-if-changed={}", - bpf_linker_symlink.to_str().unwrap() - ); + let bpf_linker = which("bpf-linker").unwrap(); + println!("cargo:rerun-if-changed={}", bpf_linker.to_str().unwrap()); } } diff --git a/test/integration-ebpf/src/bpf_probe_read.rs b/test/integration-ebpf/src/bpf_probe_read.rs index 02728767..d86a6bba 100644 --- a/test/integration-ebpf/src/bpf_probe_read.rs +++ b/test/integration-ebpf/src/bpf_probe_read.rs @@ -10,47 +10,47 @@ use aya_bpf::{ const RESULT_BUF_LEN: usize = 1024; -macro_rules! read_str_bytes { - ($fun:ident, $ptr:expr, $len:expr $(,)?) => { - let Some(ptr) = RESULT.get_ptr_mut(0) else { - return; - }; - let TestResult { - did_error, - len, - buf, - } = unsafe { &mut *ptr }; - - // $len comes from ctx.arg(1) so it's dynamic and the verifier - // doesn't see any bounds. We do $len.min(RESULT_BUF_LEN) here to - // ensure that the verifier can see the upper bound, or you get: - // - // 18: (79) r7 = *(u64 *)(r7 +8) ; R7_w=scalar() - // [snip] - // 27: (bf) r2 = r7 ; - // R2_w=scalar(id=2,umax=9223372036854775807,var_off=(0x0; 0x7fffffffffffffff)) [snip] - // 28: (85) call bpf_probe_read_user_str#114 - // R2 unbounded memory access, use 'var &= const' or 'if (var < const)' - let Some(buf) = buf.get_mut(..$len) else { - return; - }; +fn read_str_bytes( + fun: unsafe fn(*const u8, &mut [u8]) -> Result<&[u8], i64>, + iptr: Option<*const u8>, + ilen: Option, +) { + let Some(iptr) = iptr else { + return; + }; + let Some(ilen) = ilen else { + return; + }; + let Some(ptr) = RESULT.get_ptr_mut(0) else { + return; + }; + let dst = unsafe { ptr.as_mut() }; + let Some(TestResult { buf, len }) = dst else { + return; + }; + *len = None; - match unsafe { $fun($ptr, buf) } { - Ok(s) => { - *len = s.len(); - } - Err(_) => { - *did_error = 1; - } - } + // len comes from ctx.arg(1) so it's dynamic and the verifier + // doesn't see any bounds. We do len.min(RESULT_BUF_LEN) here to + // ensure that the verifier can see the upper bound, or you get: + // + // 18: (79) r7 = *(u64 *)(r7 +8) ; R7_w=scalar() + // [snip] + // 27: (bf) r2 = r7 ; + // R2_w=scalar(id=2,umax=9223372036854775807,var_off=(0x0; 0x7fffffffffffffff)) [snip] + // 28: (85) call bpf_probe_read_user_str#114 + // R2 unbounded memory access, use 'var &= const' or 'if (var < const)' + let Some(buf) = buf.get_mut(..ilen) else { + return; }; + + *len = Some(unsafe { fun(iptr, buf) }.map(<[_]>::len)); } #[repr(C)] struct TestResult { - did_error: u64, - len: usize, buf: [u8; RESULT_BUF_LEN], + len: Option>, } #[map] @@ -61,31 +61,22 @@ static KERNEL_BUFFER: Array<[u8; RESULT_BUF_LEN]> = Array::with_max_entries(1, 0 #[uprobe] pub fn test_bpf_probe_read_user_str_bytes(ctx: ProbeContext) { - read_str_bytes!( + read_str_bytes( bpf_probe_read_user_str_bytes, - match ctx.arg::<*const u8>(0) { - Some(p) => p, - _ => return, - }, - match ctx.arg::(1) { - Some(p) => p, - _ => return, - }, + ctx.arg::<*const u8>(0), + ctx.arg::(1), ); } #[uprobe] pub fn test_bpf_probe_read_kernel_str_bytes(ctx: ProbeContext) { - read_str_bytes!( + read_str_bytes( bpf_probe_read_kernel_str_bytes, - match KERNEL_BUFFER.get_ptr(0) { - Some(p) => p as *const u8, - _ => return, - }, - match ctx.arg::(0) { - Some(p) => p, - _ => return, - }, + KERNEL_BUFFER + .get_ptr(0) + .and_then(|ptr| unsafe { ptr.as_ref() }) + .map(|buf| buf.as_ptr()), + ctx.arg::(0), ); } diff --git a/test/integration-ebpf/src/log.rs b/test/integration-ebpf/src/log.rs index 51c1a46d..8b82f657 100644 --- a/test/integration-ebpf/src/log.rs +++ b/test/integration-ebpf/src/log.rs @@ -26,6 +26,11 @@ pub fn test_log(ctx: ProbeContext) { warn!(&ctx, "hex lc: {:x}, hex uc: {:X}", hex, hex); let hex = [0xde, 0xad, 0xbe, 0xef].as_slice(); debug!(&ctx, "hex lc: {:x}, hex uc: {:X}", hex, hex); + let len = 42; + let size = 43; + let slice = 44; + let record = 45; + debug!(&ctx, "{} {} {} {}", len, size, slice, record); // Testing compilation only. if false { diff --git a/test/integration-ebpf/src/redirect.rs b/test/integration-ebpf/src/redirect.rs new file mode 100644 index 00000000..41812cd0 --- /dev/null +++ b/test/integration-ebpf/src/redirect.rs @@ -0,0 +1,73 @@ +#![no_std] +#![no_main] + +use aya_bpf::{ + bindings::xdp_action, + macros::{map, xdp}, + maps::{Array, CpuMap, DevMap, DevMapHash, XskMap}, + programs::XdpContext, +}; + +#[map] +static SOCKS: XskMap = XskMap::with_max_entries(1, 0); +#[map] +static DEVS: DevMap = DevMap::with_max_entries(1, 0); +#[map] +static DEVS_HASH: DevMapHash = DevMapHash::with_max_entries(1, 0); +#[map] +static CPUS: CpuMap = CpuMap::with_max_entries(1, 0); + +/// Hits of a probe, used to test program chaining through CpuMap/DevMap. +/// The first slot counts how many times the "raw" xdp program got executed, while the second slot +/// counts how many times the map programs got executed. +/// This allows the test harness to assert that a specific step got executed. +#[map] +static mut HITS: Array = Array::with_max_entries(2, 0); + +#[xdp] +pub fn redirect_sock(_ctx: XdpContext) -> u32 { + SOCKS.redirect(0, 0).unwrap_or(xdp_action::XDP_ABORTED) +} + +#[xdp] +pub fn redirect_dev(_ctx: XdpContext) -> u32 { + inc_hit(0); + DEVS.redirect(0, 0).unwrap_or(xdp_action::XDP_ABORTED) +} + +#[xdp] +pub fn redirect_dev_hash(_ctx: XdpContext) -> u32 { + inc_hit(0); + DEVS_HASH.redirect(10, 0).unwrap_or(xdp_action::XDP_ABORTED) +} + +#[xdp] +pub fn redirect_cpu(_ctx: XdpContext) -> u32 { + inc_hit(0); + CPUS.redirect(0, 0).unwrap_or(xdp_action::XDP_ABORTED) +} + +#[xdp(map = "cpumap")] +pub fn redirect_cpu_chain(_ctx: XdpContext) -> u32 { + inc_hit(1); + xdp_action::XDP_PASS +} + +#[xdp(map = "devmap")] +pub fn redirect_dev_chain(_ctx: XdpContext) -> u32 { + inc_hit(1); + xdp_action::XDP_PASS +} + +#[inline(always)] +fn inc_hit(index: u32) { + if let Some(hit) = unsafe { HITS.get_ptr_mut(index) } { + unsafe { *hit += 1 }; + } +} + +#[cfg(not(test))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/test/integration-ebpf/src/ring_buf.rs b/test/integration-ebpf/src/ring_buf.rs new file mode 100644 index 00000000..ff9a21a0 --- /dev/null +++ b/test/integration-ebpf/src/ring_buf.rs @@ -0,0 +1,59 @@ +#![no_std] +#![no_main] + +use aya_bpf::{ + macros::{map, uprobe}, + maps::{PerCpuArray, RingBuf}, + programs::ProbeContext, +}; + +#[map] +static RING_BUF: RingBuf = RingBuf::with_byte_size(0, 0); + +// This structure's definition is duplicated in userspace. +#[repr(C)] +struct Registers { + dropped: u64, + rejected: u64, +} + +// Use a PerCpuArray to store the registers so that we can update the values from multiple CPUs +// without needing synchronization. Atomics exist [1], but aren't exposed. +// +// [1]: https://lwn.net/Articles/838884/ +#[map] +static REGISTERS: PerCpuArray = PerCpuArray::with_max_entries(1, 0); + +#[uprobe] +pub fn ring_buf_test(ctx: ProbeContext) { + let Registers { dropped, rejected } = match REGISTERS.get_ptr_mut(0) { + Some(regs) => unsafe { &mut *regs }, + None => return, + }; + let mut entry = match RING_BUF.reserve::(0) { + Some(entry) => entry, + None => { + *dropped += 1; + return; + } + }; + // Write the first argument to the function back out to RING_BUF if it is even, + // otherwise increment the counter in REJECTED. This exercises discarding data. + let arg: u64 = match ctx.arg(0) { + Some(arg) => arg, + None => return, + }; + if arg % 2 == 0 { + entry.write(arg); + entry.submit(0); + } else { + *rejected += 1; + entry.discard(0); + } +} + +#[cfg(not(test))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/test/integration-ebpf/src/xdp_sec.rs b/test/integration-ebpf/src/xdp_sec.rs new file mode 100644 index 00000000..5e64f56a --- /dev/null +++ b/test/integration-ebpf/src/xdp_sec.rs @@ -0,0 +1,26 @@ +#![no_std] +#![no_main] + +use aya_bpf::{bindings::xdp_action::XDP_PASS, macros::xdp, programs::XdpContext}; + +macro_rules! probe { + ($name:ident, ($($arg:ident $(= $value:literal)?),*) ) => { + #[xdp($($arg $(= $value)?),*)] + pub fn $name(_ctx: XdpContext) -> u32 { + XDP_PASS + } + }; +} + +probe!(xdp_plain, ()); +probe!(xdp_frags, (frags)); +probe!(xdp_cpumap, (map = "cpumap")); +probe!(xdp_devmap, (map = "devmap")); +probe!(xdp_frags_cpumap, (frags, map = "cpumap")); +probe!(xdp_frags_devmap, (frags, map = "devmap")); + +#[cfg(not(test))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/test/integration-test/Cargo.toml b/test/integration-test/Cargo.toml index 4d1a466b..36eedfef 100644 --- a/test/integration-test/Cargo.toml +++ b/test/integration-test/Cargo.toml @@ -10,13 +10,19 @@ assert_matches = { workspace = true } aya = { workspace = true } aya-log = { workspace = true } aya-obj = { workspace = true } +env_logger = { workspace = true } +epoll = { workspace = true } +futures = { workspace = true, features = ["std"] } libc = { workspace = true } log = { workspace = true } netns-rs = { workspace = true } -object = { workspace = true } +object = { workspace = true, features = ["elf", "read_core", "std"] } +rand = { workspace = true, features = ["std", "std_rng"] } rbpf = { workspace = true } test-case = { workspace = true } -tokio = { workspace = true, features = ["macros", "time"] } +test-log = { workspace = true, features = ["log"] } +tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] } +xdpilone = { workspace = true } [build-dependencies] cargo_metadata = { workspace = true } diff --git a/test/integration-test/bpf/multimap-btf.bpf.c b/test/integration-test/bpf/multimap-btf.bpf.c index 2bd7978b..9e595165 100644 --- a/test/integration-test/bpf/multimap-btf.bpf.c +++ b/test/integration-test/bpf/multimap-btf.bpf.c @@ -17,13 +17,24 @@ struct { __uint(max_entries, 1); } map_2 SEC(".maps"); -SEC("tracepoint") +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, __u32); + __type(value, __u64); + __uint(max_entries, 1); + __uint(pinning, LIBBPF_PIN_BY_NAME); +} map_pin_by_name SEC(".maps"); + +SEC("uprobe") int bpf_prog(void *ctx) { __u32 key = 0; __u64 twenty_four = 24; __u64 forty_two = 42; + __u64 forty_four = 44; + bpf_map_update_elem(&map_1, &key, &twenty_four, BPF_ANY); bpf_map_update_elem(&map_2, &key, &forty_two, BPF_ANY); + bpf_map_update_elem(&map_pin_by_name, &key, &forty_four, BPF_ANY); return 0; } diff --git a/test/integration-test/build.rs b/test/integration-test/build.rs index fec40483..1aee5fea 100644 --- a/test/integration-test/build.rs +++ b/test/integration-test/build.rs @@ -107,7 +107,7 @@ fn main() { } else if arch == "aarch64" { target_arch.push("arm64"); } else { - target_arch.push(arch); + target_arch.push(&arch); }; // NB: libbpf's documentation suggests that vmlinux.h be generated by running `bpftool btf @@ -198,6 +198,8 @@ fn main() { &target, ]); + cmd.env("CARGO_CFG_BPF_TARGET_ARCH", arch); + // Workaround to make sure that the rust-toolchain.toml is respected. for key in ["RUSTUP_TOOLCHAIN", "RUSTC"] { cmd.env_remove(key); diff --git a/test/integration-test/src/lib.rs b/test/integration-test/src/lib.rs index 4ef2b712..354c95a8 100644 --- a/test/integration-test/src/lib.rs +++ b/test/integration-test/src/lib.rs @@ -21,6 +21,9 @@ pub const RELOCATIONS: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), " pub const TWO_PROGS: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/two_progs")); pub const BPF_PROBE_READ: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/bpf_probe_read")); +pub const REDIRECT: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/redirect")); +pub const XDP_SEC: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/xdp_sec")); +pub const RING_BUF: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/ring_buf")); #[cfg(test)] mod tests; diff --git a/test/integration-test/src/tests.rs b/test/integration-test/src/tests.rs index dd8565b0..f37d54bb 100644 --- a/test/integration-test/src/tests.rs +++ b/test/integration-test/src/tests.rs @@ -5,4 +5,6 @@ mod load; mod log; mod rbpf; mod relocations; +mod ring_buf; mod smoke; +mod xdp; diff --git a/test/integration-test/src/tests/bpf_probe_read.rs b/test/integration-test/src/tests/bpf_probe_read.rs index bf91f271..5d7cf6ab 100644 --- a/test/integration-test/src/tests/bpf_probe_read.rs +++ b/test/integration-test/src/tests/bpf_probe_read.rs @@ -1,13 +1,13 @@ use aya::{maps::Array, programs::UProbe, Bpf}; +use test_log::test; const RESULT_BUF_LEN: usize = 1024; #[derive(Copy, Clone)] #[repr(C)] struct TestResult { - did_error: u64, - len: usize, buf: [u8; RESULT_BUF_LEN], + len: Option>, } unsafe impl aya::Pod for TestResult {} @@ -96,11 +96,12 @@ fn set_kernel_buffer_element(bpf: &mut Bpf, bytes: &[u8]) { #[track_caller] fn result_bytes(bpf: &Bpf) -> Vec { let m = Array::<_, TestResult>::try_from(bpf.map("RESULT").unwrap()).unwrap(); - let result = m.get(&0, 0).unwrap(); - assert_eq!(result.did_error, 0); + let TestResult { buf, len } = m.get(&0, 0).unwrap(); + let len = len.unwrap(); + let len = len.unwrap(); // assert that the buffer is always null terminated - assert_eq!(result.buf[result.len], 0); - result.buf[..result.len].to_vec() + assert_eq!(buf[len], 0); + buf[..len].to_vec() } fn load_and_attach_uprobe(prog_name: &str, func_name: &str, bytes: &[u8]) -> Bpf { diff --git a/test/integration-test/src/tests/btf_relocations.rs b/test/integration-test/src/tests/btf_relocations.rs index 79eb3e52..c149d43e 100644 --- a/test/integration-test/src/tests/btf_relocations.rs +++ b/test/integration-test/src/tests/btf_relocations.rs @@ -1,6 +1,5 @@ -use test_case::test_case; - use aya::{maps::Array, programs::UProbe, util::KernelVersion, BpfLoader, Btf, Endianness}; +use test_case::test_case; #[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)] diff --git a/test/integration-test/src/tests/elf.rs b/test/integration-test/src/tests/elf.rs index 9c68144f..3a5ad0a3 100644 --- a/test/integration-test/src/tests/elf.rs +++ b/test/integration-test/src/tests/elf.rs @@ -1,4 +1,5 @@ use object::{Object, ObjectSymbol}; +use test_log::test; #[test] fn test_maps() { diff --git a/test/integration-test/src/tests/load.rs b/test/integration-test/src/tests/load.rs index d7ffaf89..7187ac78 100644 --- a/test/integration-test/src/tests/load.rs +++ b/test/integration-test/src/tests/load.rs @@ -1,4 +1,10 @@ -use std::{convert::TryInto as _, thread, time}; +use std::{ + convert::TryInto as _, + fs::remove_file, + path::Path, + thread, + time::{Duration, SystemTime}, +}; use aya::{ maps::Array, @@ -11,9 +17,11 @@ use aya::{ util::KernelVersion, Bpf, }; +use aya_obj::programs::XdpAttachType; +use test_log::test; const MAX_RETRIES: usize = 100; -const RETRY_DURATION: time::Duration = time::Duration::from_millis(10); +const RETRY_DURATION: Duration = Duration::from_millis(10); #[test] fn tc_name_limit() { @@ -61,19 +69,94 @@ fn multiple_btf_maps() { let map_1: Array<_, u64> = bpf.take_map("map_1").unwrap().try_into().unwrap(); let map_2: Array<_, u64> = bpf.take_map("map_2").unwrap().try_into().unwrap(); + let map_pin_by_name: Array<_, u64> = + bpf.take_map("map_pin_by_name").unwrap().try_into().unwrap(); - let prog: &mut TracePoint = bpf.program_mut("bpf_prog").unwrap().try_into().unwrap(); + let prog: &mut UProbe = bpf.program_mut("bpf_prog").unwrap().try_into().unwrap(); prog.load().unwrap(); - prog.attach("sched", "sched_switch").unwrap(); + prog.attach(Some("trigger_bpf_program"), 0, "/proc/self/exe", None) + .unwrap(); - thread::sleep(time::Duration::from_secs(3)); + trigger_bpf_program(); let key = 0; let val_1 = map_1.get(&key, 0).unwrap(); let val_2 = map_2.get(&key, 0).unwrap(); + let val_3 = map_pin_by_name.get(&key, 0).unwrap(); assert_eq!(val_1, 24); assert_eq!(val_2, 42); + assert_eq!(val_3, 44); + let map_pin = Path::new("/sys/fs/bpf/map_pin_by_name"); + assert!(&map_pin.exists()); + + remove_file(map_pin).unwrap(); +} + +#[test] +fn pin_lifecycle_multiple_btf_maps() { + let mut bpf = Bpf::load(crate::MULTIMAP_BTF).unwrap(); + + // "map_pin_by_name" should already be pinned, unpin and pin again later + let map_pin_by_name_path = Path::new("/sys/fs/bpf/map_pin_by_name"); + + assert!(map_pin_by_name_path.exists()); + remove_file(map_pin_by_name_path).unwrap(); + + // pin and unpin all maps before casting to explicit types + for (i, (name, map)) in bpf.maps_mut().enumerate() { + // Don't pin system maps or the map that's already pinned by name. + if name.contains(".rodata") || name.contains(".bss") { + continue; + } + let map_pin_path = &Path::new("/sys/fs/bpf/").join(i.to_string()); + + map.pin(map_pin_path).unwrap(); + + assert!(map_pin_path.exists()); + remove_file(map_pin_path).unwrap(); + } + + let mut map_1: Array<_, u64> = bpf.take_map("map_1").unwrap().try_into().unwrap(); + let mut map_2: Array<_, u64> = bpf.take_map("map_2").unwrap().try_into().unwrap(); + let mut map_pin_by_name: Array<_, u64> = + bpf.take_map("map_pin_by_name").unwrap().try_into().unwrap(); + + let prog: &mut UProbe = bpf.program_mut("bpf_prog").unwrap().try_into().unwrap(); + prog.load().unwrap(); + prog.attach(Some("trigger_bpf_program"), 0, "/proc/self/exe", None) + .unwrap(); + + trigger_bpf_program(); + + let key = 0; + let val_1 = map_1.get(&key, 0).unwrap(); + let val_2 = map_2.get(&key, 0).unwrap(); + let val_3 = map_pin_by_name.get(&key, 0).unwrap(); + + assert_eq!(val_1, 24); + assert_eq!(val_2, 42); + assert_eq!(val_3, 44); + + let map_1_pin_path = Path::new("/sys/fs/bpf/map_1"); + let map_2_pin_path = Path::new("/sys/fs/bpf/map_2"); + + map_1.pin(map_1_pin_path).unwrap(); + map_2.pin(map_2_pin_path).unwrap(); + map_pin_by_name.pin(map_pin_by_name_path).unwrap(); + assert!(map_1_pin_path.exists()); + assert!(map_2_pin_path.exists()); + assert!(map_pin_by_name_path.exists()); + + remove_file(map_1_pin_path).unwrap(); + remove_file(map_2_pin_path).unwrap(); + remove_file(map_pin_by_name_path).unwrap(); +} + +#[no_mangle] +#[inline(never)] +pub extern "C" fn trigger_bpf_program() { + core::hint::black_box(trigger_bpf_program); } fn poll_loaded_program_id(name: &str) -> impl Iterator> + '_ { @@ -164,6 +247,42 @@ fn unload_xdp() { assert_unloaded("pass"); } +#[test] +fn test_loaded_at() { + let mut bpf = Bpf::load(crate::TEST).unwrap(); + let prog: &mut Xdp = bpf.program_mut("pass").unwrap().try_into().unwrap(); + + // SystemTime is not monotonic, which can cause this test to flake. We don't expect the clock + // timestamp to continuously jump around, so we add some retries. If the test is ever correct, + // we know that the value returned by loaded_at() was reasonable relative to SystemTime::now(). + let mut failures = Vec::new(); + for _ in 0..5 { + let t1 = SystemTime::now(); + prog.load().unwrap(); + let t2 = SystemTime::now(); + let loaded_at = prog.info().unwrap().loaded_at(); + prog.unload().unwrap(); + let range = t1..t2; + if range.contains(&loaded_at) { + failures.clear(); + break; + } + failures.push(LoadedAtRange(loaded_at, range)); + } + assert!( + failures.is_empty(), + "loaded_at was not in range: {failures:?}", + ); + + struct LoadedAtRange(SystemTime, std::ops::Range); + impl std::fmt::Debug for LoadedAtRange { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self(loaded_at, range) = self; + write!(f, "{range:?}.contains({loaded_at:?})") + } + } +} + #[test] fn unload_kprobe() { let mut bpf = Bpf::load(crate::TEST).unwrap(); @@ -302,7 +421,7 @@ fn pin_lifecycle() { // 2. Load program from bpffs but don't attach it { - let _ = Xdp::from_pin("/sys/fs/bpf/aya-xdp-test-prog").unwrap(); + let _ = Xdp::from_pin("/sys/fs/bpf/aya-xdp-test-prog", XdpAttachType::Interface).unwrap(); } // should still be loaded since prog was pinned @@ -310,7 +429,8 @@ fn pin_lifecycle() { // 3. Load program from bpffs and attach { - let mut prog = Xdp::from_pin("/sys/fs/bpf/aya-xdp-test-prog").unwrap(); + let mut prog = + Xdp::from_pin("/sys/fs/bpf/aya-xdp-test-prog", XdpAttachType::Interface).unwrap(); let link_id = prog.attach("lo", XdpFlags::default()).unwrap(); let link = prog.take_link(link_id).unwrap(); let fd_link: FdLink = link.try_into().unwrap(); diff --git a/test/integration-test/src/tests/log.rs b/test/integration-test/src/tests/log.rs index c51f7e96..c7980e0c 100644 --- a/test/integration-test/src/tests/log.rs +++ b/test/integration-test/src/tests/log.rs @@ -6,6 +6,7 @@ use std::{ use aya::{programs::UProbe, Bpf}; use aya_log::BpfLogger; use log::{Level, Log, Record}; +use test_log::test; #[no_mangle] #[inline(never)] @@ -37,7 +38,7 @@ struct CapturedLog<'a> { pub target: Cow<'a, str>, } -#[tokio::test] +#[test(tokio::test)] async fn log() { let mut bpf = Bpf::load(crate::LOG).unwrap(); @@ -138,5 +139,14 @@ async fn log() { }) ); + assert_eq!( + records.next(), + Some(&CapturedLog { + body: "42 43 44 45".into(), + level: Level::Debug, + target: "log".into(), + }) + ); + assert_eq!(records.next(), None); } diff --git a/test/integration-test/src/tests/rbpf.rs b/test/integration-test/src/tests/rbpf.rs index 0a85adbf..900d1462 100644 --- a/test/integration-test/src/tests/rbpf.rs +++ b/test/integration-test/src/tests/rbpf.rs @@ -2,7 +2,8 @@ use core::{mem::size_of, ptr::null_mut, slice::from_raw_parts}; use std::collections::HashMap; use assert_matches::assert_matches; -use aya_obj::{generated::bpf_insn, Object, ProgramSection}; +use aya_obj::{generated::bpf_insn, programs::XdpAttachType, Object, ProgramSection}; +use test_log::test; #[test] fn run_with_rbpf() { @@ -11,7 +12,10 @@ fn run_with_rbpf() { assert_eq!(object.programs.len(), 1); assert_matches!( object.programs["pass"].section, - ProgramSection::Xdp { frags: true } + ProgramSection::Xdp { + frags: true, + attach_type: XdpAttachType::Interface + } ); let instructions = &object @@ -31,7 +35,7 @@ fn run_with_rbpf() { assert_eq!(vm.execute_program().unwrap(), XDP_PASS); } -static mut MULTIMAP_MAPS: [*mut Vec; 2] = [null_mut(), null_mut()]; +static mut MULTIMAP_MAPS: [*mut Vec; 3] = [null_mut(); 3]; #[test] fn use_map_with_rbpf() { @@ -40,15 +44,15 @@ fn use_map_with_rbpf() { assert_eq!(object.programs.len(), 1); assert_matches!( object.programs["bpf_prog"].section, - ProgramSection::TracePoint { .. } + ProgramSection::UProbe { .. } ); // Initialize maps: - // - fd: 0xCAFE00 or 0xCAFE01 (the 0xCAFE00 part is used to distinguish fds from indices), + // - fd: Bitwise OR of the map_id with 0xCAFE00 (used to distinguish fds from indices), // - Note that rbpf does not convert fds into real pointers, // so we keeps the pointers to our maps in MULTIMAP_MAPS, to be used in helpers. let mut maps = HashMap::new(); - let mut map_instances = vec![vec![0u64], vec![0u64]]; + let mut map_instances = vec![vec![0u64], vec![0u64], vec![0u64]]; for (name, map) in object.maps.iter() { assert_eq!(map.key_size(), size_of::() as u32); assert_eq!(map.value_size(), size_of::() as u32); @@ -57,7 +61,13 @@ fn use_map_with_rbpf() { aya_obj::generated::bpf_map_type::BPF_MAP_TYPE_ARRAY as u32 ); - let map_id = if name == "map_1" { 0 } else { 1 }; + let map_id = match name.as_str() { + "map_1" => 0, + "map_2" => 1, + "map_pin_by_name" => 2, + n => panic!("Unexpected map: {n}"), + }; + let fd = map_id as i32 | 0xCAFE00; maps.insert(name.to_owned(), (fd, map.clone())); @@ -99,18 +109,16 @@ fn use_map_with_rbpf() { .expect("Helper failed"); assert_eq!(vm.execute_program().unwrap(), 0); - assert_eq!(map_instances[0][0], 24); - assert_eq!(map_instances[1][0], 42); + assert_eq!(map_instances, [[24], [42], [44]]); unsafe { - MULTIMAP_MAPS[0] = null_mut(); - MULTIMAP_MAPS[1] = null_mut(); + MULTIMAP_MAPS.iter_mut().for_each(|v| *v = null_mut()); } } #[track_caller] fn bpf_map_update_elem_multimap(map: u64, key: u64, value: u64, _: u64, _: u64) -> u64 { - assert_matches!(map, 0xCAFE00 | 0xCAFE01); + assert_matches!(map, 0xCAFE00 | 0xCAFE01 | 0xCAFE02); let key = *unsafe { (key as usize as *const u32).as_ref().unwrap() }; let value = *unsafe { (value as usize as *const u64).as_ref().unwrap() }; assert_eq!(key, 0); diff --git a/test/integration-test/src/tests/relocations.rs b/test/integration-test/src/tests/relocations.rs index 1b550e9f..9c5dab7f 100644 --- a/test/integration-test/src/tests/relocations.rs +++ b/test/integration-test/src/tests/relocations.rs @@ -1,13 +1,11 @@ -use std::time::Duration; - -use aya::{programs::UProbe, Bpf}; +use aya::{programs::UProbe, util::KernelVersion, Bpf}; +use test_log::test; #[test] fn relocations() { let bpf = load_and_attach("test_64_32_call_relocs", crate::RELOCATIONS); trigger_relocations_program(); - std::thread::sleep(Duration::from_millis(100)); let m = aya::maps::Array::<_, u64>::try_from(bpf.map("RESULTS").unwrap()).unwrap(); assert_eq!(m.get(&0, 0).unwrap(), 1); @@ -17,6 +15,12 @@ fn relocations() { #[test] fn text_64_64_reloc() { + let kernel_version = KernelVersion::current().unwrap(); + if kernel_version < KernelVersion::new(5, 13, 0) { + eprintln!("skipping test on kernel {kernel_version:?}, support for bpf_for_each_map_elem was added in 5.13.0; see https://github.com/torvalds/linux/commit/69c087b"); + return; + } + let mut bpf = load_and_attach("test_text_64_64_reloc", crate::TEXT_64_64_RELOC); let mut m = aya::maps::Array::<_, u64>::try_from(bpf.map_mut("RESULTS").unwrap()).unwrap(); @@ -24,7 +28,6 @@ fn text_64_64_reloc() { m.set(1, 2, 0).unwrap(); trigger_relocations_program(); - std::thread::sleep(Duration::from_millis(100)); assert_eq!(m.get(&0, 0).unwrap(), 2); assert_eq!(m.get(&1, 0).unwrap(), 3); diff --git a/test/integration-test/src/tests/ring_buf.rs b/test/integration-test/src/tests/ring_buf.rs new file mode 100644 index 00000000..927d80a9 --- /dev/null +++ b/test/integration-test/src/tests/ring_buf.rs @@ -0,0 +1,442 @@ +use std::{ + mem, + os::fd::AsRawFd as _, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, + thread, +}; + +use anyhow::Context as _; +use assert_matches::assert_matches; +use aya::{ + maps::{array::PerCpuArray, ring_buf::RingBuf, MapData}, + programs::UProbe, + Bpf, BpfLoader, Pod, +}; +use aya_obj::generated::BPF_RINGBUF_HDR_SZ; +use rand::Rng as _; +use test_log::test; +use tokio::{ + io::unix::AsyncFd, + time::{sleep, Duration}, +}; + +// This structure's definition is duplicated in the probe. +#[repr(C)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Default)] +struct Registers { + dropped: u64, + rejected: u64, +} + +impl std::ops::Add for Registers { + type Output = Self; + fn add(self, rhs: Self) -> Self::Output { + Self { + dropped: self.dropped + rhs.dropped, + rejected: self.rejected + rhs.rejected, + } + } +} + +impl<'a> std::iter::Sum<&'a Registers> for Registers { + fn sum>(iter: I) -> Self { + iter.fold(Default::default(), |a, b| a + *b) + } +} + +unsafe impl Pod for Registers {} + +struct RingBufTest { + _bpf: Bpf, + ring_buf: RingBuf, + regs: PerCpuArray, +} + +// Note that it is important for this test that RING_BUF_MAX_ENTRIES ends up creating a ring buffer +// that is exactly a power-of-two multiple of the page size. The synchronous test will fail if +// that's not the case because the actual size will be rounded up, and fewer entries will be dropped +// than expected. +const RING_BUF_MAX_ENTRIES: usize = 512; + +impl RingBufTest { + fn new() -> Self { + const RING_BUF_BYTE_SIZE: u32 = + (RING_BUF_MAX_ENTRIES * (mem::size_of::() + BPF_RINGBUF_HDR_SZ as usize)) as u32; + + // Use the loader API to control the size of the ring_buf. + let mut bpf = BpfLoader::new() + .set_max_entries("RING_BUF", RING_BUF_BYTE_SIZE) + .load(crate::RING_BUF) + .unwrap(); + let ring_buf = bpf.take_map("RING_BUF").unwrap(); + let ring_buf = RingBuf::try_from(ring_buf).unwrap(); + let regs = bpf.take_map("REGISTERS").unwrap(); + let regs = PerCpuArray::<_, Registers>::try_from(regs).unwrap(); + let prog: &mut UProbe = bpf + .program_mut("ring_buf_test") + .unwrap() + .try_into() + .unwrap(); + prog.load().unwrap(); + prog.attach( + Some("ring_buf_trigger_ebpf_program"), + 0, + "/proc/self/exe", + None, + ) + .unwrap(); + + Self { + _bpf: bpf, + ring_buf, + regs, + } + } +} + +struct WithData(RingBufTest, Vec); + +impl WithData { + fn new(n: usize) -> Self { + Self(RingBufTest::new(), { + let mut rng = rand::thread_rng(); + std::iter::repeat_with(|| rng.gen()).take(n).collect() + }) + } +} + +#[test_case::test_case(0; "write zero items")] +#[test_case::test_case(1; "write one item")] +#[test_case::test_case(RING_BUF_MAX_ENTRIES / 2; "write half the capacity items")] +#[test_case::test_case(RING_BUF_MAX_ENTRIES - 1; "write one less than capacity items")] +#[test_case::test_case(RING_BUF_MAX_ENTRIES * 8; "write more items than capacity")] +fn ring_buf(n: usize) { + let WithData( + RingBufTest { + mut ring_buf, + regs, + _bpf, + }, + data, + ) = WithData::new(n); + + // Note that after expected_capacity has been submitted, reserve calls in the probe will fail + // and the probe will give up. + let expected_capacity = RING_BUF_MAX_ENTRIES - 1; + + // Call the function that the uprobe is attached to with the data. + let mut expected = Vec::new(); + let mut expected_rejected = 0u64; + let mut expected_dropped = 0u64; + for (i, &v) in data.iter().enumerate() { + ring_buf_trigger_ebpf_program(v); + if i >= expected_capacity { + expected_dropped += 1; + } else if v % 2 == 0 { + expected.push(v); + } else { + expected_rejected += 1; + } + } + + let mut seen = Vec::::new(); + while seen.len() < expected.len() { + if let Some(read) = ring_buf.next() { + let read: [u8; 8] = (*read) + .try_into() + .with_context(|| format!("data: {:?}", read.len())) + .unwrap(); + let arg = u64::from_ne_bytes(read); + assert_eq!(arg % 2, 0, "got {arg} from probe"); + seen.push(arg); + } + } + + // Make sure that there is nothing else in the ring_buf. + assert_matches!(ring_buf.next(), None); + + // Ensure that the data that was read matches what was passed, and the rejected count was set + // properly. + assert_eq!(seen, expected); + let Registers { dropped, rejected } = regs.get(&0, 0).unwrap().iter().sum(); + assert_eq!(dropped, expected_dropped); + assert_eq!(rejected, expected_rejected); +} + +#[no_mangle] +#[inline(never)] +pub extern "C" fn ring_buf_trigger_ebpf_program(arg: u64) { + std::hint::black_box(arg); +} + +// This test differs from the other async test in that it's possible for the producer +// to fill the ring_buf. We just ensure that the number of events we see is sane given +// what the producer sees, and that the logic does not hang. This exercises interleaving +// discards, successful commits, and drops due to the ring_buf being full. +#[test(tokio::test(flavor = "multi_thread"))] +async fn ring_buf_async_with_drops() { + let WithData( + RingBufTest { + ring_buf, + regs, + _bpf, + }, + data, + ) = WithData::new(RING_BUF_MAX_ENTRIES * 8); + + let mut async_fd = AsyncFd::new(ring_buf).unwrap(); + + // Spawn the writer which internally will spawn many parallel writers. + // Construct an AsyncFd from the RingBuf in order to receive readiness notifications. + let mut seen = 0; + let mut process_ring_buf = |ring_buf: &mut RingBuf<_>| { + while let Some(read) = ring_buf.next() { + let read: [u8; 8] = (*read) + .try_into() + .with_context(|| format!("data: {:?}", read.len())) + .unwrap(); + let arg = u64::from_ne_bytes(read); + assert_eq!(arg % 2, 0, "got {arg} from probe"); + seen += 1; + } + }; + use futures::future::{ + select, + Either::{Left, Right}, + }; + let writer = futures::future::try_join_all(data.chunks(8).map(ToOwned::to_owned).map(|v| { + tokio::spawn(async { + for value in v { + ring_buf_trigger_ebpf_program(value); + } + }) + })); + let readable = { + let mut writer = writer; + loop { + let readable = Box::pin(async_fd.readable_mut()); + writer = match select(readable, writer).await { + Left((guard, writer)) => { + let mut guard = guard.unwrap(); + process_ring_buf(guard.get_inner_mut()); + guard.clear_ready(); + writer + } + Right((writer, readable)) => { + writer.unwrap(); + break readable; + } + } + } + }; + + // If there's more to read, we should receive a readiness notification in a timely manner. + // If we don't then, then assert that there's nothing else to read. Note that it's important + // to wait some time before attempting to read, otherwise we may catch up with the producer + // before epoll has an opportunity to send a notification; our consumer thread can race + // with the kernel epoll check. + let sleep_fut = sleep(Duration::from_millis(10)); + tokio::pin!(sleep_fut); + match select(sleep_fut, readable).await { + Left(((), _)) => {} + Right((guard, _)) => { + let mut guard = guard.unwrap(); + process_ring_buf(guard.get_inner_mut()); + guard.clear_ready(); + } + } + + // Make sure that there is nothing else in the ring_buf. + assert_matches!(async_fd.into_inner().next(), None); + + let max_dropped: u64 = u64::try_from( + data.len() + .checked_sub(RING_BUF_MAX_ENTRIES - 1) + .unwrap_or_default(), + ) + .unwrap(); + let max_seen = u64::try_from(data.iter().filter(|v| *v % 2 == 0).count()).unwrap(); + let max_rejected = u64::try_from(data.len()).unwrap() - max_seen; + let Registers { dropped, rejected } = regs.get(&0, 0).unwrap().iter().sum(); + let total = u64::try_from(data.len()).unwrap(); + let min_seen = max_seen.checked_sub(max_dropped).unwrap_or_default(); + let min_rejected = max_rejected.checked_sub(dropped).unwrap_or_default(); + let facts = format!( + "seen={seen}, rejected={rejected}, dropped={dropped}, total={total}, max_seen={max_seen}, \ + max_rejected={max_rejected}, max_dropped={max_dropped}", + ); + assert_eq!(seen + rejected + dropped, total, "{facts}",); + assert!( + (0u64..=max_dropped).contains(&dropped), + "dropped={dropped} not in 0..={max_dropped}; {facts}", + ); + assert!( + (min_rejected..=max_rejected).contains(&rejected), + "rejected={rejected} not in {min_rejected}..={max_rejected}; {facts}", + ); + assert!( + (min_seen..=max_seen).contains(&seen), + "seen={seen} not in {min_seen}..={max_seen}, rejected={rejected}; {facts}", + ); +} + +#[test(tokio::test(flavor = "multi_thread"))] +async fn ring_buf_async_no_drop() { + let WithData( + RingBufTest { + ring_buf, + regs, + _bpf, + }, + data, + ) = WithData::new(RING_BUF_MAX_ENTRIES * 3); + + let writer = { + let data = data.to_owned(); + tokio::spawn(async move { + for value in data { + // Sleep a tad so we feel confident that the consumer will keep up + // and no messages will be dropped. + let dur = Duration::from_nanos(rand::thread_rng().gen_range(0..10)); + sleep(dur).await; + ring_buf_trigger_ebpf_program(value); + } + }) + }; + + // Construct an AsyncFd from the RingBuf in order to receive readiness notifications. + let mut async_fd = AsyncFd::new(ring_buf).unwrap(); + // Note that unlike in the synchronous case where all of the entries are written before any of + // them are read, in this case we expect all of the entries to make their way to userspace + // because entries are being consumed as they are produced. + let expected: Vec = data.iter().cloned().filter(|v| *v % 2 == 0).collect(); + let expected_len = expected.len(); + let reader = async move { + let mut seen = Vec::with_capacity(expected_len); + while seen.len() < expected_len { + let mut guard = async_fd.readable_mut().await.unwrap(); + let ring_buf = guard.get_inner_mut(); + while let Some(read) = ring_buf.next() { + let read: [u8; 8] = (*read) + .try_into() + .with_context(|| format!("data: {:?}", read.len())) + .unwrap(); + let arg = u64::from_ne_bytes(read); + seen.push(arg); + } + guard.clear_ready(); + } + (seen, async_fd.into_inner()) + }; + let (writer, (seen, mut ring_buf)) = futures::future::join(writer, reader).await; + writer.unwrap(); + + // Make sure that there is nothing else in the ring_buf. + assert_matches!(ring_buf.next(), None); + + // Ensure that the data that was read matches what was passed. + assert_eq!(&seen, &expected); + let Registers { dropped, rejected } = regs.get(&0, 0).unwrap().iter().sum(); + assert_eq!(dropped, 0); + assert_eq!(rejected, (data.len() - expected.len()).try_into().unwrap()); +} + +// This test reproduces a bug where the ring buffer would not be notified of new entries if the +// state was not properly synchronized between the producer and consumer. This would result in the +// consumer never being woken up and the test hanging. +#[test] +fn ring_buf_epoll_wakeup() { + let RingBufTest { + mut ring_buf, + _bpf, + regs: _, + } = RingBufTest::new(); + + let epoll_fd = epoll::create(false).unwrap(); + epoll::ctl( + epoll_fd, + epoll::ControlOptions::EPOLL_CTL_ADD, + ring_buf.as_raw_fd(), + // The use of EPOLLET is intentional. Without it, level-triggering would result in + // more notifications, and would mask the underlying bug this test reproduced when + // the synchronization logic in the RingBuf mirrored that of libbpf. Also, tokio's + // AsyncFd always uses this flag (as demonstrated in the subsequent test). + epoll::Event::new(epoll::Events::EPOLLIN | epoll::Events::EPOLLET, 0), + ) + .unwrap(); + let mut epoll_event_buf = [epoll::Event::new(epoll::Events::EPOLLIN, 0); 1]; + let mut total_events: u64 = 0; + let writer = WriterThread::spawn(); + while total_events < WriterThread::NUM_MESSAGES { + epoll::wait(epoll_fd, -1, &mut epoll_event_buf).unwrap(); + while let Some(read) = ring_buf.next() { + assert_eq!(read.len(), 8); + total_events += 1; + } + } + writer.join(); +} + +// This test is like the above test but uses tokio and AsyncFd instead of raw epoll. +#[test(tokio::test)] +async fn ring_buf_asyncfd_events() { + let RingBufTest { + ring_buf, + regs: _, + _bpf, + } = RingBufTest::new(); + + let mut async_fd = AsyncFd::new(ring_buf).unwrap(); + let mut total_events = 0; + let writer = WriterThread::spawn(); + while total_events < WriterThread::NUM_MESSAGES { + let mut guard = async_fd.readable_mut().await.unwrap(); + let rb = guard.get_inner_mut(); + while let Some(read) = rb.next() { + assert_eq!(read.len(), 8); + total_events += 1; + } + guard.clear_ready(); + } + writer.join(); +} + +// WriterThread triggers the ring_buf write continuously until the join() method is called. It is +// used by both the epoll and async fd test that need frequent writes to the ring buffer to trigger +// the memory synchronization bug that was fixed. +struct WriterThread { + thread: thread::JoinHandle<()>, + done: Arc, +} + +impl WriterThread { + // When the ring buffer implementation uses Ordering::Relaxed to write the consumer position + // rather than Ordering::SeqCst, the test will hang. This number was determined to be large + // enough to tickle that bug on a hardware accelerated VM with 2 vCPUs. + const NUM_MESSAGES: u64 = 20_000; + + fn spawn() -> Self { + let done = Arc::new(AtomicBool::new(false)); + Self { + thread: { + let done = done.clone(); + thread::spawn(move || { + while !done.load(Ordering::Relaxed) { + // Write 0 which is even and won't be rejected. + ring_buf_trigger_ebpf_program(0); + } + }) + }, + done, + } + } + + fn join(self) { + let Self { thread, done } = self; + done.store(true, Ordering::Relaxed); + thread.join().unwrap(); + } +} diff --git a/test/integration-test/src/tests/smoke.rs b/test/integration-test/src/tests/smoke.rs index 48c1600b..13204557 100644 --- a/test/integration-test/src/tests/smoke.rs +++ b/test/integration-test/src/tests/smoke.rs @@ -1,21 +1,23 @@ use aya::{ + maps::loaded_maps, programs::{loaded_programs, Extension, TracePoint, Xdp, XdpFlags}, util::KernelVersion, Bpf, BpfLoader, }; +use test_log::test; use crate::utils::NetNsGuard; #[test] fn xdp() { - let _netns = NetNsGuard::new(); - let kernel_version = KernelVersion::current().unwrap(); if kernel_version < KernelVersion::new(5, 18, 0) { eprintln!("skipping test on kernel {kernel_version:?}, support for BPF_F_XDP_HAS_FRAGS was added in 5.18.0; see https://github.com/torvalds/linux/commit/c2f2cdb"); return; } + let _netns = NetNsGuard::new(); + let mut bpf = Bpf::load(crate::PASS).unwrap(); let dispatcher: &mut Xdp = bpf.program_mut("pass").unwrap().try_into().unwrap(); dispatcher.load().unwrap(); @@ -46,13 +48,14 @@ fn two_progs() { #[test] fn extension() { - let _netns = NetNsGuard::new(); - let kernel_version = KernelVersion::current().unwrap(); if kernel_version < KernelVersion::new(5, 9, 0) { eprintln!("skipping test on kernel {kernel_version:?}, XDP uses netlink"); return; } + + let _netns = NetNsGuard::new(); + let mut bpf = Bpf::load(crate::MAIN).unwrap(); let pass: &mut Xdp = bpf.program_mut("xdp_pass").unwrap().try_into().unwrap(); pass.load().unwrap(); @@ -96,3 +99,28 @@ fn list_loaded_programs() { prog.loaded_at(); prog.fd().unwrap(); } + +#[test] +fn list_loaded_maps() { + // Load a program with maps. + let mut bpf = Bpf::load(crate::MAP_TEST).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_maps() api doesn't panic and retrieve a map. + let map = loaded_maps() + .map(|m| m.unwrap()) + .find(|m| m.name_as_str().unwrap() == "FOO") + .unwrap(); + + // Ensure all relevant helper functions don't panic. + map.name(); + map.id(); + map.map_type(); + map.key_size(); + map.value_size(); + map.max_entries(); + map.map_flags(); + map.fd().unwrap(); +} diff --git a/test/integration-test/src/tests/xdp.rs b/test/integration-test/src/tests/xdp.rs new file mode 100644 index 00000000..784ffe75 --- /dev/null +++ b/test/integration-test/src/tests/xdp.rs @@ -0,0 +1,178 @@ +use std::{ffi::CStr, mem::MaybeUninit, net::UdpSocket, num::NonZeroU32, time::Duration}; + +use aya::{ + maps::{Array, CpuMap, XskMap}, + programs::{Xdp, XdpFlags}, + Bpf, +}; +use object::{Object, ObjectSection, ObjectSymbol, SymbolSection}; +use test_log::test; +use xdpilone::{BufIdx, IfInfo, Socket, SocketConfig, Umem, UmemConfig}; + +use crate::utils::NetNsGuard; + +#[test] +fn af_xdp() { + let _netns = NetNsGuard::new(); + + let mut bpf = Bpf::load(crate::REDIRECT).unwrap(); + let mut socks: XskMap<_> = bpf.take_map("SOCKS").unwrap().try_into().unwrap(); + + let xdp: &mut Xdp = bpf + .program_mut("redirect_sock") + .unwrap() + .try_into() + .unwrap(); + xdp.load().unwrap(); + xdp.attach("lo", XdpFlags::default()).unwrap(); + + // So this needs to be page aligned. Pages are 4k on all mainstream architectures except for + // Apple Silicon which uses 16k pages. So let's align on that for tests to run natively there. + #[repr(align(16384))] + struct PacketMap(MaybeUninit<[u8; 4096]>); + + // Safety: don't access alloc down the line. + let mut alloc = Box::new(PacketMap(MaybeUninit::uninit())); + let umem = { + // Safety: this is a shared buffer between the kernel and us, uninitialized memory is valid. + let mem = unsafe { alloc.0.assume_init_mut() }.as_mut().into(); + // Safety: we cannot access `mem` further down the line because it falls out of scope. + unsafe { Umem::new(UmemConfig::default(), mem).unwrap() } + }; + + let mut iface = IfInfo::invalid(); + iface + .from_name(CStr::from_bytes_with_nul(b"lo\0").unwrap()) + .unwrap(); + let sock = Socket::with_shared(&iface, &umem).unwrap(); + + let mut fq_cq = umem.fq_cq(&sock).unwrap(); // Fill Queue / Completion Queue + + let cfg = SocketConfig { + rx_size: NonZeroU32::new(32), + ..Default::default() + }; + let rxtx = umem.rx_tx(&sock, &cfg).unwrap(); // RX + TX Queues + let mut rx = rxtx.map_rx().unwrap(); + + umem.bind(&rxtx).unwrap(); + + socks.set(0, rx.as_raw_fd(), 0).unwrap(); + + let frame = umem.frame(BufIdx(0)).unwrap(); + + // Produce a frame to be filled by the kernel + let mut writer = fq_cq.fill(1); + writer.insert_once(frame.offset); + writer.commit(); + + let sock = UdpSocket::bind("127.0.0.1:0").unwrap(); + let port = sock.local_addr().unwrap().port(); + sock.send_to(b"hello AF_XDP", "127.0.0.1:1777").unwrap(); + + assert_eq!(rx.available(), 1); + let desc = rx.receive(1).read().unwrap(); + let buf = unsafe { + &frame.addr.as_ref()[desc.addr as usize..(desc.addr as usize + desc.len as usize)] + }; + + let (eth, buf) = buf.split_at(14); + assert_eq!(eth[12..14], [0x08, 0x00]); // IP + let (ip, buf) = buf.split_at(20); + assert_eq!(ip[9], 17); // UDP + let (udp, payload) = buf.split_at(8); + assert_eq!(&udp[0..2], port.to_be_bytes().as_slice()); // Source + assert_eq!(&udp[2..4], 1777u16.to_be_bytes().as_slice()); // Dest + assert_eq!(payload, b"hello AF_XDP"); +} + +#[test] +fn prog_sections() { + let obj_file = object::File::parse(crate::XDP_SEC).unwrap(); + + ensure_symbol(&obj_file, "xdp", "xdp_plain"); + ensure_symbol(&obj_file, "xdp.frags", "xdp_frags"); + ensure_symbol(&obj_file, "xdp/cpumap", "xdp_cpumap"); + ensure_symbol(&obj_file, "xdp/devmap", "xdp_devmap"); + ensure_symbol(&obj_file, "xdp.frags/cpumap", "xdp_frags_cpumap"); + ensure_symbol(&obj_file, "xdp.frags/devmap", "xdp_frags_devmap"); +} + +#[track_caller] +fn ensure_symbol(obj_file: &object::File, sec_name: &str, sym_name: &str) { + let sec = obj_file.section_by_name(sec_name).unwrap_or_else(|| { + let secs = obj_file + .sections() + .flat_map(|sec| sec.name().ok().map(|name| name.to_owned())) + .collect::>(); + panic!("section {sec_name} not found. available sections: {secs:?}"); + }); + let sec = SymbolSection::Section(sec.index()); + + let syms = obj_file + .symbols() + .filter(|sym| sym.section() == sec) + .filter_map(|sym| sym.name().ok()) + .collect::>(); + assert!( + syms.contains(&sym_name), + "symbol not found. available symbols in section: {syms:?}" + ); +} + +#[test] +fn map_load() { + let bpf = Bpf::load(crate::XDP_SEC).unwrap(); + + bpf.program("xdp_plain").unwrap(); + bpf.program("xdp_frags").unwrap(); + bpf.program("xdp_cpumap").unwrap(); + bpf.program("xdp_devmap").unwrap(); + bpf.program("xdp_frags_cpumap").unwrap(); + bpf.program("xdp_frags_devmap").unwrap(); +} + +#[test] +fn cpumap_chain() { + let _netns = NetNsGuard::new(); + + let mut bpf = Bpf::load(crate::REDIRECT).unwrap(); + + // Load our cpumap and our canary map + let mut cpus: CpuMap<_> = bpf.take_map("CPUS").unwrap().try_into().unwrap(); + let hits: Array<_, u32> = bpf.take_map("HITS").unwrap().try_into().unwrap(); + + let xdp_chain_fd = { + // Load the chained program to run on the target CPU + let xdp: &mut Xdp = bpf + .program_mut("redirect_cpu_chain") + .unwrap() + .try_into() + .unwrap(); + xdp.load().unwrap(); + xdp.fd().unwrap() + }; + cpus.set(0, 2048, Some(xdp_chain_fd), 0).unwrap(); + + // Load the main program + let xdp: &mut Xdp = bpf.program_mut("redirect_cpu").unwrap().try_into().unwrap(); + xdp.load().unwrap(); + xdp.attach("lo", XdpFlags::default()).unwrap(); + + const PAYLOAD: &str = "hello cpumap"; + + let sock = UdpSocket::bind("127.0.0.1:0").unwrap(); + let addr = sock.local_addr().unwrap(); + sock.set_read_timeout(Some(Duration::from_secs(60))) + .unwrap(); + sock.send_to(PAYLOAD.as_bytes(), addr).unwrap(); + + // Read back the packet to ensure it went through the entire network stack, including our two + // probes. + let mut buf = [0u8; PAYLOAD.len() + 1]; + let n = sock.recv(&mut buf).unwrap(); + + assert_eq!(&buf[..n], PAYLOAD.as_bytes()); + assert_eq!(hits.get(&0, 0).unwrap(), 1); + assert_eq!(hits.get(&1, 0).unwrap(), 1); +} diff --git a/xtask/public-api/aya-bpf-bindings.txt b/xtask/public-api/aya-bpf-bindings.txt index c98486a2..1d35dcf8 100644 --- a/xtask/public-api/aya-bpf-bindings.txt +++ b/xtask/public-api/aya-bpf-bindings.txt @@ -1813,9 +1813,9 @@ pub fn aya_bpf_bindings::bindings::__BindgenBitfieldUnit::clone(&self) impl core::cmp::Eq for aya_bpf_bindings::bindings::__BindgenBitfieldUnit impl core::cmp::Ord for aya_bpf_bindings::bindings::__BindgenBitfieldUnit pub fn aya_bpf_bindings::bindings::__BindgenBitfieldUnit::cmp(&self, other: &aya_bpf_bindings::bindings::__BindgenBitfieldUnit) -> core::cmp::Ordering -impl core::cmp::PartialEq> for aya_bpf_bindings::bindings::__BindgenBitfieldUnit +impl core::cmp::PartialEq for aya_bpf_bindings::bindings::__BindgenBitfieldUnit pub fn aya_bpf_bindings::bindings::__BindgenBitfieldUnit::eq(&self, other: &aya_bpf_bindings::bindings::__BindgenBitfieldUnit) -> bool -impl core::cmp::PartialOrd> for aya_bpf_bindings::bindings::__BindgenBitfieldUnit +impl core::cmp::PartialOrd for aya_bpf_bindings::bindings::__BindgenBitfieldUnit pub fn aya_bpf_bindings::bindings::__BindgenBitfieldUnit::partial_cmp(&self, other: &aya_bpf_bindings::bindings::__BindgenBitfieldUnit) -> core::option::Option impl core::default::Default for aya_bpf_bindings::bindings::__BindgenBitfieldUnit pub fn aya_bpf_bindings::bindings::__BindgenBitfieldUnit::default() -> aya_bpf_bindings::bindings::__BindgenBitfieldUnit diff --git a/xtask/public-api/aya-bpf.txt b/xtask/public-api/aya-bpf.txt index 4d4aa0f7..ba5ea3d8 100644 --- a/xtask/public-api/aya-bpf.txt +++ b/xtask/public-api/aya-bpf.txt @@ -448,6 +448,65 @@ impl core::borrow::BorrowMut for aya_bpf::maps::queue::Queue where T: c pub fn aya_bpf::maps::queue::Queue::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya_bpf::maps::queue::Queue pub fn aya_bpf::maps::queue::Queue::from(t: T) -> T +pub mod aya_bpf::maps::ring_buf +#[repr(transparent)] pub struct aya_bpf::maps::ring_buf::RingBuf +impl aya_bpf::maps::ring_buf::RingBuf +pub fn aya_bpf::maps::ring_buf::RingBuf::output(&self, data: &T, flags: u64) -> core::result::Result<(), i64> +pub const fn aya_bpf::maps::ring_buf::RingBuf::pinned(byte_size: u32, flags: u32) -> Self +pub fn aya_bpf::maps::ring_buf::RingBuf::query(&self, flags: u64) -> u64 +pub fn aya_bpf::maps::ring_buf::RingBuf::reserve(&self, flags: u64) -> core::option::Option> where const_assert::Assert<{ _ }>: const_assert::IsTrue +pub const fn aya_bpf::maps::ring_buf::RingBuf::with_byte_size(byte_size: u32, flags: u32) -> Self +impl core::marker::Sync for aya_bpf::maps::ring_buf::RingBuf +impl core::marker::Send for aya_bpf::maps::ring_buf::RingBuf +impl core::marker::Unpin for aya_bpf::maps::ring_buf::RingBuf +impl !core::panic::unwind_safe::RefUnwindSafe for aya_bpf::maps::ring_buf::RingBuf +impl core::panic::unwind_safe::UnwindSafe for aya_bpf::maps::ring_buf::RingBuf +impl core::convert::Into for aya_bpf::maps::ring_buf::RingBuf where U: core::convert::From +pub fn aya_bpf::maps::ring_buf::RingBuf::into(self) -> U +impl core::convert::TryFrom for aya_bpf::maps::ring_buf::RingBuf where U: core::convert::Into +pub type aya_bpf::maps::ring_buf::RingBuf::Error = core::convert::Infallible +pub fn aya_bpf::maps::ring_buf::RingBuf::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_bpf::maps::ring_buf::RingBuf where U: core::convert::TryFrom +pub type aya_bpf::maps::ring_buf::RingBuf::Error = >::Error +pub fn aya_bpf::maps::ring_buf::RingBuf::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya_bpf::maps::ring_buf::RingBuf where T: 'static + core::marker::Sized +pub fn aya_bpf::maps::ring_buf::RingBuf::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_bpf::maps::ring_buf::RingBuf where T: core::marker::Sized +pub fn aya_bpf::maps::ring_buf::RingBuf::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_bpf::maps::ring_buf::RingBuf where T: core::marker::Sized +pub fn aya_bpf::maps::ring_buf::RingBuf::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_bpf::maps::ring_buf::RingBuf +pub fn aya_bpf::maps::ring_buf::RingBuf::from(t: T) -> T +pub struct aya_bpf::maps::ring_buf::RingBufEntry(_) +impl aya_bpf::maps::ring_buf::RingBufEntry +pub fn aya_bpf::maps::ring_buf::RingBufEntry::discard(self, flags: u64) +pub fn aya_bpf::maps::ring_buf::RingBufEntry::submit(self, flags: u64) +impl core::ops::deref::Deref for aya_bpf::maps::ring_buf::RingBufEntry +pub type aya_bpf::maps::ring_buf::RingBufEntry::Target = core::mem::maybe_uninit::MaybeUninit +pub fn aya_bpf::maps::ring_buf::RingBufEntry::deref(&self) -> &Self::Target +impl core::ops::deref::DerefMut for aya_bpf::maps::ring_buf::RingBufEntry +pub fn aya_bpf::maps::ring_buf::RingBufEntry::deref_mut(&mut self) -> &mut Self::Target +impl core::marker::Send for aya_bpf::maps::ring_buf::RingBufEntry where T: core::marker::Send +impl core::marker::Sync for aya_bpf::maps::ring_buf::RingBufEntry where T: core::marker::Sync +impl core::marker::Unpin for aya_bpf::maps::ring_buf::RingBufEntry +impl core::panic::unwind_safe::RefUnwindSafe for aya_bpf::maps::ring_buf::RingBufEntry where T: core::panic::unwind_safe::RefUnwindSafe +impl !core::panic::unwind_safe::UnwindSafe for aya_bpf::maps::ring_buf::RingBufEntry +impl core::convert::Into for aya_bpf::maps::ring_buf::RingBufEntry where U: core::convert::From +pub fn aya_bpf::maps::ring_buf::RingBufEntry::into(self) -> U +impl core::convert::TryFrom for aya_bpf::maps::ring_buf::RingBufEntry where U: core::convert::Into +pub type aya_bpf::maps::ring_buf::RingBufEntry::Error = core::convert::Infallible +pub fn aya_bpf::maps::ring_buf::RingBufEntry::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_bpf::maps::ring_buf::RingBufEntry where U: core::convert::TryFrom +pub type aya_bpf::maps::ring_buf::RingBufEntry::Error = >::Error +pub fn aya_bpf::maps::ring_buf::RingBufEntry::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya_bpf::maps::ring_buf::RingBufEntry where T: 'static + core::marker::Sized +pub fn aya_bpf::maps::ring_buf::RingBufEntry::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_bpf::maps::ring_buf::RingBufEntry where T: core::marker::Sized +pub fn aya_bpf::maps::ring_buf::RingBufEntry::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_bpf::maps::ring_buf::RingBufEntry where T: core::marker::Sized +pub fn aya_bpf::maps::ring_buf::RingBufEntry::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_bpf::maps::ring_buf::RingBufEntry +pub fn aya_bpf::maps::ring_buf::RingBufEntry::from(t: T) -> T pub mod aya_bpf::maps::sock_hash #[repr(transparent)] pub struct aya_bpf::maps::sock_hash::SockHash impl aya_bpf::maps::sock_hash::SockHash @@ -563,6 +622,114 @@ impl core::borrow::BorrowMut for aya_bpf::maps::stack_trace::StackTrace wh pub fn aya_bpf::maps::stack_trace::StackTrace::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya_bpf::maps::stack_trace::StackTrace pub fn aya_bpf::maps::stack_trace::StackTrace::from(t: T) -> T +pub mod aya_bpf::maps::xdp +#[repr(transparent)] pub struct aya_bpf::maps::xdp::CpuMap +impl aya_bpf::maps::CpuMap +pub const fn aya_bpf::maps::CpuMap::pinned(max_entries: u32, flags: u32) -> aya_bpf::maps::CpuMap +pub fn aya_bpf::maps::CpuMap::redirect(&self, index: u32, flags: u64) -> core::result::Result +pub const fn aya_bpf::maps::CpuMap::with_max_entries(max_entries: u32, flags: u32) -> aya_bpf::maps::CpuMap +impl core::marker::Sync for aya_bpf::maps::CpuMap +impl core::marker::Send for aya_bpf::maps::CpuMap +impl core::marker::Unpin for aya_bpf::maps::CpuMap +impl !core::panic::unwind_safe::RefUnwindSafe for aya_bpf::maps::CpuMap +impl core::panic::unwind_safe::UnwindSafe for aya_bpf::maps::CpuMap +impl core::convert::Into for aya_bpf::maps::CpuMap where U: core::convert::From +pub fn aya_bpf::maps::CpuMap::into(self) -> U +impl core::convert::TryFrom for aya_bpf::maps::CpuMap where U: core::convert::Into +pub type aya_bpf::maps::CpuMap::Error = core::convert::Infallible +pub fn aya_bpf::maps::CpuMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_bpf::maps::CpuMap where U: core::convert::TryFrom +pub type aya_bpf::maps::CpuMap::Error = >::Error +pub fn aya_bpf::maps::CpuMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya_bpf::maps::CpuMap where T: 'static + core::marker::Sized +pub fn aya_bpf::maps::CpuMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_bpf::maps::CpuMap where T: core::marker::Sized +pub fn aya_bpf::maps::CpuMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_bpf::maps::CpuMap where T: core::marker::Sized +pub fn aya_bpf::maps::CpuMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_bpf::maps::CpuMap +pub fn aya_bpf::maps::CpuMap::from(t: T) -> T +#[repr(transparent)] pub struct aya_bpf::maps::xdp::DevMap +impl aya_bpf::maps::DevMap +pub fn aya_bpf::maps::DevMap::get(&self, index: u32) -> core::option::Option +pub const fn aya_bpf::maps::DevMap::pinned(max_entries: u32, flags: u32) -> aya_bpf::maps::DevMap +pub fn aya_bpf::maps::DevMap::redirect(&self, index: u32, flags: u64) -> core::result::Result +pub const fn aya_bpf::maps::DevMap::with_max_entries(max_entries: u32, flags: u32) -> aya_bpf::maps::DevMap +impl core::marker::Sync for aya_bpf::maps::DevMap +impl core::marker::Send for aya_bpf::maps::DevMap +impl core::marker::Unpin for aya_bpf::maps::DevMap +impl !core::panic::unwind_safe::RefUnwindSafe for aya_bpf::maps::DevMap +impl core::panic::unwind_safe::UnwindSafe for aya_bpf::maps::DevMap +impl core::convert::Into for aya_bpf::maps::DevMap where U: core::convert::From +pub fn aya_bpf::maps::DevMap::into(self) -> U +impl core::convert::TryFrom for aya_bpf::maps::DevMap where U: core::convert::Into +pub type aya_bpf::maps::DevMap::Error = core::convert::Infallible +pub fn aya_bpf::maps::DevMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_bpf::maps::DevMap where U: core::convert::TryFrom +pub type aya_bpf::maps::DevMap::Error = >::Error +pub fn aya_bpf::maps::DevMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya_bpf::maps::DevMap where T: 'static + core::marker::Sized +pub fn aya_bpf::maps::DevMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_bpf::maps::DevMap where T: core::marker::Sized +pub fn aya_bpf::maps::DevMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_bpf::maps::DevMap where T: core::marker::Sized +pub fn aya_bpf::maps::DevMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_bpf::maps::DevMap +pub fn aya_bpf::maps::DevMap::from(t: T) -> T +#[repr(transparent)] pub struct aya_bpf::maps::xdp::DevMapHash +impl aya_bpf::maps::DevMapHash +pub fn aya_bpf::maps::DevMapHash::get(&self, key: u32) -> core::option::Option +pub const fn aya_bpf::maps::DevMapHash::pinned(max_entries: u32, flags: u32) -> aya_bpf::maps::DevMapHash +pub fn aya_bpf::maps::DevMapHash::redirect(&self, key: u32, flags: u64) -> core::result::Result +pub const fn aya_bpf::maps::DevMapHash::with_max_entries(max_entries: u32, flags: u32) -> aya_bpf::maps::DevMapHash +impl core::marker::Sync for aya_bpf::maps::DevMapHash +impl core::marker::Send for aya_bpf::maps::DevMapHash +impl core::marker::Unpin for aya_bpf::maps::DevMapHash +impl !core::panic::unwind_safe::RefUnwindSafe for aya_bpf::maps::DevMapHash +impl core::panic::unwind_safe::UnwindSafe for aya_bpf::maps::DevMapHash +impl core::convert::Into for aya_bpf::maps::DevMapHash where U: core::convert::From +pub fn aya_bpf::maps::DevMapHash::into(self) -> U +impl core::convert::TryFrom for aya_bpf::maps::DevMapHash where U: core::convert::Into +pub type aya_bpf::maps::DevMapHash::Error = core::convert::Infallible +pub fn aya_bpf::maps::DevMapHash::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_bpf::maps::DevMapHash where U: core::convert::TryFrom +pub type aya_bpf::maps::DevMapHash::Error = >::Error +pub fn aya_bpf::maps::DevMapHash::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya_bpf::maps::DevMapHash where T: 'static + core::marker::Sized +pub fn aya_bpf::maps::DevMapHash::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_bpf::maps::DevMapHash where T: core::marker::Sized +pub fn aya_bpf::maps::DevMapHash::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_bpf::maps::DevMapHash where T: core::marker::Sized +pub fn aya_bpf::maps::DevMapHash::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_bpf::maps::DevMapHash +pub fn aya_bpf::maps::DevMapHash::from(t: T) -> T +#[repr(transparent)] pub struct aya_bpf::maps::xdp::XskMap +impl aya_bpf::maps::XskMap +pub fn aya_bpf::maps::XskMap::get(&self, index: u32) -> core::option::Option +pub const fn aya_bpf::maps::XskMap::pinned(max_entries: u32, flags: u32) -> aya_bpf::maps::XskMap +pub fn aya_bpf::maps::XskMap::redirect(&self, index: u32, flags: u64) -> core::result::Result +pub const fn aya_bpf::maps::XskMap::with_max_entries(max_entries: u32, flags: u32) -> aya_bpf::maps::XskMap +impl core::marker::Sync for aya_bpf::maps::XskMap +impl core::marker::Send for aya_bpf::maps::XskMap +impl core::marker::Unpin for aya_bpf::maps::XskMap +impl !core::panic::unwind_safe::RefUnwindSafe for aya_bpf::maps::XskMap +impl core::panic::unwind_safe::UnwindSafe for aya_bpf::maps::XskMap +impl core::convert::Into for aya_bpf::maps::XskMap where U: core::convert::From +pub fn aya_bpf::maps::XskMap::into(self) -> U +impl core::convert::TryFrom for aya_bpf::maps::XskMap where U: core::convert::Into +pub type aya_bpf::maps::XskMap::Error = core::convert::Infallible +pub fn aya_bpf::maps::XskMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_bpf::maps::XskMap where U: core::convert::TryFrom +pub type aya_bpf::maps::XskMap::Error = >::Error +pub fn aya_bpf::maps::XskMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya_bpf::maps::XskMap where T: 'static + core::marker::Sized +pub fn aya_bpf::maps::XskMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_bpf::maps::XskMap where T: core::marker::Sized +pub fn aya_bpf::maps::XskMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_bpf::maps::XskMap where T: core::marker::Sized +pub fn aya_bpf::maps::XskMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_bpf::maps::XskMap +pub fn aya_bpf::maps::XskMap::from(t: T) -> T #[repr(transparent)] pub struct aya_bpf::maps::Array impl aya_bpf::maps::array::Array pub fn aya_bpf::maps::array::Array::get(&self, index: u32) -> core::option::Option<&T> @@ -618,6 +785,86 @@ impl core::borrow::BorrowMut for aya_bpf::maps::bloom_filter::BloomFilter< pub fn aya_bpf::maps::bloom_filter::BloomFilter::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya_bpf::maps::bloom_filter::BloomFilter pub fn aya_bpf::maps::bloom_filter::BloomFilter::from(t: T) -> T +#[repr(transparent)] pub struct aya_bpf::maps::CpuMap +impl aya_bpf::maps::CpuMap +pub const fn aya_bpf::maps::CpuMap::pinned(max_entries: u32, flags: u32) -> aya_bpf::maps::CpuMap +pub fn aya_bpf::maps::CpuMap::redirect(&self, index: u32, flags: u64) -> core::result::Result +pub const fn aya_bpf::maps::CpuMap::with_max_entries(max_entries: u32, flags: u32) -> aya_bpf::maps::CpuMap +impl core::marker::Sync for aya_bpf::maps::CpuMap +impl core::marker::Send for aya_bpf::maps::CpuMap +impl core::marker::Unpin for aya_bpf::maps::CpuMap +impl !core::panic::unwind_safe::RefUnwindSafe for aya_bpf::maps::CpuMap +impl core::panic::unwind_safe::UnwindSafe for aya_bpf::maps::CpuMap +impl core::convert::Into for aya_bpf::maps::CpuMap where U: core::convert::From +pub fn aya_bpf::maps::CpuMap::into(self) -> U +impl core::convert::TryFrom for aya_bpf::maps::CpuMap where U: core::convert::Into +pub type aya_bpf::maps::CpuMap::Error = core::convert::Infallible +pub fn aya_bpf::maps::CpuMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_bpf::maps::CpuMap where U: core::convert::TryFrom +pub type aya_bpf::maps::CpuMap::Error = >::Error +pub fn aya_bpf::maps::CpuMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya_bpf::maps::CpuMap where T: 'static + core::marker::Sized +pub fn aya_bpf::maps::CpuMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_bpf::maps::CpuMap where T: core::marker::Sized +pub fn aya_bpf::maps::CpuMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_bpf::maps::CpuMap where T: core::marker::Sized +pub fn aya_bpf::maps::CpuMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_bpf::maps::CpuMap +pub fn aya_bpf::maps::CpuMap::from(t: T) -> T +#[repr(transparent)] pub struct aya_bpf::maps::DevMap +impl aya_bpf::maps::DevMap +pub fn aya_bpf::maps::DevMap::get(&self, index: u32) -> core::option::Option +pub const fn aya_bpf::maps::DevMap::pinned(max_entries: u32, flags: u32) -> aya_bpf::maps::DevMap +pub fn aya_bpf::maps::DevMap::redirect(&self, index: u32, flags: u64) -> core::result::Result +pub const fn aya_bpf::maps::DevMap::with_max_entries(max_entries: u32, flags: u32) -> aya_bpf::maps::DevMap +impl core::marker::Sync for aya_bpf::maps::DevMap +impl core::marker::Send for aya_bpf::maps::DevMap +impl core::marker::Unpin for aya_bpf::maps::DevMap +impl !core::panic::unwind_safe::RefUnwindSafe for aya_bpf::maps::DevMap +impl core::panic::unwind_safe::UnwindSafe for aya_bpf::maps::DevMap +impl core::convert::Into for aya_bpf::maps::DevMap where U: core::convert::From +pub fn aya_bpf::maps::DevMap::into(self) -> U +impl core::convert::TryFrom for aya_bpf::maps::DevMap where U: core::convert::Into +pub type aya_bpf::maps::DevMap::Error = core::convert::Infallible +pub fn aya_bpf::maps::DevMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_bpf::maps::DevMap where U: core::convert::TryFrom +pub type aya_bpf::maps::DevMap::Error = >::Error +pub fn aya_bpf::maps::DevMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya_bpf::maps::DevMap where T: 'static + core::marker::Sized +pub fn aya_bpf::maps::DevMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_bpf::maps::DevMap where T: core::marker::Sized +pub fn aya_bpf::maps::DevMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_bpf::maps::DevMap where T: core::marker::Sized +pub fn aya_bpf::maps::DevMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_bpf::maps::DevMap +pub fn aya_bpf::maps::DevMap::from(t: T) -> T +#[repr(transparent)] pub struct aya_bpf::maps::DevMapHash +impl aya_bpf::maps::DevMapHash +pub fn aya_bpf::maps::DevMapHash::get(&self, key: u32) -> core::option::Option +pub const fn aya_bpf::maps::DevMapHash::pinned(max_entries: u32, flags: u32) -> aya_bpf::maps::DevMapHash +pub fn aya_bpf::maps::DevMapHash::redirect(&self, key: u32, flags: u64) -> core::result::Result +pub const fn aya_bpf::maps::DevMapHash::with_max_entries(max_entries: u32, flags: u32) -> aya_bpf::maps::DevMapHash +impl core::marker::Sync for aya_bpf::maps::DevMapHash +impl core::marker::Send for aya_bpf::maps::DevMapHash +impl core::marker::Unpin for aya_bpf::maps::DevMapHash +impl !core::panic::unwind_safe::RefUnwindSafe for aya_bpf::maps::DevMapHash +impl core::panic::unwind_safe::UnwindSafe for aya_bpf::maps::DevMapHash +impl core::convert::Into for aya_bpf::maps::DevMapHash where U: core::convert::From +pub fn aya_bpf::maps::DevMapHash::into(self) -> U +impl core::convert::TryFrom for aya_bpf::maps::DevMapHash where U: core::convert::Into +pub type aya_bpf::maps::DevMapHash::Error = core::convert::Infallible +pub fn aya_bpf::maps::DevMapHash::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_bpf::maps::DevMapHash where U: core::convert::TryFrom +pub type aya_bpf::maps::DevMapHash::Error = >::Error +pub fn aya_bpf::maps::DevMapHash::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya_bpf::maps::DevMapHash where T: 'static + core::marker::Sized +pub fn aya_bpf::maps::DevMapHash::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_bpf::maps::DevMapHash where T: core::marker::Sized +pub fn aya_bpf::maps::DevMapHash::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_bpf::maps::DevMapHash where T: core::marker::Sized +pub fn aya_bpf::maps::DevMapHash::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_bpf::maps::DevMapHash +pub fn aya_bpf::maps::DevMapHash::from(t: T) -> T #[repr(transparent)] pub struct aya_bpf::maps::HashMap impl aya_bpf::maps::hash_map::HashMap pub unsafe fn aya_bpf::maps::hash_map::HashMap::get(&self, key: &K) -> core::option::Option<&V> @@ -903,6 +1150,34 @@ impl core::borrow::BorrowMut for aya_bpf::maps::queue::Queue where T: c pub fn aya_bpf::maps::queue::Queue::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya_bpf::maps::queue::Queue pub fn aya_bpf::maps::queue::Queue::from(t: T) -> T +#[repr(transparent)] pub struct aya_bpf::maps::RingBuf +impl aya_bpf::maps::ring_buf::RingBuf +pub fn aya_bpf::maps::ring_buf::RingBuf::output(&self, data: &T, flags: u64) -> core::result::Result<(), i64> +pub const fn aya_bpf::maps::ring_buf::RingBuf::pinned(byte_size: u32, flags: u32) -> Self +pub fn aya_bpf::maps::ring_buf::RingBuf::query(&self, flags: u64) -> u64 +pub fn aya_bpf::maps::ring_buf::RingBuf::reserve(&self, flags: u64) -> core::option::Option> where const_assert::Assert<{ _ }>: const_assert::IsTrue +pub const fn aya_bpf::maps::ring_buf::RingBuf::with_byte_size(byte_size: u32, flags: u32) -> Self +impl core::marker::Sync for aya_bpf::maps::ring_buf::RingBuf +impl core::marker::Send for aya_bpf::maps::ring_buf::RingBuf +impl core::marker::Unpin for aya_bpf::maps::ring_buf::RingBuf +impl !core::panic::unwind_safe::RefUnwindSafe for aya_bpf::maps::ring_buf::RingBuf +impl core::panic::unwind_safe::UnwindSafe for aya_bpf::maps::ring_buf::RingBuf +impl core::convert::Into for aya_bpf::maps::ring_buf::RingBuf where U: core::convert::From +pub fn aya_bpf::maps::ring_buf::RingBuf::into(self) -> U +impl core::convert::TryFrom for aya_bpf::maps::ring_buf::RingBuf where U: core::convert::Into +pub type aya_bpf::maps::ring_buf::RingBuf::Error = core::convert::Infallible +pub fn aya_bpf::maps::ring_buf::RingBuf::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_bpf::maps::ring_buf::RingBuf where U: core::convert::TryFrom +pub type aya_bpf::maps::ring_buf::RingBuf::Error = >::Error +pub fn aya_bpf::maps::ring_buf::RingBuf::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya_bpf::maps::ring_buf::RingBuf where T: 'static + core::marker::Sized +pub fn aya_bpf::maps::ring_buf::RingBuf::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_bpf::maps::ring_buf::RingBuf where T: core::marker::Sized +pub fn aya_bpf::maps::ring_buf::RingBuf::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_bpf::maps::ring_buf::RingBuf where T: core::marker::Sized +pub fn aya_bpf::maps::ring_buf::RingBuf::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_bpf::maps::ring_buf::RingBuf +pub fn aya_bpf::maps::ring_buf::RingBuf::from(t: T) -> T #[repr(transparent)] pub struct aya_bpf::maps::SockHash impl aya_bpf::maps::sock_hash::SockHash pub const fn aya_bpf::maps::sock_hash::SockHash::pinned(max_entries: u32, flags: u32) -> aya_bpf::maps::sock_hash::SockHash @@ -1014,6 +1289,33 @@ impl core::borrow::BorrowMut for aya_bpf::maps::stack_trace::StackTrace wh pub fn aya_bpf::maps::stack_trace::StackTrace::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya_bpf::maps::stack_trace::StackTrace pub fn aya_bpf::maps::stack_trace::StackTrace::from(t: T) -> T +#[repr(transparent)] pub struct aya_bpf::maps::XskMap +impl aya_bpf::maps::XskMap +pub fn aya_bpf::maps::XskMap::get(&self, index: u32) -> core::option::Option +pub const fn aya_bpf::maps::XskMap::pinned(max_entries: u32, flags: u32) -> aya_bpf::maps::XskMap +pub fn aya_bpf::maps::XskMap::redirect(&self, index: u32, flags: u64) -> core::result::Result +pub const fn aya_bpf::maps::XskMap::with_max_entries(max_entries: u32, flags: u32) -> aya_bpf::maps::XskMap +impl core::marker::Sync for aya_bpf::maps::XskMap +impl core::marker::Send for aya_bpf::maps::XskMap +impl core::marker::Unpin for aya_bpf::maps::XskMap +impl !core::panic::unwind_safe::RefUnwindSafe for aya_bpf::maps::XskMap +impl core::panic::unwind_safe::UnwindSafe for aya_bpf::maps::XskMap +impl core::convert::Into for aya_bpf::maps::XskMap where U: core::convert::From +pub fn aya_bpf::maps::XskMap::into(self) -> U +impl core::convert::TryFrom for aya_bpf::maps::XskMap where U: core::convert::Into +pub type aya_bpf::maps::XskMap::Error = core::convert::Infallible +pub fn aya_bpf::maps::XskMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_bpf::maps::XskMap where U: core::convert::TryFrom +pub type aya_bpf::maps::XskMap::Error = >::Error +pub fn aya_bpf::maps::XskMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya_bpf::maps::XskMap where T: 'static + core::marker::Sized +pub fn aya_bpf::maps::XskMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_bpf::maps::XskMap where T: core::marker::Sized +pub fn aya_bpf::maps::XskMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_bpf::maps::XskMap where T: core::marker::Sized +pub fn aya_bpf::maps::XskMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_bpf::maps::XskMap +pub fn aya_bpf::maps::XskMap::from(t: T) -> T pub mod aya_bpf::programs pub mod aya_bpf::programs::device pub struct aya_bpf::programs::device::DeviceContext diff --git a/xtask/public-api/aya-log-common.txt b/xtask/public-api/aya-log-common.txt index fd921d9b..cc1621b5 100644 --- a/xtask/public-api/aya-log-common.txt +++ b/xtask/public-api/aya-log-common.txt @@ -60,7 +60,7 @@ pub fn u8::from(enum_value: aya_log_common::DisplayHint) -> Self impl core::clone::Clone for aya_log_common::DisplayHint pub fn aya_log_common::DisplayHint::clone(&self) -> aya_log_common::DisplayHint impl core::cmp::Eq for aya_log_common::DisplayHint -impl core::cmp::PartialEq for aya_log_common::DisplayHint +impl core::cmp::PartialEq for aya_log_common::DisplayHint pub fn aya_log_common::DisplayHint::eq(&self, other: &aya_log_common::DisplayHint) -> bool impl core::fmt::Debug for aya_log_common::DisplayHint pub fn aya_log_common::DisplayHint::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -99,7 +99,7 @@ pub fn u8::from(enum_value: aya_log_common::Level) -> Self impl core::clone::Clone for aya_log_common::Level pub fn aya_log_common::Level::clone(&self) -> aya_log_common::Level impl core::cmp::Eq for aya_log_common::Level -impl core::cmp::PartialEq for aya_log_common::Level +impl core::cmp::PartialEq for aya_log_common::Level pub fn aya_log_common::Level::eq(&self, other: &aya_log_common::Level) -> bool impl core::fmt::Debug for aya_log_common::Level pub fn aya_log_common::Level::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result diff --git a/xtask/public-api/aya-log-parser.txt b/xtask/public-api/aya-log-parser.txt index cf1f3493..3b933b14 100644 --- a/xtask/public-api/aya-log-parser.txt +++ b/xtask/public-api/aya-log-parser.txt @@ -5,7 +5,7 @@ pub aya_log_parser::Fragment::Parameter(aya_log_parser::Parameter) impl core::clone::Clone for aya_log_parser::Fragment pub fn aya_log_parser::Fragment::clone(&self) -> aya_log_parser::Fragment impl core::cmp::Eq for aya_log_parser::Fragment -impl core::cmp::PartialEq for aya_log_parser::Fragment +impl core::cmp::PartialEq for aya_log_parser::Fragment pub fn aya_log_parser::Fragment::eq(&self, other: &aya_log_parser::Fragment) -> bool impl core::fmt::Debug for aya_log_parser::Fragment pub fn aya_log_parser::Fragment::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -41,7 +41,7 @@ pub aya_log_parser::Parameter::hint: aya_log_common::DisplayHint impl core::clone::Clone for aya_log_parser::Parameter pub fn aya_log_parser::Parameter::clone(&self) -> aya_log_parser::Parameter impl core::cmp::Eq for aya_log_parser::Parameter -impl core::cmp::PartialEq for aya_log_parser::Parameter +impl core::cmp::PartialEq for aya_log_parser::Parameter pub fn aya_log_parser::Parameter::eq(&self, other: &aya_log_parser::Parameter) -> bool impl core::fmt::Debug for aya_log_parser::Parameter pub fn aya_log_parser::Parameter::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result diff --git a/xtask/public-api/aya-obj.txt b/xtask/public-api/aya-obj.txt index 574862f4..50f42ac4 100644 --- a/xtask/public-api/aya-obj.txt +++ b/xtask/public-api/aya-obj.txt @@ -98,7 +98,7 @@ pub fn aya_obj::btf::BtfKind::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> co impl core::clone::Clone for aya_obj::btf::BtfKind pub fn aya_obj::btf::BtfKind::clone(&self) -> aya_obj::btf::BtfKind impl core::cmp::Eq for aya_obj::btf::BtfKind -impl core::cmp::PartialEq for aya_obj::btf::BtfKind +impl core::cmp::PartialEq for aya_obj::btf::BtfKind pub fn aya_obj::btf::BtfKind::eq(&self, other: &aya_obj::btf::BtfKind) -> bool impl core::default::Default for aya_obj::btf::BtfKind pub fn aya_obj::btf::BtfKind::default() -> aya_obj::btf::BtfKind @@ -194,7 +194,7 @@ pub fn aya_obj::btf::FuncLinkage::from(v: u32) -> Self impl core::clone::Clone for aya_obj::btf::FuncLinkage pub fn aya_obj::btf::FuncLinkage::clone(&self) -> aya_obj::btf::FuncLinkage impl core::cmp::Eq for aya_obj::btf::FuncLinkage -impl core::cmp::PartialEq for aya_obj::btf::FuncLinkage +impl core::cmp::PartialEq for aya_obj::btf::FuncLinkage pub fn aya_obj::btf::FuncLinkage::eq(&self, other: &aya_obj::btf::FuncLinkage) -> bool impl core::fmt::Debug for aya_obj::btf::FuncLinkage pub fn aya_obj::btf::FuncLinkage::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -236,7 +236,7 @@ pub fn aya_obj::btf::IntEncoding::from(v: u32) -> Self impl core::clone::Clone for aya_obj::btf::IntEncoding pub fn aya_obj::btf::IntEncoding::clone(&self) -> aya_obj::btf::IntEncoding impl core::cmp::Eq for aya_obj::btf::IntEncoding -impl core::cmp::PartialEq for aya_obj::btf::IntEncoding +impl core::cmp::PartialEq for aya_obj::btf::IntEncoding pub fn aya_obj::btf::IntEncoding::eq(&self, other: &aya_obj::btf::IntEncoding) -> bool impl core::fmt::Debug for aya_obj::btf::IntEncoding pub fn aya_obj::btf::IntEncoding::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -277,7 +277,7 @@ pub fn aya_obj::btf::VarLinkage::from(v: u32) -> Self impl core::clone::Clone for aya_obj::btf::VarLinkage pub fn aya_obj::btf::VarLinkage::clone(&self) -> aya_obj::btf::VarLinkage impl core::cmp::Eq for aya_obj::btf::VarLinkage -impl core::cmp::PartialEq for aya_obj::btf::VarLinkage +impl core::cmp::PartialEq for aya_obj::btf::VarLinkage pub fn aya_obj::btf::VarLinkage::eq(&self, other: &aya_obj::btf::VarLinkage) -> bool impl core::fmt::Debug for aya_obj::btf::VarLinkage pub fn aya_obj::btf::VarLinkage::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -1342,10 +1342,12 @@ impl core::convert::From aya_obj::generated::bpf_attach_type impl core::convert::From for aya_obj::generated::bpf_attach_type pub fn aya_obj::generated::bpf_attach_type::from(s: aya_obj::programs::cgroup_sockopt::CgroupSockoptAttachType) -> aya_obj::generated::bpf_attach_type +impl core::convert::From for aya_obj::generated::bpf_attach_type +pub fn aya_obj::generated::bpf_attach_type::from(value: aya_obj::programs::xdp::XdpAttachType) -> Self impl core::clone::Clone for aya_obj::generated::bpf_attach_type pub fn aya_obj::generated::bpf_attach_type::clone(&self) -> aya_obj::generated::bpf_attach_type impl core::cmp::Eq for aya_obj::generated::bpf_attach_type -impl core::cmp::PartialEq for aya_obj::generated::bpf_attach_type +impl core::cmp::PartialEq for aya_obj::generated::bpf_attach_type pub fn aya_obj::generated::bpf_attach_type::eq(&self, other: &aya_obj::generated::bpf_attach_type) -> bool impl core::fmt::Debug for aya_obj::generated::bpf_attach_type pub fn aya_obj::generated::bpf_attach_type::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -1421,7 +1423,7 @@ pub const aya_obj::generated::bpf_cmd::BPF_PROG_RUN: aya_obj::generated::bpf_cmd impl core::clone::Clone for aya_obj::generated::bpf_cmd pub fn aya_obj::generated::bpf_cmd::clone(&self) -> aya_obj::generated::bpf_cmd impl core::cmp::Eq for aya_obj::generated::bpf_cmd -impl core::cmp::PartialEq for aya_obj::generated::bpf_cmd +impl core::cmp::PartialEq for aya_obj::generated::bpf_cmd pub fn aya_obj::generated::bpf_cmd::eq(&self, other: &aya_obj::generated::bpf_cmd) -> bool impl core::fmt::Debug for aya_obj::generated::bpf_cmd pub fn aya_obj::generated::bpf_cmd::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -1471,7 +1473,7 @@ pub aya_obj::generated::bpf_link_type::MAX_BPF_LINK_TYPE = 11 impl core::clone::Clone for aya_obj::generated::bpf_link_type pub fn aya_obj::generated::bpf_link_type::clone(&self) -> aya_obj::generated::bpf_link_type impl core::cmp::Eq for aya_obj::generated::bpf_link_type -impl core::cmp::PartialEq for aya_obj::generated::bpf_link_type +impl core::cmp::PartialEq for aya_obj::generated::bpf_link_type pub fn aya_obj::generated::bpf_link_type::eq(&self, other: &aya_obj::generated::bpf_link_type) -> bool impl core::fmt::Debug for aya_obj::generated::bpf_link_type pub fn aya_obj::generated::bpf_link_type::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -1547,7 +1549,7 @@ pub fn aya_obj::generated::bpf_map_type::try_from(map_type: u32) -> core::result impl core::clone::Clone for aya_obj::generated::bpf_map_type pub fn aya_obj::generated::bpf_map_type::clone(&self) -> aya_obj::generated::bpf_map_type impl core::cmp::Eq for aya_obj::generated::bpf_map_type -impl core::cmp::PartialEq for aya_obj::generated::bpf_map_type +impl core::cmp::PartialEq for aya_obj::generated::bpf_map_type pub fn aya_obj::generated::bpf_map_type::eq(&self, other: &aya_obj::generated::bpf_map_type) -> bool impl core::fmt::Debug for aya_obj::generated::bpf_map_type pub fn aya_obj::generated::bpf_map_type::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -1618,7 +1620,7 @@ pub aya_obj::generated::bpf_prog_type::BPF_PROG_TYPE_XDP = 6 impl core::clone::Clone for aya_obj::generated::bpf_prog_type pub fn aya_obj::generated::bpf_prog_type::clone(&self) -> aya_obj::generated::bpf_prog_type impl core::cmp::Eq for aya_obj::generated::bpf_prog_type -impl core::cmp::PartialEq for aya_obj::generated::bpf_prog_type +impl core::cmp::PartialEq for aya_obj::generated::bpf_prog_type pub fn aya_obj::generated::bpf_prog_type::eq(&self, other: &aya_obj::generated::bpf_prog_type) -> bool impl core::fmt::Debug for aya_obj::generated::bpf_prog_type pub fn aya_obj::generated::bpf_prog_type::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -1659,7 +1661,7 @@ pub aya_obj::generated::btf_func_linkage::BTF_FUNC_STATIC = 0 impl core::clone::Clone for aya_obj::generated::btf_func_linkage pub fn aya_obj::generated::btf_func_linkage::clone(&self) -> aya_obj::generated::btf_func_linkage impl core::cmp::Eq for aya_obj::generated::btf_func_linkage -impl core::cmp::PartialEq for aya_obj::generated::btf_func_linkage +impl core::cmp::PartialEq for aya_obj::generated::btf_func_linkage pub fn aya_obj::generated::btf_func_linkage::eq(&self, other: &aya_obj::generated::btf_func_linkage) -> bool impl core::fmt::Debug for aya_obj::generated::btf_func_linkage pub fn aya_obj::generated::btf_func_linkage::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -1723,7 +1725,7 @@ pub aya_obj::generated::perf_event_sample_format::PERF_SAMPLE_WEIGHT_STRUCT = 16 impl core::clone::Clone for aya_obj::generated::perf_event_sample_format pub fn aya_obj::generated::perf_event_sample_format::clone(&self) -> aya_obj::generated::perf_event_sample_format impl core::cmp::Eq for aya_obj::generated::perf_event_sample_format -impl core::cmp::PartialEq for aya_obj::generated::perf_event_sample_format +impl core::cmp::PartialEq for aya_obj::generated::perf_event_sample_format pub fn aya_obj::generated::perf_event_sample_format::eq(&self, other: &aya_obj::generated::perf_event_sample_format) -> bool impl core::fmt::Debug for aya_obj::generated::perf_event_sample_format pub fn aya_obj::generated::perf_event_sample_format::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -1783,7 +1785,7 @@ pub aya_obj::generated::perf_event_type::PERF_RECORD_UNTHROTTLE = 6 impl core::clone::Clone for aya_obj::generated::perf_event_type pub fn aya_obj::generated::perf_event_type::clone(&self) -> aya_obj::generated::perf_event_type impl core::cmp::Eq for aya_obj::generated::perf_event_type -impl core::cmp::PartialEq for aya_obj::generated::perf_event_type +impl core::cmp::PartialEq for aya_obj::generated::perf_event_type pub fn aya_obj::generated::perf_event_type::eq(&self, other: &aya_obj::generated::perf_event_type) -> bool impl core::fmt::Debug for aya_obj::generated::perf_event_type pub fn aya_obj::generated::perf_event_type::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -1829,7 +1831,7 @@ pub aya_obj::generated::perf_hw_cache_id::PERF_COUNT_HW_CACHE_NODE = 6 impl core::clone::Clone for aya_obj::generated::perf_hw_cache_id pub fn aya_obj::generated::perf_hw_cache_id::clone(&self) -> aya_obj::generated::perf_hw_cache_id impl core::cmp::Eq for aya_obj::generated::perf_hw_cache_id -impl core::cmp::PartialEq for aya_obj::generated::perf_hw_cache_id +impl core::cmp::PartialEq for aya_obj::generated::perf_hw_cache_id pub fn aya_obj::generated::perf_hw_cache_id::eq(&self, other: &aya_obj::generated::perf_hw_cache_id) -> bool impl core::fmt::Debug for aya_obj::generated::perf_hw_cache_id pub fn aya_obj::generated::perf_hw_cache_id::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -1871,7 +1873,7 @@ pub aya_obj::generated::perf_hw_cache_op_id::PERF_COUNT_HW_CACHE_OP_WRITE = 1 impl core::clone::Clone for aya_obj::generated::perf_hw_cache_op_id pub fn aya_obj::generated::perf_hw_cache_op_id::clone(&self) -> aya_obj::generated::perf_hw_cache_op_id impl core::cmp::Eq for aya_obj::generated::perf_hw_cache_op_id -impl core::cmp::PartialEq for aya_obj::generated::perf_hw_cache_op_id +impl core::cmp::PartialEq for aya_obj::generated::perf_hw_cache_op_id pub fn aya_obj::generated::perf_hw_cache_op_id::eq(&self, other: &aya_obj::generated::perf_hw_cache_op_id) -> bool impl core::fmt::Debug for aya_obj::generated::perf_hw_cache_op_id pub fn aya_obj::generated::perf_hw_cache_op_id::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -1912,7 +1914,7 @@ pub aya_obj::generated::perf_hw_cache_op_result_id::PERF_COUNT_HW_CACHE_RESULT_M impl core::clone::Clone for aya_obj::generated::perf_hw_cache_op_result_id pub fn aya_obj::generated::perf_hw_cache_op_result_id::clone(&self) -> aya_obj::generated::perf_hw_cache_op_result_id impl core::cmp::Eq for aya_obj::generated::perf_hw_cache_op_result_id -impl core::cmp::PartialEq for aya_obj::generated::perf_hw_cache_op_result_id +impl core::cmp::PartialEq for aya_obj::generated::perf_hw_cache_op_result_id pub fn aya_obj::generated::perf_hw_cache_op_result_id::eq(&self, other: &aya_obj::generated::perf_hw_cache_op_result_id) -> bool impl core::fmt::Debug for aya_obj::generated::perf_hw_cache_op_result_id pub fn aya_obj::generated::perf_hw_cache_op_result_id::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -1961,7 +1963,7 @@ pub aya_obj::generated::perf_hw_id::PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7 impl core::clone::Clone for aya_obj::generated::perf_hw_id pub fn aya_obj::generated::perf_hw_id::clone(&self) -> aya_obj::generated::perf_hw_id impl core::cmp::Eq for aya_obj::generated::perf_hw_id -impl core::cmp::PartialEq for aya_obj::generated::perf_hw_id +impl core::cmp::PartialEq for aya_obj::generated::perf_hw_id pub fn aya_obj::generated::perf_hw_id::eq(&self, other: &aya_obj::generated::perf_hw_id) -> bool impl core::fmt::Debug for aya_obj::generated::perf_hw_id pub fn aya_obj::generated::perf_hw_id::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -2012,7 +2014,7 @@ pub aya_obj::generated::perf_sw_ids::PERF_COUNT_SW_TASK_CLOCK = 1 impl core::clone::Clone for aya_obj::generated::perf_sw_ids pub fn aya_obj::generated::perf_sw_ids::clone(&self) -> aya_obj::generated::perf_sw_ids impl core::cmp::Eq for aya_obj::generated::perf_sw_ids -impl core::cmp::PartialEq for aya_obj::generated::perf_sw_ids +impl core::cmp::PartialEq for aya_obj::generated::perf_sw_ids pub fn aya_obj::generated::perf_sw_ids::eq(&self, other: &aya_obj::generated::perf_sw_ids) -> bool impl core::fmt::Debug for aya_obj::generated::perf_sw_ids pub fn aya_obj::generated::perf_sw_ids::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -2057,7 +2059,7 @@ pub aya_obj::generated::perf_type_id::PERF_TYPE_TRACEPOINT = 2 impl core::clone::Clone for aya_obj::generated::perf_type_id pub fn aya_obj::generated::perf_type_id::clone(&self) -> aya_obj::generated::perf_type_id impl core::cmp::Eq for aya_obj::generated::perf_type_id -impl core::cmp::PartialEq for aya_obj::generated::perf_type_id +impl core::cmp::PartialEq for aya_obj::generated::perf_type_id pub fn aya_obj::generated::perf_type_id::eq(&self, other: &aya_obj::generated::perf_type_id) -> bool impl core::fmt::Debug for aya_obj::generated::perf_type_id pub fn aya_obj::generated::perf_type_id::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -2757,9 +2759,9 @@ pub fn aya_obj::generated::__BindgenBitfieldUnit::clone(&self) -> aya_o impl core::cmp::Eq for aya_obj::generated::__BindgenBitfieldUnit impl core::cmp::Ord for aya_obj::generated::__BindgenBitfieldUnit pub fn aya_obj::generated::__BindgenBitfieldUnit::cmp(&self, other: &aya_obj::generated::__BindgenBitfieldUnit) -> core::cmp::Ordering -impl core::cmp::PartialEq> for aya_obj::generated::__BindgenBitfieldUnit +impl core::cmp::PartialEq for aya_obj::generated::__BindgenBitfieldUnit pub fn aya_obj::generated::__BindgenBitfieldUnit::eq(&self, other: &aya_obj::generated::__BindgenBitfieldUnit) -> bool -impl core::cmp::PartialOrd> for aya_obj::generated::__BindgenBitfieldUnit +impl core::cmp::PartialOrd for aya_obj::generated::__BindgenBitfieldUnit pub fn aya_obj::generated::__BindgenBitfieldUnit::partial_cmp(&self, other: &aya_obj::generated::__BindgenBitfieldUnit) -> core::option::Option impl core::default::Default for aya_obj::generated::__BindgenBitfieldUnit pub fn aya_obj::generated::__BindgenBitfieldUnit::default() -> aya_obj::generated::__BindgenBitfieldUnit @@ -5411,6 +5413,7 @@ pub fn aya_obj::maps::Map::pinning(&self) -> aya_obj::maps::PinningType pub fn aya_obj::maps::Map::section_index(&self) -> usize pub fn aya_obj::maps::Map::section_kind(&self) -> aya_obj::BpfSectionKind pub fn aya_obj::maps::Map::set_max_entries(&mut self, v: u32) +pub fn aya_obj::maps::Map::set_value_size(&mut self, size: u32) pub fn aya_obj::maps::Map::symbol_index(&self) -> core::option::Option pub fn aya_obj::maps::Map::value_size(&self) -> u32 impl core::clone::Clone for aya_obj::maps::Map @@ -5482,7 +5485,7 @@ pub fn aya_obj::maps::PinningType::try_from(value: u32) -> core::result::Result< impl core::clone::Clone for aya_obj::maps::PinningType pub fn aya_obj::maps::PinningType::clone(&self) -> aya_obj::maps::PinningType impl core::cmp::Eq for aya_obj::maps::PinningType -impl core::cmp::PartialEq for aya_obj::maps::PinningType +impl core::cmp::PartialEq for aya_obj::maps::PinningType pub fn aya_obj::maps::PinningType::eq(&self, other: &aya_obj::maps::PinningType) -> bool impl core::default::Default for aya_obj::maps::PinningType pub fn aya_obj::maps::PinningType::default() -> aya_obj::maps::PinningType @@ -5553,7 +5556,7 @@ pub aya_obj::maps::BtfMapDef::btf_value_type_id: u32 impl core::clone::Clone for aya_obj::maps::BtfMapDef pub fn aya_obj::maps::BtfMapDef::clone(&self) -> aya_obj::maps::BtfMapDef impl core::cmp::Eq for aya_obj::maps::BtfMapDef -impl core::cmp::PartialEq for aya_obj::maps::BtfMapDef +impl core::cmp::PartialEq for aya_obj::maps::BtfMapDef pub fn aya_obj::maps::BtfMapDef::eq(&self, other: &aya_obj::maps::BtfMapDef) -> bool impl core::default::Default for aya_obj::maps::BtfMapDef pub fn aya_obj::maps::BtfMapDef::default() -> aya_obj::maps::BtfMapDef @@ -5656,7 +5659,7 @@ pub aya_obj::maps::bpf_map_def::value_size: u32 impl core::clone::Clone for aya_obj::maps::bpf_map_def pub fn aya_obj::maps::bpf_map_def::clone(&self) -> aya_obj::maps::bpf_map_def impl core::cmp::Eq for aya_obj::maps::bpf_map_def -impl core::cmp::PartialEq for aya_obj::maps::bpf_map_def +impl core::cmp::PartialEq for aya_obj::maps::bpf_map_def pub fn aya_obj::maps::bpf_map_def::eq(&self, other: &aya_obj::maps::bpf_map_def) -> bool impl core::default::Default for aya_obj::maps::bpf_map_def pub fn aya_obj::maps::bpf_map_def::default() -> aya_obj::maps::bpf_map_def @@ -5707,7 +5710,7 @@ pub aya_obj::obj::BpfSectionKind::Version impl core::clone::Clone for aya_obj::BpfSectionKind pub fn aya_obj::BpfSectionKind::clone(&self) -> aya_obj::BpfSectionKind impl core::cmp::Eq for aya_obj::BpfSectionKind -impl core::cmp::PartialEq for aya_obj::BpfSectionKind +impl core::cmp::PartialEq for aya_obj::BpfSectionKind pub fn aya_obj::BpfSectionKind::eq(&self, other: &aya_obj::BpfSectionKind) -> bool impl core::fmt::Debug for aya_obj::BpfSectionKind pub fn aya_obj::BpfSectionKind::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -5848,6 +5851,7 @@ pub aya_obj::obj::ProgramSection::UProbe::sleepable: bool pub aya_obj::obj::ProgramSection::URetProbe pub aya_obj::obj::ProgramSection::URetProbe::sleepable: bool pub aya_obj::obj::ProgramSection::Xdp +pub aya_obj::obj::ProgramSection::Xdp::attach_type: aya_obj::programs::xdp::XdpAttachType pub aya_obj::obj::ProgramSection::Xdp::frags: bool impl core::str::traits::FromStr for aya_obj::ProgramSection pub type aya_obj::ProgramSection::Err = aya_obj::ParseError @@ -5889,6 +5893,8 @@ pub fn aya_obj::Features::bpf_name(&self) -> bool pub fn aya_obj::Features::bpf_perf_link(&self) -> bool pub fn aya_obj::Features::bpf_probe_read_kernel(&self) -> bool pub fn aya_obj::Features::btf(&self) -> core::option::Option<&aya_obj::btf::BtfFeatures> +pub fn aya_obj::Features::cpumap_prog_id(&self) -> bool +pub fn aya_obj::Features::devmap_prog_id(&self) -> bool impl core::default::Default for aya_obj::Features pub fn aya_obj::Features::default() -> aya_obj::Features impl core::fmt::Debug for aya_obj::Features @@ -5972,7 +5978,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>(&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 @@ -6164,6 +6170,43 @@ impl core::borrow::BorrowMut for aya_obj::programs::cgroup_sockopt::Cgroup pub fn aya_obj::programs::cgroup_sockopt::CgroupSockoptAttachType::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya_obj::programs::cgroup_sockopt::CgroupSockoptAttachType pub fn aya_obj::programs::cgroup_sockopt::CgroupSockoptAttachType::from(t: T) -> T +pub mod aya_obj::programs::xdp +pub enum aya_obj::programs::xdp::XdpAttachType +pub aya_obj::programs::xdp::XdpAttachType::CpuMap +pub aya_obj::programs::xdp::XdpAttachType::DevMap +pub aya_obj::programs::xdp::XdpAttachType::Interface +impl core::convert::From for aya_obj::generated::bpf_attach_type +pub fn aya_obj::generated::bpf_attach_type::from(value: aya_obj::programs::xdp::XdpAttachType) -> Self +impl core::clone::Clone for aya_obj::programs::xdp::XdpAttachType +pub fn aya_obj::programs::xdp::XdpAttachType::clone(&self) -> aya_obj::programs::xdp::XdpAttachType +impl core::fmt::Debug for aya_obj::programs::xdp::XdpAttachType +pub fn aya_obj::programs::xdp::XdpAttachType::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for aya_obj::programs::xdp::XdpAttachType +impl core::marker::Send for aya_obj::programs::xdp::XdpAttachType +impl core::marker::Sync for aya_obj::programs::xdp::XdpAttachType +impl core::marker::Unpin for aya_obj::programs::xdp::XdpAttachType +impl core::panic::unwind_safe::RefUnwindSafe for aya_obj::programs::xdp::XdpAttachType +impl core::panic::unwind_safe::UnwindSafe for aya_obj::programs::xdp::XdpAttachType +impl core::convert::Into for aya_obj::programs::xdp::XdpAttachType where U: core::convert::From +pub fn aya_obj::programs::xdp::XdpAttachType::into(self) -> U +impl core::convert::TryFrom for aya_obj::programs::xdp::XdpAttachType where U: core::convert::Into +pub type aya_obj::programs::xdp::XdpAttachType::Error = core::convert::Infallible +pub fn aya_obj::programs::xdp::XdpAttachType::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_obj::programs::xdp::XdpAttachType where U: core::convert::TryFrom +pub type aya_obj::programs::xdp::XdpAttachType::Error = >::Error +pub fn aya_obj::programs::xdp::XdpAttachType::try_into(self) -> core::result::Result>::Error> +impl alloc::borrow::ToOwned for aya_obj::programs::xdp::XdpAttachType where T: core::clone::Clone +pub type aya_obj::programs::xdp::XdpAttachType::Owned = T +pub fn aya_obj::programs::xdp::XdpAttachType::clone_into(&self, target: &mut T) +pub fn aya_obj::programs::xdp::XdpAttachType::to_owned(&self) -> T +impl core::any::Any for aya_obj::programs::xdp::XdpAttachType where T: 'static + core::marker::Sized +pub fn aya_obj::programs::xdp::XdpAttachType::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_obj::programs::xdp::XdpAttachType where T: core::marker::Sized +pub fn aya_obj::programs::xdp::XdpAttachType::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_obj::programs::xdp::XdpAttachType where T: core::marker::Sized +pub fn aya_obj::programs::xdp::XdpAttachType::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_obj::programs::xdp::XdpAttachType +pub fn aya_obj::programs::xdp::XdpAttachType::from(t: T) -> T pub enum aya_obj::programs::CgroupSockAddrAttachType pub aya_obj::programs::CgroupSockAddrAttachType::Bind4 pub aya_obj::programs::CgroupSockAddrAttachType::Bind6 @@ -6283,6 +6326,42 @@ impl core::borrow::BorrowMut for aya_obj::programs::cgroup_sockopt::Cgroup pub fn aya_obj::programs::cgroup_sockopt::CgroupSockoptAttachType::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya_obj::programs::cgroup_sockopt::CgroupSockoptAttachType pub fn aya_obj::programs::cgroup_sockopt::CgroupSockoptAttachType::from(t: T) -> T +pub enum aya_obj::programs::XdpAttachType +pub aya_obj::programs::XdpAttachType::CpuMap +pub aya_obj::programs::XdpAttachType::DevMap +pub aya_obj::programs::XdpAttachType::Interface +impl core::convert::From for aya_obj::generated::bpf_attach_type +pub fn aya_obj::generated::bpf_attach_type::from(value: aya_obj::programs::xdp::XdpAttachType) -> Self +impl core::clone::Clone for aya_obj::programs::xdp::XdpAttachType +pub fn aya_obj::programs::xdp::XdpAttachType::clone(&self) -> aya_obj::programs::xdp::XdpAttachType +impl core::fmt::Debug for aya_obj::programs::xdp::XdpAttachType +pub fn aya_obj::programs::xdp::XdpAttachType::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Copy for aya_obj::programs::xdp::XdpAttachType +impl core::marker::Send for aya_obj::programs::xdp::XdpAttachType +impl core::marker::Sync for aya_obj::programs::xdp::XdpAttachType +impl core::marker::Unpin for aya_obj::programs::xdp::XdpAttachType +impl core::panic::unwind_safe::RefUnwindSafe for aya_obj::programs::xdp::XdpAttachType +impl core::panic::unwind_safe::UnwindSafe for aya_obj::programs::xdp::XdpAttachType +impl core::convert::Into for aya_obj::programs::xdp::XdpAttachType where U: core::convert::From +pub fn aya_obj::programs::xdp::XdpAttachType::into(self) -> U +impl core::convert::TryFrom for aya_obj::programs::xdp::XdpAttachType where U: core::convert::Into +pub type aya_obj::programs::xdp::XdpAttachType::Error = core::convert::Infallible +pub fn aya_obj::programs::xdp::XdpAttachType::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya_obj::programs::xdp::XdpAttachType where U: core::convert::TryFrom +pub type aya_obj::programs::xdp::XdpAttachType::Error = >::Error +pub fn aya_obj::programs::xdp::XdpAttachType::try_into(self) -> core::result::Result>::Error> +impl alloc::borrow::ToOwned for aya_obj::programs::xdp::XdpAttachType where T: core::clone::Clone +pub type aya_obj::programs::xdp::XdpAttachType::Owned = T +pub fn aya_obj::programs::xdp::XdpAttachType::clone_into(&self, target: &mut T) +pub fn aya_obj::programs::xdp::XdpAttachType::to_owned(&self) -> T +impl core::any::Any for aya_obj::programs::xdp::XdpAttachType where T: 'static + core::marker::Sized +pub fn aya_obj::programs::xdp::XdpAttachType::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya_obj::programs::xdp::XdpAttachType where T: core::marker::Sized +pub fn aya_obj::programs::xdp::XdpAttachType::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya_obj::programs::xdp::XdpAttachType where T: core::marker::Sized +pub fn aya_obj::programs::xdp::XdpAttachType::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya_obj::programs::xdp::XdpAttachType +pub fn aya_obj::programs::xdp::XdpAttachType::from(t: T) -> T pub mod aya_obj::relocation pub enum aya_obj::relocation::RelocationError pub aya_obj::relocation::RelocationError::InvalidRelocationOffset @@ -6374,7 +6453,7 @@ pub aya_obj::BpfSectionKind::Version impl core::clone::Clone for aya_obj::BpfSectionKind pub fn aya_obj::BpfSectionKind::clone(&self) -> aya_obj::BpfSectionKind impl core::cmp::Eq for aya_obj::BpfSectionKind -impl core::cmp::PartialEq for aya_obj::BpfSectionKind +impl core::cmp::PartialEq for aya_obj::BpfSectionKind pub fn aya_obj::BpfSectionKind::eq(&self, other: &aya_obj::BpfSectionKind) -> bool impl core::fmt::Debug for aya_obj::BpfSectionKind pub fn aya_obj::BpfSectionKind::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -6420,6 +6499,7 @@ pub fn aya_obj::maps::Map::pinning(&self) -> aya_obj::maps::PinningType pub fn aya_obj::maps::Map::section_index(&self) -> usize pub fn aya_obj::maps::Map::section_kind(&self) -> aya_obj::BpfSectionKind pub fn aya_obj::maps::Map::set_max_entries(&mut self, v: u32) +pub fn aya_obj::maps::Map::set_value_size(&mut self, size: u32) pub fn aya_obj::maps::Map::symbol_index(&self) -> core::option::Option pub fn aya_obj::maps::Map::value_size(&self) -> u32 impl core::clone::Clone for aya_obj::maps::Map @@ -6560,6 +6640,7 @@ pub aya_obj::ProgramSection::UProbe::sleepable: bool pub aya_obj::ProgramSection::URetProbe pub aya_obj::ProgramSection::URetProbe::sleepable: bool pub aya_obj::ProgramSection::Xdp +pub aya_obj::ProgramSection::Xdp::attach_type: aya_obj::programs::xdp::XdpAttachType pub aya_obj::ProgramSection::Xdp::frags: bool impl core::str::traits::FromStr for aya_obj::ProgramSection pub type aya_obj::ProgramSection::Err = aya_obj::ParseError @@ -6601,6 +6682,8 @@ pub fn aya_obj::Features::bpf_name(&self) -> bool pub fn aya_obj::Features::bpf_perf_link(&self) -> bool pub fn aya_obj::Features::bpf_probe_read_kernel(&self) -> bool pub fn aya_obj::Features::btf(&self) -> core::option::Option<&aya_obj::btf::BtfFeatures> +pub fn aya_obj::Features::cpumap_prog_id(&self) -> bool +pub fn aya_obj::Features::devmap_prog_id(&self) -> bool impl core::default::Default for aya_obj::Features pub fn aya_obj::Features::default() -> aya_obj::Features impl core::fmt::Debug for aya_obj::Features @@ -6684,7 +6767,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>(&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.txt b/xtask/public-api/aya.txt index ebf7699f..196e0cec 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -12,19 +12,21 @@ pub fn aya::maps::array::Array::get(&self, index: &u32, flags: u64) -> cor pub fn aya::maps::array::Array::iter(&self) -> impl core::iter::traits::iterator::Iterator> + '_ pub fn aya::maps::array::Array::len(&self) -> u32 impl, V: aya::Pod> aya::maps::array::Array +pub fn aya::maps::array::Array::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl, V: aya::Pod> aya::maps::array::Array pub fn aya::maps::array::Array::set(&mut self, index: u32, 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::array::Array<&'a aya::maps::MapData, V> pub type aya::maps::array::Array<&'a aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::array::Array<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::array::Array<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::array::Array<&'a mut aya::maps::MapData, V> pub type aya::maps::array::Array<&'a mut aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::array::Array<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::array::Array<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl, V: aya::Pod> aya::maps::IterableMap for aya::maps::array::Array pub fn aya::maps::array::Array::get(&self, index: &u32) -> core::result::Result pub fn aya::maps::array::Array::map(&self) -> &aya::maps::MapData impl core::convert::TryFrom for aya::maps::array::Array pub type aya::maps::array::Array::Error = aya::maps::MapError -pub fn aya::maps::array::Array::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::array::Array::try_from(map: aya::maps::Map) -> core::result::Result impl core::marker::Send for aya::maps::array::Array where T: core::marker::Send, V: core::marker::Send impl core::marker::Sync for aya::maps::array::Array where T: core::marker::Sync, V: core::marker::Sync impl core::marker::Unpin for aya::maps::array::Array where T: core::marker::Unpin, V: core::marker::Unpin @@ -52,19 +54,21 @@ pub fn aya::maps::PerCpuArray::get(&self, index: &u32, flags: u64) -> core pub fn aya::maps::PerCpuArray::iter(&self) -> impl core::iter::traits::iterator::Iterator, aya::maps::MapError>> + '_ pub fn aya::maps::PerCpuArray::len(&self) -> u32 impl, V: aya::Pod> aya::maps::PerCpuArray +pub fn aya::maps::PerCpuArray::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl, V: aya::Pod> aya::maps::PerCpuArray pub fn aya::maps::PerCpuArray::set(&mut self, index: u32, values: aya::maps::PerCpuValues, flags: u64) -> core::result::Result<(), aya::maps::MapError> impl<'a, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::PerCpuArray<&'a aya::maps::MapData, V> pub type aya::maps::PerCpuArray<&'a aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::PerCpuArray<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::PerCpuArray<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::PerCpuArray<&'a mut aya::maps::MapData, V> pub type aya::maps::PerCpuArray<&'a mut aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::PerCpuArray<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::PerCpuArray<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl, V: aya::Pod> aya::maps::IterableMap> for aya::maps::PerCpuArray pub fn aya::maps::PerCpuArray::get(&self, index: &u32) -> core::result::Result, aya::maps::MapError> pub fn aya::maps::PerCpuArray::map(&self) -> &aya::maps::MapData impl core::convert::TryFrom for aya::maps::PerCpuArray pub type aya::maps::PerCpuArray::Error = aya::maps::MapError -pub fn aya::maps::PerCpuArray::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::PerCpuArray::try_from(map: aya::maps::Map) -> core::result::Result impl core::marker::Send for aya::maps::PerCpuArray where T: core::marker::Send, V: core::marker::Send impl core::marker::Sync for aya::maps::PerCpuArray where T: core::marker::Sync, V: core::marker::Sync impl core::marker::Unpin for aya::maps::PerCpuArray where T: core::marker::Unpin, V: core::marker::Unpin @@ -92,15 +96,17 @@ 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> +impl> aya::maps::ProgramArray +pub fn aya::maps::ProgramArray::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> 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> +pub fn aya::maps::ProgramArray::try_from(map: aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::ProgramArray<&'a aya::maps::MapData> pub type aya::maps::ProgramArray<&'a aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::ProgramArray<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::ProgramArray<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::ProgramArray<&'a mut aya::maps::MapData> pub type aya::maps::ProgramArray<&'a mut aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::ProgramArray<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::ProgramArray<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl core::marker::Send for aya::maps::ProgramArray where T: core::marker::Send impl core::marker::Sync for aya::maps::ProgramArray where T: core::marker::Sync impl core::marker::Unpin for aya::maps::ProgramArray where T: core::marker::Unpin @@ -128,15 +134,17 @@ impl, V: aya::Pod> aya::maps::bloom_ pub fn aya::maps::bloom_filter::BloomFilter::contains(&self, value: &V, 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, V: aya::Pod> aya::maps::bloom_filter::BloomFilter +pub fn aya::maps::bloom_filter::BloomFilter::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> 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> +pub fn aya::maps::bloom_filter::BloomFilter<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::bloom_filter::BloomFilter<&'a mut aya::maps::MapData, V> pub type aya::maps::bloom_filter::BloomFilter<&'a mut aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::bloom_filter::BloomFilter<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::bloom_filter::BloomFilter<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl core::convert::TryFrom for aya::maps::bloom_filter::BloomFilter pub type aya::maps::bloom_filter::BloomFilter::Error = aya::maps::MapError -pub fn aya::maps::bloom_filter::BloomFilter::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::bloom_filter::BloomFilter::try_from(map: aya::maps::Map) -> core::result::Result impl core::fmt::Debug for aya::maps::bloom_filter::BloomFilter pub fn aya::maps::bloom_filter::BloomFilter::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Send for aya::maps::bloom_filter::BloomFilter where T: core::marker::Send, V: core::marker::Send @@ -169,18 +177,20 @@ pub fn aya::maps::hash_map::HashMap::keys(&self) -> aya::maps::MapKeys< impl, K: aya::Pod, V: aya::Pod> aya::maps::hash_map::HashMap pub fn aya::maps::hash_map::HashMap::insert(&mut self, key: impl core::borrow::Borrow, value: impl core::borrow::Borrow, flags: u64) -> core::result::Result<(), aya::maps::MapError> pub fn aya::maps::hash_map::HashMap::remove(&mut self, key: &K) -> core::result::Result<(), aya::maps::MapError> -impl<'a, V: aya::Pod, K: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::hash_map::HashMap<&'a aya::maps::MapData, V, K> -pub type aya::maps::hash_map::HashMap<&'a aya::maps::MapData, V, K>::Error = aya::maps::MapError -pub fn aya::maps::hash_map::HashMap<&'a aya::maps::MapData, V, K>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> -impl<'a, V: aya::Pod, K: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::hash_map::HashMap<&'a mut aya::maps::MapData, V, K> -pub type aya::maps::hash_map::HashMap<&'a mut aya::maps::MapData, V, K>::Error = aya::maps::MapError -pub fn aya::maps::hash_map::HashMap<&'a mut aya::maps::MapData, V, K>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +impl, K: aya::Pod, V: aya::Pod> aya::maps::hash_map::HashMap +pub fn aya::maps::hash_map::HashMap::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl<'a, K: aya::Pod, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::hash_map::HashMap<&'a aya::maps::MapData, K, V> +pub type aya::maps::hash_map::HashMap<&'a aya::maps::MapData, K, V>::Error = aya::maps::MapError +pub fn aya::maps::hash_map::HashMap<&'a aya::maps::MapData, K, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a, K: aya::Pod, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::hash_map::HashMap<&'a mut aya::maps::MapData, K, V> +pub type aya::maps::hash_map::HashMap<&'a mut aya::maps::MapData, K, V>::Error = aya::maps::MapError +pub fn aya::maps::hash_map::HashMap<&'a mut aya::maps::MapData, K, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::convert::TryFrom for aya::maps::hash_map::HashMap +pub type aya::maps::hash_map::HashMap::Error = aya::maps::MapError +pub fn aya::maps::hash_map::HashMap::try_from(map: aya::maps::Map) -> core::result::Result impl, K: aya::Pod, V: aya::Pod> aya::maps::IterableMap for aya::maps::hash_map::HashMap pub fn aya::maps::hash_map::HashMap::get(&self, key: &K) -> core::result::Result pub fn aya::maps::hash_map::HashMap::map(&self) -> &aya::maps::MapData -impl core::convert::TryFrom for aya::maps::hash_map::HashMap -pub type aya::maps::hash_map::HashMap::Error = aya::maps::MapError -pub fn aya::maps::hash_map::HashMap::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> impl core::fmt::Debug for aya::maps::hash_map::HashMap pub fn aya::maps::hash_map::HashMap::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Send for aya::maps::hash_map::HashMap where K: core::marker::Send, T: core::marker::Send, V: core::marker::Send @@ -212,18 +222,20 @@ pub fn aya::maps::hash_map::PerCpuHashMap::keys(&self) -> aya::maps::Ma impl, K: aya::Pod, V: aya::Pod> aya::maps::hash_map::PerCpuHashMap pub fn aya::maps::hash_map::PerCpuHashMap::insert(&mut self, key: impl core::borrow::Borrow, values: aya::maps::PerCpuValues, flags: u64) -> core::result::Result<(), aya::maps::MapError> pub fn aya::maps::hash_map::PerCpuHashMap::remove(&mut self, key: &K) -> core::result::Result<(), aya::maps::MapError> -impl<'a, V: aya::Pod, K: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::hash_map::PerCpuHashMap<&'a aya::maps::MapData, V, K> -pub type aya::maps::hash_map::PerCpuHashMap<&'a aya::maps::MapData, V, K>::Error = aya::maps::MapError -pub fn aya::maps::hash_map::PerCpuHashMap<&'a aya::maps::MapData, V, K>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> -impl<'a, V: aya::Pod, K: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::hash_map::PerCpuHashMap<&'a mut aya::maps::MapData, V, K> -pub type aya::maps::hash_map::PerCpuHashMap<&'a mut aya::maps::MapData, V, K>::Error = aya::maps::MapError -pub fn aya::maps::hash_map::PerCpuHashMap<&'a mut aya::maps::MapData, V, K>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +impl, K: aya::Pod, V: aya::Pod> aya::maps::hash_map::PerCpuHashMap +pub fn aya::maps::hash_map::PerCpuHashMap::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl<'a, K: aya::Pod, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::hash_map::PerCpuHashMap<&'a aya::maps::MapData, K, V> +pub type aya::maps::hash_map::PerCpuHashMap<&'a aya::maps::MapData, K, V>::Error = aya::maps::MapError +pub fn aya::maps::hash_map::PerCpuHashMap<&'a aya::maps::MapData, K, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a, K: aya::Pod, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::hash_map::PerCpuHashMap<&'a mut aya::maps::MapData, K, V> +pub type aya::maps::hash_map::PerCpuHashMap<&'a mut aya::maps::MapData, K, V>::Error = aya::maps::MapError +pub fn aya::maps::hash_map::PerCpuHashMap<&'a mut aya::maps::MapData, K, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::convert::TryFrom for aya::maps::hash_map::PerCpuHashMap +pub type aya::maps::hash_map::PerCpuHashMap::Error = aya::maps::MapError +pub fn aya::maps::hash_map::PerCpuHashMap::try_from(map: aya::maps::Map) -> core::result::Result impl, K: aya::Pod, V: aya::Pod> aya::maps::IterableMap> for aya::maps::hash_map::PerCpuHashMap pub fn aya::maps::hash_map::PerCpuHashMap::get(&self, key: &K) -> core::result::Result, aya::maps::MapError> pub fn aya::maps::hash_map::PerCpuHashMap::map(&self) -> &aya::maps::MapData -impl core::convert::TryFrom for aya::maps::hash_map::PerCpuHashMap -pub type aya::maps::hash_map::PerCpuHashMap::Error = aya::maps::MapError -pub fn aya::maps::hash_map::PerCpuHashMap::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> impl core::marker::Send for aya::maps::hash_map::PerCpuHashMap where K: core::marker::Send, T: core::marker::Send, V: core::marker::Send impl core::marker::Sync for aya::maps::hash_map::PerCpuHashMap where K: core::marker::Sync, T: core::marker::Sync, V: core::marker::Sync impl core::marker::Unpin for aya::maps::hash_map::PerCpuHashMap where K: core::marker::Unpin, T: core::marker::Unpin, V: core::marker::Unpin @@ -291,18 +303,20 @@ pub fn aya::maps::lpm_trie::LpmTrie::keys(&self) -> aya::maps::MapKeys< impl, K: aya::Pod, V: aya::Pod> aya::maps::lpm_trie::LpmTrie pub fn aya::maps::lpm_trie::LpmTrie::insert(&mut self, key: &aya::maps::lpm_trie::Key, value: impl core::borrow::Borrow, flags: u64) -> core::result::Result<(), aya::maps::MapError> pub fn aya::maps::lpm_trie::LpmTrie::remove(&mut self, key: &aya::maps::lpm_trie::Key) -> core::result::Result<(), aya::maps::MapError> -impl<'a, V: aya::Pod, K: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::lpm_trie::LpmTrie<&'a aya::maps::MapData, V, K> -pub type aya::maps::lpm_trie::LpmTrie<&'a aya::maps::MapData, V, K>::Error = aya::maps::MapError -pub fn aya::maps::lpm_trie::LpmTrie<&'a aya::maps::MapData, V, K>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> -impl<'a, V: aya::Pod, K: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::lpm_trie::LpmTrie<&'a mut aya::maps::MapData, V, K> -pub type aya::maps::lpm_trie::LpmTrie<&'a mut aya::maps::MapData, V, K>::Error = aya::maps::MapError -pub fn aya::maps::lpm_trie::LpmTrie<&'a mut aya::maps::MapData, V, K>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +impl, K: aya::Pod, V: aya::Pod> aya::maps::lpm_trie::LpmTrie +pub fn aya::maps::lpm_trie::LpmTrie::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl<'a, K: aya::Pod, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::lpm_trie::LpmTrie<&'a aya::maps::MapData, K, V> +pub type aya::maps::lpm_trie::LpmTrie<&'a aya::maps::MapData, K, V>::Error = aya::maps::MapError +pub fn aya::maps::lpm_trie::LpmTrie<&'a aya::maps::MapData, K, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a, K: aya::Pod, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::lpm_trie::LpmTrie<&'a mut aya::maps::MapData, K, V> +pub type aya::maps::lpm_trie::LpmTrie<&'a mut aya::maps::MapData, K, V>::Error = aya::maps::MapError +pub fn aya::maps::lpm_trie::LpmTrie<&'a mut aya::maps::MapData, K, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::convert::TryFrom for aya::maps::lpm_trie::LpmTrie +pub type aya::maps::lpm_trie::LpmTrie::Error = aya::maps::MapError +pub fn aya::maps::lpm_trie::LpmTrie::try_from(map: aya::maps::Map) -> core::result::Result impl, K: aya::Pod, V: aya::Pod> aya::maps::IterableMap, V> for aya::maps::lpm_trie::LpmTrie pub fn aya::maps::lpm_trie::LpmTrie::get(&self, key: &aya::maps::lpm_trie::Key) -> core::result::Result pub fn aya::maps::lpm_trie::LpmTrie::map(&self) -> &aya::maps::MapData -impl core::convert::TryFrom for aya::maps::lpm_trie::LpmTrie -pub type aya::maps::lpm_trie::LpmTrie::Error = aya::maps::MapError -pub fn aya::maps::lpm_trie::LpmTrie::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> impl core::fmt::Debug for aya::maps::lpm_trie::LpmTrie pub fn aya::maps::lpm_trie::LpmTrie::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Send for aya::maps::lpm_trie::LpmTrie where K: core::marker::Send, T: core::marker::Send, V: core::marker::Send @@ -372,17 +386,17 @@ pub fn aya::maps::perf::PerfBufferError::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::perf::PerfBufferError pub fn aya::maps::perf::PerfBufferError::from(t: T) -> T pub struct aya::maps::perf::AsyncPerfEventArray -impl + core::borrow::Borrow> aya::maps::perf::AsyncPerfEventArray +impl> aya::maps::perf::AsyncPerfEventArray pub fn aya::maps::perf::AsyncPerfEventArray::open(&mut self, index: u32, page_count: core::option::Option) -> core::result::Result, aya::maps::perf::PerfBufferError> impl core::convert::TryFrom for aya::maps::perf::AsyncPerfEventArray pub type aya::maps::perf::AsyncPerfEventArray::Error = aya::maps::MapError -pub fn aya::maps::perf::AsyncPerfEventArray::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::perf::AsyncPerfEventArray::try_from(map: aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::perf::AsyncPerfEventArray<&'a aya::maps::MapData> pub type aya::maps::perf::AsyncPerfEventArray<&'a aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::perf::AsyncPerfEventArray<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::perf::AsyncPerfEventArray<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::perf::AsyncPerfEventArray<&'a mut aya::maps::MapData> pub type aya::maps::perf::AsyncPerfEventArray<&'a mut aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::perf::AsyncPerfEventArray<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::perf::AsyncPerfEventArray<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl core::marker::Send for aya::maps::perf::AsyncPerfEventArray where T: core::marker::Send + core::marker::Sync impl core::marker::Sync for aya::maps::perf::AsyncPerfEventArray where T: core::marker::Send + core::marker::Sync impl core::marker::Unpin for aya::maps::perf::AsyncPerfEventArray @@ -404,8 +418,8 @@ impl core::borrow::BorrowMut for aya::maps::perf::AsyncPerfEventArray w pub fn aya::maps::perf::AsyncPerfEventArray::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::perf::AsyncPerfEventArray pub fn aya::maps::perf::AsyncPerfEventArray::from(t: T) -> T -pub struct aya::maps::perf::AsyncPerfEventArrayBuffer -impl + core::borrow::Borrow> aya::maps::perf::AsyncPerfEventArrayBuffer +pub struct aya::maps::perf::AsyncPerfEventArrayBuffer> +impl> aya::maps::perf::AsyncPerfEventArrayBuffer pub async fn aya::maps::perf::AsyncPerfEventArrayBuffer::read_events(&mut self, buffers: &mut [bytes::bytes_mut::BytesMut]) -> core::result::Result impl core::marker::Send for aya::maps::perf::AsyncPerfEventArrayBuffer where T: core::marker::Send + core::marker::Sync impl core::marker::Sync for aya::maps::perf::AsyncPerfEventArrayBuffer where T: core::marker::Send + core::marker::Sync @@ -432,7 +446,7 @@ pub struct aya::maps::perf::Events pub aya::maps::perf::Events::lost: usize pub aya::maps::perf::Events::read: usize impl core::cmp::Eq for aya::maps::perf::Events -impl core::cmp::PartialEq for aya::maps::perf::Events +impl core::cmp::PartialEq for aya::maps::perf::Events pub fn aya::maps::perf::Events::eq(&self, other: &aya::maps::perf::Events) -> bool impl core::fmt::Debug for aya::maps::perf::Events pub fn aya::maps::perf::Events::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -460,17 +474,17 @@ pub fn aya::maps::perf::Events::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::perf::Events pub fn aya::maps::perf::Events::from(t: T) -> T pub struct aya::maps::perf::PerfEventArray -impl + core::borrow::Borrow> aya::maps::perf::PerfEventArray +impl> aya::maps::perf::PerfEventArray pub fn aya::maps::perf::PerfEventArray::open(&mut self, index: u32, page_count: core::option::Option) -> core::result::Result, aya::maps::perf::PerfBufferError> impl core::convert::TryFrom for aya::maps::perf::PerfEventArray pub type aya::maps::perf::PerfEventArray::Error = aya::maps::MapError -pub fn aya::maps::perf::PerfEventArray::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::perf::PerfEventArray::try_from(map: aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::perf::PerfEventArray<&'a aya::maps::MapData> pub type aya::maps::perf::PerfEventArray<&'a aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::perf::PerfEventArray<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::perf::PerfEventArray<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::perf::PerfEventArray<&'a mut aya::maps::MapData> pub type aya::maps::perf::PerfEventArray<&'a mut aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::perf::PerfEventArray<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::perf::PerfEventArray<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl core::marker::Send for aya::maps::perf::PerfEventArray where T: core::marker::Send + core::marker::Sync impl core::marker::Sync for aya::maps::perf::PerfEventArray where T: core::marker::Send + core::marker::Sync impl core::marker::Unpin for aya::maps::perf::PerfEventArray @@ -493,10 +507,12 @@ pub fn aya::maps::perf::PerfEventArray::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::perf::PerfEventArray pub fn aya::maps::perf::PerfEventArray::from(t: T) -> T pub struct aya::maps::perf::PerfEventArrayBuffer -impl + core::borrow::Borrow> aya::maps::perf::PerfEventArrayBuffer +impl> aya::maps::perf::PerfEventArrayBuffer pub fn aya::maps::perf::PerfEventArrayBuffer::read_events(&mut self, out_bufs: &mut [bytes::bytes_mut::BytesMut]) -> core::result::Result pub fn aya::maps::perf::PerfEventArrayBuffer::readable(&self) -> bool -impl + core::borrow::Borrow> std::os::fd::raw::AsRawFd for aya::maps::perf::PerfEventArrayBuffer +impl> std::os::fd::owned::AsFd for aya::maps::perf::PerfEventArrayBuffer +pub fn aya::maps::perf::PerfEventArrayBuffer::as_fd(&self) -> std::os::fd::owned::BorrowedFd<'_> +impl> std::os::fd::raw::AsRawFd for aya::maps::perf::PerfEventArrayBuffer pub fn aya::maps::perf::PerfEventArrayBuffer::as_raw_fd(&self) -> std::os::fd::raw::RawFd impl core::marker::Send for aya::maps::perf::PerfEventArrayBuffer where T: core::marker::Send + core::marker::Sync impl core::marker::Sync for aya::maps::perf::PerfEventArrayBuffer where T: core::marker::Send + core::marker::Sync @@ -524,17 +540,19 @@ pub struct aya::maps::queue::Queue impl, V: aya::Pod> aya::maps::queue::Queue pub fn aya::maps::queue::Queue::capacity(&self) -> u32 impl, V: aya::Pod> aya::maps::queue::Queue +pub fn aya::maps::queue::Queue::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl, V: aya::Pod> aya::maps::queue::Queue pub fn aya::maps::queue::Queue::pop(&mut self, flags: u64) -> core::result::Result pub fn aya::maps::queue::Queue::push(&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::queue::Queue<&'a aya::maps::MapData, V> pub type aya::maps::queue::Queue<&'a aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::queue::Queue<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::queue::Queue<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::queue::Queue<&'a mut aya::maps::MapData, V> pub type aya::maps::queue::Queue<&'a mut aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::queue::Queue<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::queue::Queue<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl core::convert::TryFrom for aya::maps::queue::Queue pub type aya::maps::queue::Queue::Error = aya::maps::MapError -pub fn aya::maps::queue::Queue::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::queue::Queue::try_from(map: aya::maps::Map) -> core::result::Result impl core::marker::Send for aya::maps::queue::Queue where T: core::marker::Send, V: core::marker::Send impl core::marker::Sync for aya::maps::queue::Queue where T: core::marker::Sync, V: core::marker::Sync impl core::marker::Unpin for aya::maps::queue::Queue where T: core::marker::Unpin, V: core::marker::Unpin @@ -556,28 +574,95 @@ impl core::borrow::BorrowMut for aya::maps::queue::Queue where T: co pub fn aya::maps::queue::Queue::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::queue::Queue pub fn aya::maps::queue::Queue::from(t: T) -> T +pub mod aya::maps::ring_buf +pub struct aya::maps::ring_buf::RingBuf +impl aya::maps::ring_buf::RingBuf +pub fn aya::maps::ring_buf::RingBuf::next(&mut self) -> core::option::Option> +impl core::convert::TryFrom for aya::maps::ring_buf::RingBuf +pub type aya::maps::ring_buf::RingBuf::Error = aya::maps::MapError +pub fn aya::maps::ring_buf::RingBuf::try_from(map: aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::ring_buf::RingBuf<&'a aya::maps::MapData> +pub type aya::maps::ring_buf::RingBuf<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::ring_buf::RingBuf<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::ring_buf::RingBuf<&'a mut aya::maps::MapData> +pub type aya::maps::ring_buf::RingBuf<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::ring_buf::RingBuf<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl> std::os::fd::raw::AsRawFd for aya::maps::ring_buf::RingBuf +pub fn aya::maps::ring_buf::RingBuf::as_raw_fd(&self) -> std::os::fd::raw::RawFd +impl !core::marker::Send for aya::maps::ring_buf::RingBuf +impl !core::marker::Sync for aya::maps::ring_buf::RingBuf +impl core::marker::Unpin for aya::maps::ring_buf::RingBuf where T: core::marker::Unpin +impl core::panic::unwind_safe::RefUnwindSafe for aya::maps::ring_buf::RingBuf where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for aya::maps::ring_buf::RingBuf where T: core::panic::unwind_safe::UnwindSafe +impl core::convert::Into for aya::maps::ring_buf::RingBuf where U: core::convert::From +pub fn aya::maps::ring_buf::RingBuf::into(self) -> U +impl core::convert::TryFrom for aya::maps::ring_buf::RingBuf where U: core::convert::Into +pub type aya::maps::ring_buf::RingBuf::Error = core::convert::Infallible +pub fn aya::maps::ring_buf::RingBuf::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::ring_buf::RingBuf where U: core::convert::TryFrom +pub type aya::maps::ring_buf::RingBuf::Error = >::Error +pub fn aya::maps::ring_buf::RingBuf::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya::maps::ring_buf::RingBuf where T: 'static + core::marker::Sized +pub fn aya::maps::ring_buf::RingBuf::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::ring_buf::RingBuf where T: core::marker::Sized +pub fn aya::maps::ring_buf::RingBuf::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::ring_buf::RingBuf where T: core::marker::Sized +pub fn aya::maps::ring_buf::RingBuf::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::ring_buf::RingBuf +pub fn aya::maps::ring_buf::RingBuf::from(t: T) -> T +pub struct aya::maps::ring_buf::RingBufItem<'a> +impl core::fmt::Debug for aya::maps::ring_buf::RingBufItem<'_> +pub fn aya::maps::ring_buf::RingBufItem<'_>::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::ops::deref::Deref for aya::maps::ring_buf::RingBufItem<'_> +pub type aya::maps::ring_buf::RingBufItem<'_>::Target = [u8] +pub fn aya::maps::ring_buf::RingBufItem<'_>::deref(&self) -> &Self::Target +impl core::ops::drop::Drop for aya::maps::ring_buf::RingBufItem<'_> +pub fn aya::maps::ring_buf::RingBufItem<'_>::drop(&mut self) +impl<'a> !core::marker::Send for aya::maps::ring_buf::RingBufItem<'a> +impl<'a> !core::marker::Sync for aya::maps::ring_buf::RingBufItem<'a> +impl<'a> core::marker::Unpin for aya::maps::ring_buf::RingBufItem<'a> +impl<'a> core::panic::unwind_safe::RefUnwindSafe for aya::maps::ring_buf::RingBufItem<'a> +impl<'a> !core::panic::unwind_safe::UnwindSafe for aya::maps::ring_buf::RingBufItem<'a> +impl core::convert::Into for aya::maps::ring_buf::RingBufItem<'a> where U: core::convert::From +pub fn aya::maps::ring_buf::RingBufItem<'a>::into(self) -> U +impl core::convert::TryFrom for aya::maps::ring_buf::RingBufItem<'a> where U: core::convert::Into +pub type aya::maps::ring_buf::RingBufItem<'a>::Error = core::convert::Infallible +pub fn aya::maps::ring_buf::RingBufItem<'a>::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::ring_buf::RingBufItem<'a> where U: core::convert::TryFrom +pub type aya::maps::ring_buf::RingBufItem<'a>::Error = >::Error +pub fn aya::maps::ring_buf::RingBufItem<'a>::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya::maps::ring_buf::RingBufItem<'a> where T: 'static + core::marker::Sized +pub fn aya::maps::ring_buf::RingBufItem<'a>::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::ring_buf::RingBufItem<'a> where T: core::marker::Sized +pub fn aya::maps::ring_buf::RingBufItem<'a>::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::ring_buf::RingBufItem<'a> where T: core::marker::Sized +pub fn aya::maps::ring_buf::RingBufItem<'a>::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::ring_buf::RingBufItem<'a> +pub fn aya::maps::ring_buf::RingBufItem<'a>::from(t: T) -> T pub mod aya::maps::sock pub struct aya::maps::sock::SockHash impl, K: aya::Pod> aya::maps::SockHash -pub fn aya::maps::SockHash::fd(&self) -> core::result::Result +pub fn aya::maps::SockHash::fd(&self) -> &aya::maps::sock::SockMapFd pub fn aya::maps::SockHash::get(&self, key: &K, flags: u64) -> core::result::Result pub fn aya::maps::SockHash::iter(&self) -> aya::maps::MapIter<'_, K, std::os::fd::raw::RawFd, Self> pub fn aya::maps::SockHash::keys(&self) -> aya::maps::MapKeys<'_, K> impl, K: aya::Pod> aya::maps::SockHash pub fn aya::maps::SockHash::insert(&mut self, key: impl core::borrow::Borrow, value: I, flags: u64) -> core::result::Result<(), aya::maps::MapError> pub fn aya::maps::SockHash::remove(&mut self, key: &K) -> core::result::Result<(), aya::maps::MapError> +impl, V: aya::Pod> aya::maps::SockHash +pub fn aya::maps::SockHash::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> impl<'a, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::SockHash<&'a aya::maps::MapData, V> pub type aya::maps::SockHash<&'a aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::SockHash<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::SockHash<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::SockHash<&'a mut aya::maps::MapData, V> pub type aya::maps::SockHash<&'a mut aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::SockHash<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::SockHash<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl, K: aya::Pod> aya::maps::IterableMap for aya::maps::SockHash pub fn aya::maps::SockHash::get(&self, key: &K) -> core::result::Result pub fn aya::maps::SockHash::map(&self) -> &aya::maps::MapData impl core::convert::TryFrom for aya::maps::SockHash pub type aya::maps::SockHash::Error = aya::maps::MapError -pub fn aya::maps::SockHash::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::SockHash::try_from(map: aya::maps::Map) -> core::result::Result impl core::marker::Send for aya::maps::SockHash where K: core::marker::Send, T: core::marker::Send impl core::marker::Sync for aya::maps::SockHash where K: core::marker::Sync, T: core::marker::Sync impl core::marker::Unpin for aya::maps::SockHash where K: core::marker::Unpin, T: core::marker::Unpin @@ -601,20 +686,22 @@ impl core::convert::From for aya::maps::SockHash pub fn aya::maps::SockHash::from(t: T) -> T pub struct aya::maps::sock::SockMap impl> aya::maps::SockMap -pub fn aya::maps::SockMap::fd(&self) -> core::result::Result +pub fn aya::maps::SockMap::fd(&self) -> &aya::maps::sock::SockMapFd pub fn aya::maps::SockMap::indices(&self) -> aya::maps::MapKeys<'_, u32> impl> aya::maps::SockMap pub fn aya::maps::SockMap::clear_index(&mut self, index: &u32) -> core::result::Result<(), aya::maps::MapError> pub fn aya::maps::SockMap::set(&mut self, index: u32, socket: &I, flags: u64) -> core::result::Result<(), aya::maps::MapError> +impl> aya::maps::SockMap +pub fn aya::maps::SockMap::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> impl core::convert::TryFrom for aya::maps::SockMap pub type aya::maps::SockMap::Error = aya::maps::MapError -pub fn aya::maps::SockMap::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::SockMap::try_from(map: aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::SockMap<&'a aya::maps::MapData> pub type aya::maps::SockMap<&'a aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::SockMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::SockMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::SockMap<&'a mut aya::maps::MapData> pub type aya::maps::SockMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::SockMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::SockMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl core::marker::Send for aya::maps::SockMap where T: core::marker::Send impl core::marker::Sync for aya::maps::SockMap where T: core::marker::Sync impl core::marker::Unpin for aya::maps::SockMap where T: core::marker::Unpin @@ -636,12 +723,11 @@ impl core::borrow::BorrowMut for aya::maps::SockMap where T: core::mark pub fn aya::maps::SockMap::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::SockMap pub fn aya::maps::SockMap::from(t: T) -> T -pub struct aya::maps::sock::SockMapFd(_) -impl std::os::fd::raw::AsRawFd for aya::maps::sock::SockMapFd -pub fn aya::maps::sock::SockMapFd::as_raw_fd(&self) -> std::os::fd::raw::RawFd -impl core::clone::Clone for aya::maps::sock::SockMapFd -pub fn aya::maps::sock::SockMapFd::clone(&self) -> aya::maps::sock::SockMapFd -impl core::marker::Copy for aya::maps::sock::SockMapFd +#[repr(transparent)] pub struct aya::maps::sock::SockMapFd(_) +impl aya::maps::sock::SockMapFd +pub fn aya::maps::sock::SockMapFd::try_clone(&self) -> std::io::error::Result +impl std::os::fd::owned::AsFd for aya::maps::sock::SockMapFd +pub fn aya::maps::sock::SockMapFd::as_fd(&self) -> std::os::fd::owned::BorrowedFd<'_> impl core::marker::Send for aya::maps::sock::SockMapFd impl core::marker::Sync for aya::maps::sock::SockMapFd impl core::marker::Unpin for aya::maps::sock::SockMapFd @@ -655,10 +741,6 @@ pub fn aya::maps::sock::SockMapFd::try_from(value: U) -> core::result::Result core::convert::TryInto for aya::maps::sock::SockMapFd where U: core::convert::TryFrom pub type aya::maps::sock::SockMapFd::Error = >::Error pub fn aya::maps::sock::SockMapFd::try_into(self) -> core::result::Result>::Error> -impl alloc::borrow::ToOwned for aya::maps::sock::SockMapFd where T: core::clone::Clone -pub type aya::maps::sock::SockMapFd::Owned = T -pub fn aya::maps::sock::SockMapFd::clone_into(&self, target: &mut T) -pub fn aya::maps::sock::SockMapFd::to_owned(&self) -> T impl core::any::Any for aya::maps::sock::SockMapFd where T: 'static + core::marker::Sized pub fn aya::maps::sock::SockMapFd::type_id(&self) -> core::any::TypeId impl core::borrow::Borrow for aya::maps::sock::SockMapFd where T: core::marker::Sized @@ -672,17 +754,19 @@ pub struct aya::maps::stack::Stack impl, V: aya::Pod> aya::maps::stack::Stack pub fn aya::maps::stack::Stack::capacity(&self) -> u32 impl, V: aya::Pod> aya::maps::stack::Stack +pub fn aya::maps::stack::Stack::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl, V: aya::Pod> aya::maps::stack::Stack pub fn aya::maps::stack::Stack::pop(&mut self, flags: u64) -> core::result::Result pub fn aya::maps::stack::Stack::push(&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::stack::Stack<&'a aya::maps::MapData, V> pub type aya::maps::stack::Stack<&'a aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::stack::Stack<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::stack::Stack<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::stack::Stack<&'a mut aya::maps::MapData, V> pub type aya::maps::stack::Stack<&'a mut aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::stack::Stack<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::stack::Stack<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl core::convert::TryFrom for aya::maps::stack::Stack pub type aya::maps::stack::Stack::Error = aya::maps::MapError -pub fn aya::maps::stack::Stack::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::stack::Stack::try_from(map: aya::maps::Map) -> core::result::Result impl core::marker::Send for aya::maps::stack::Stack where T: core::marker::Send, V: core::marker::Send impl core::marker::Sync for aya::maps::stack::Stack where T: core::marker::Sync, V: core::marker::Sync impl core::marker::Unpin for aya::maps::stack::Stack where T: core::marker::Unpin, V: core::marker::Unpin @@ -761,19 +845,21 @@ impl> aya::maps::stack_trace::StackT pub fn aya::maps::stack_trace::StackTraceMap::get(&self, stack_id: &u32, flags: u64) -> core::result::Result pub fn aya::maps::stack_trace::StackTraceMap::iter(&self) -> aya::maps::MapIter<'_, u32, aya::maps::stack_trace::StackTrace, Self> pub fn aya::maps::stack_trace::StackTraceMap::stack_ids(&self) -> aya::maps::MapKeys<'_, u32> +impl> aya::maps::stack_trace::StackTraceMap +pub fn aya::maps::stack_trace::StackTraceMap::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> impl core::convert::TryFrom for aya::maps::stack_trace::StackTraceMap pub type aya::maps::stack_trace::StackTraceMap::Error = aya::maps::MapError -pub fn aya::maps::stack_trace::StackTraceMap::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::stack_trace::StackTraceMap::try_from(map: aya::maps::Map) -> core::result::Result impl<'a, T: core::borrow::Borrow> core::iter::traits::collect::IntoIterator for &'a aya::maps::stack_trace::StackTraceMap pub type &'a aya::maps::stack_trace::StackTraceMap::IntoIter = aya::maps::MapIter<'a, u32, aya::maps::stack_trace::StackTrace, aya::maps::stack_trace::StackTraceMap> pub type &'a aya::maps::stack_trace::StackTraceMap::Item = core::result::Result<(u32, aya::maps::stack_trace::StackTrace), aya::maps::MapError> pub fn &'a aya::maps::stack_trace::StackTraceMap::into_iter(self) -> Self::IntoIter impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::stack_trace::StackTraceMap<&'a aya::maps::MapData> pub type aya::maps::stack_trace::StackTraceMap<&'a aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::stack_trace::StackTraceMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::stack_trace::StackTraceMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::stack_trace::StackTraceMap<&'a mut aya::maps::MapData> pub type aya::maps::stack_trace::StackTraceMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::stack_trace::StackTraceMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::stack_trace::StackTraceMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result 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 @@ -800,9 +886,202 @@ 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 mod aya::maps::xdp +pub enum aya::maps::xdp::XdpMapError +pub aya::maps::xdp::XdpMapError::ChainedProgramNotSupported +pub aya::maps::xdp::XdpMapError::MapError(aya::maps::MapError) +impl core::convert::From for aya::maps::xdp::XdpMapError +pub fn aya::maps::xdp::XdpMapError::from(source: aya::maps::MapError) -> Self +impl core::error::Error for aya::maps::xdp::XdpMapError +pub fn aya::maps::xdp::XdpMapError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> +impl core::fmt::Display for aya::maps::xdp::XdpMapError +pub fn aya::maps::xdp::XdpMapError::fmt(&self, __formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::fmt::Debug for aya::maps::xdp::XdpMapError +pub fn aya::maps::xdp::XdpMapError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Send for aya::maps::xdp::XdpMapError +impl core::marker::Sync for aya::maps::xdp::XdpMapError +impl core::marker::Unpin for aya::maps::xdp::XdpMapError +impl !core::panic::unwind_safe::RefUnwindSafe for aya::maps::xdp::XdpMapError +impl !core::panic::unwind_safe::UnwindSafe for aya::maps::xdp::XdpMapError +impl core::convert::Into for aya::maps::xdp::XdpMapError where U: core::convert::From +pub fn aya::maps::xdp::XdpMapError::into(self) -> U +impl core::convert::TryFrom for aya::maps::xdp::XdpMapError where U: core::convert::Into +pub type aya::maps::xdp::XdpMapError::Error = core::convert::Infallible +pub fn aya::maps::xdp::XdpMapError::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::xdp::XdpMapError where U: core::convert::TryFrom +pub type aya::maps::xdp::XdpMapError::Error = >::Error +pub fn aya::maps::xdp::XdpMapError::try_into(self) -> core::result::Result>::Error> +impl alloc::string::ToString for aya::maps::xdp::XdpMapError where T: core::fmt::Display + core::marker::Sized +pub fn aya::maps::xdp::XdpMapError::to_string(&self) -> alloc::string::String +impl core::any::Any for aya::maps::xdp::XdpMapError where T: 'static + core::marker::Sized +pub fn aya::maps::xdp::XdpMapError::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::xdp::XdpMapError where T: core::marker::Sized +pub fn aya::maps::xdp::XdpMapError::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::xdp::XdpMapError where T: core::marker::Sized +pub fn aya::maps::xdp::XdpMapError::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::xdp::XdpMapError +pub fn aya::maps::xdp::XdpMapError::from(t: T) -> T +pub struct aya::maps::xdp::CpuMap +impl> aya::maps::CpuMap +pub fn aya::maps::CpuMap::get(&self, cpu_index: u32, flags: u64) -> core::result::Result +pub fn aya::maps::CpuMap::iter(&self) -> impl core::iter::traits::iterator::Iterator> + '_ +pub fn aya::maps::CpuMap::len(&self) -> u32 +impl> aya::maps::CpuMap +pub fn aya::maps::CpuMap::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl> aya::maps::CpuMap +pub fn aya::maps::CpuMap::set(&mut self, cpu_index: u32, queue_size: u32, program: core::option::Option<&aya::programs::ProgramFd>, flags: u64) -> core::result::Result<(), aya::maps::xdp::XdpMapError> +impl core::convert::TryFrom for aya::maps::CpuMap +pub type aya::maps::CpuMap::Error = aya::maps::MapError +pub fn aya::maps::CpuMap::try_from(map: aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::CpuMap<&'a aya::maps::MapData> +pub type aya::maps::CpuMap<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::CpuMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::CpuMap<&'a mut aya::maps::MapData> +pub type aya::maps::CpuMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::CpuMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::marker::Send for aya::maps::CpuMap where T: core::marker::Send +impl core::marker::Sync for aya::maps::CpuMap where T: core::marker::Sync +impl core::marker::Unpin for aya::maps::CpuMap where T: core::marker::Unpin +impl core::panic::unwind_safe::RefUnwindSafe for aya::maps::CpuMap where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for aya::maps::CpuMap where T: core::panic::unwind_safe::UnwindSafe +impl core::convert::Into for aya::maps::CpuMap where U: core::convert::From +pub fn aya::maps::CpuMap::into(self) -> U +impl core::convert::TryFrom for aya::maps::CpuMap where U: core::convert::Into +pub type aya::maps::CpuMap::Error = core::convert::Infallible +pub fn aya::maps::CpuMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::CpuMap where U: core::convert::TryFrom +pub type aya::maps::CpuMap::Error = >::Error +pub fn aya::maps::CpuMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya::maps::CpuMap where T: 'static + core::marker::Sized +pub fn aya::maps::CpuMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::CpuMap where T: core::marker::Sized +pub fn aya::maps::CpuMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::CpuMap where T: core::marker::Sized +pub fn aya::maps::CpuMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::CpuMap +pub fn aya::maps::CpuMap::from(t: T) -> T +pub struct aya::maps::xdp::DevMap +impl> aya::maps::DevMap +pub fn aya::maps::DevMap::get(&self, index: u32, flags: u64) -> core::result::Result +pub fn aya::maps::DevMap::iter(&self) -> impl core::iter::traits::iterator::Iterator> + '_ +pub fn aya::maps::DevMap::len(&self) -> u32 +impl> aya::maps::DevMap +pub fn aya::maps::DevMap::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl> aya::maps::DevMap +pub fn aya::maps::DevMap::set(&mut self, index: u32, target_if_index: u32, program: core::option::Option<&aya::programs::ProgramFd>, flags: u64) -> core::result::Result<(), aya::maps::xdp::XdpMapError> +impl core::convert::TryFrom for aya::maps::DevMap +pub type aya::maps::DevMap::Error = aya::maps::MapError +pub fn aya::maps::DevMap::try_from(map: aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::DevMap<&'a aya::maps::MapData> +pub type aya::maps::DevMap<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::DevMap<&'a mut aya::maps::MapData> +pub type aya::maps::DevMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::marker::Send for aya::maps::DevMap where T: core::marker::Send +impl core::marker::Sync for aya::maps::DevMap where T: core::marker::Sync +impl core::marker::Unpin for aya::maps::DevMap where T: core::marker::Unpin +impl core::panic::unwind_safe::RefUnwindSafe for aya::maps::DevMap where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for aya::maps::DevMap where T: core::panic::unwind_safe::UnwindSafe +impl core::convert::Into for aya::maps::DevMap where U: core::convert::From +pub fn aya::maps::DevMap::into(self) -> U +impl core::convert::TryFrom for aya::maps::DevMap where U: core::convert::Into +pub type aya::maps::DevMap::Error = core::convert::Infallible +pub fn aya::maps::DevMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::DevMap where U: core::convert::TryFrom +pub type aya::maps::DevMap::Error = >::Error +pub fn aya::maps::DevMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya::maps::DevMap where T: 'static + core::marker::Sized +pub fn aya::maps::DevMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::DevMap where T: core::marker::Sized +pub fn aya::maps::DevMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::DevMap where T: core::marker::Sized +pub fn aya::maps::DevMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::DevMap +pub fn aya::maps::DevMap::from(t: T) -> T +pub struct aya::maps::xdp::DevMapHash +impl> aya::maps::DevMapHash +pub fn aya::maps::DevMapHash::get(&self, key: u32, flags: u64) -> core::result::Result +pub fn aya::maps::DevMapHash::iter(&self) -> aya::maps::MapIter<'_, u32, DevMapValue, Self> +pub fn aya::maps::DevMapHash::keys(&self) -> aya::maps::MapKeys<'_, u32> +impl> aya::maps::DevMapHash +pub fn aya::maps::DevMapHash::insert(&mut self, key: u32, target_if_index: u32, program: core::option::Option<&aya::programs::ProgramFd>, flags: u64) -> core::result::Result<(), aya::maps::xdp::XdpMapError> +pub fn aya::maps::DevMapHash::remove(&mut self, key: u32) -> core::result::Result<(), aya::maps::MapError> +impl> aya::maps::DevMapHash +pub fn aya::maps::DevMapHash::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl core::convert::TryFrom for aya::maps::DevMapHash +pub type aya::maps::DevMapHash::Error = aya::maps::MapError +pub fn aya::maps::DevMapHash::try_from(map: aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::DevMapHash<&'a aya::maps::MapData> +pub type aya::maps::DevMapHash<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMapHash<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::DevMapHash<&'a mut aya::maps::MapData> +pub type aya::maps::DevMapHash<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMapHash<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::marker::Send for aya::maps::DevMapHash where T: core::marker::Send +impl core::marker::Sync for aya::maps::DevMapHash where T: core::marker::Sync +impl core::marker::Unpin for aya::maps::DevMapHash where T: core::marker::Unpin +impl core::panic::unwind_safe::RefUnwindSafe for aya::maps::DevMapHash where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for aya::maps::DevMapHash where T: core::panic::unwind_safe::UnwindSafe +impl core::convert::Into for aya::maps::DevMapHash where U: core::convert::From +pub fn aya::maps::DevMapHash::into(self) -> U +impl core::convert::TryFrom for aya::maps::DevMapHash where U: core::convert::Into +pub type aya::maps::DevMapHash::Error = core::convert::Infallible +pub fn aya::maps::DevMapHash::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::DevMapHash where U: core::convert::TryFrom +pub type aya::maps::DevMapHash::Error = >::Error +pub fn aya::maps::DevMapHash::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya::maps::DevMapHash where T: 'static + core::marker::Sized +pub fn aya::maps::DevMapHash::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::DevMapHash where T: core::marker::Sized +pub fn aya::maps::DevMapHash::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::DevMapHash where T: core::marker::Sized +pub fn aya::maps::DevMapHash::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::DevMapHash +pub fn aya::maps::DevMapHash::from(t: T) -> T +pub struct aya::maps::xdp::XskMap +impl> aya::maps::XskMap +pub fn aya::maps::XskMap::len(&self) -> u32 +impl> aya::maps::XskMap +pub fn aya::maps::XskMap::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl> aya::maps::XskMap +pub fn aya::maps::XskMap::set(&mut self, index: u32, socket_fd: impl std::os::fd::raw::AsRawFd, flags: u64) -> core::result::Result<(), aya::maps::MapError> +impl core::convert::TryFrom for aya::maps::XskMap +pub type aya::maps::XskMap::Error = aya::maps::MapError +pub fn aya::maps::XskMap::try_from(map: aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::XskMap<&'a aya::maps::MapData> +pub type aya::maps::XskMap<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::XskMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::XskMap<&'a mut aya::maps::MapData> +pub type aya::maps::XskMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::XskMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::marker::Send for aya::maps::XskMap where T: core::marker::Send +impl core::marker::Sync for aya::maps::XskMap where T: core::marker::Sync +impl core::marker::Unpin for aya::maps::XskMap where T: core::marker::Unpin +impl core::panic::unwind_safe::RefUnwindSafe for aya::maps::XskMap where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for aya::maps::XskMap where T: core::panic::unwind_safe::UnwindSafe +impl core::convert::Into for aya::maps::XskMap where U: core::convert::From +pub fn aya::maps::XskMap::into(self) -> U +impl core::convert::TryFrom for aya::maps::XskMap where U: core::convert::Into +pub type aya::maps::XskMap::Error = core::convert::Infallible +pub fn aya::maps::XskMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::XskMap where U: core::convert::TryFrom +pub type aya::maps::XskMap::Error = >::Error +pub fn aya::maps::XskMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya::maps::XskMap where T: 'static + core::marker::Sized +pub fn aya::maps::XskMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::XskMap where T: core::marker::Sized +pub fn aya::maps::XskMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::XskMap where T: core::marker::Sized +pub fn aya::maps::XskMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::XskMap +pub fn aya::maps::XskMap::from(t: T) -> T pub enum aya::maps::Map pub aya::maps::Map::Array(aya::maps::MapData) pub aya::maps::Map::BloomFilter(aya::maps::MapData) +pub aya::maps::Map::CpuMap(aya::maps::MapData) +pub aya::maps::Map::DevMap(aya::maps::MapData) +pub aya::maps::Map::DevMapHash(aya::maps::MapData) pub aya::maps::Map::HashMap(aya::maps::MapData) pub aya::maps::Map::LpmTrie(aya::maps::MapData) pub aya::maps::Map::LruHashMap(aya::maps::MapData) @@ -812,137 +1091,186 @@ pub aya::maps::Map::PerCpuLruHashMap(aya::maps::MapData) pub aya::maps::Map::PerfEventArray(aya::maps::MapData) pub aya::maps::Map::ProgramArray(aya::maps::MapData) pub aya::maps::Map::Queue(aya::maps::MapData) +pub aya::maps::Map::RingBuf(aya::maps::MapData) pub aya::maps::Map::SockHash(aya::maps::MapData) pub aya::maps::Map::SockMap(aya::maps::MapData) pub aya::maps::Map::Stack(aya::maps::MapData) pub aya::maps::Map::StackTraceMap(aya::maps::MapData) pub aya::maps::Map::Unsupported(aya::maps::MapData) +pub aya::maps::Map::XskMap(aya::maps::MapData) +impl aya::maps::Map +pub fn aya::maps::Map::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl core::convert::TryFrom for aya::maps::CpuMap +pub type aya::maps::CpuMap::Error = aya::maps::MapError +pub fn aya::maps::CpuMap::try_from(map: aya::maps::Map) -> core::result::Result +impl core::convert::TryFrom for aya::maps::DevMap +pub type aya::maps::DevMap::Error = aya::maps::MapError +pub fn aya::maps::DevMap::try_from(map: aya::maps::Map) -> core::result::Result +impl core::convert::TryFrom for aya::maps::DevMapHash +pub type aya::maps::DevMapHash::Error = aya::maps::MapError +pub fn aya::maps::DevMapHash::try_from(map: aya::maps::Map) -> core::result::Result 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> +pub fn aya::maps::ProgramArray::try_from(map: aya::maps::Map) -> core::result::Result impl core::convert::TryFrom for aya::maps::SockMap pub type aya::maps::SockMap::Error = aya::maps::MapError -pub fn aya::maps::SockMap::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::SockMap::try_from(map: aya::maps::Map) -> core::result::Result +impl core::convert::TryFrom for aya::maps::XskMap +pub type aya::maps::XskMap::Error = aya::maps::MapError +pub fn aya::maps::XskMap::try_from(map: aya::maps::Map) -> core::result::Result impl core::convert::TryFrom for aya::maps::perf::AsyncPerfEventArray pub type aya::maps::perf::AsyncPerfEventArray::Error = aya::maps::MapError -pub fn aya::maps::perf::AsyncPerfEventArray::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::perf::AsyncPerfEventArray::try_from(map: aya::maps::Map) -> core::result::Result impl core::convert::TryFrom for aya::maps::perf::PerfEventArray pub type aya::maps::perf::PerfEventArray::Error = aya::maps::MapError -pub fn aya::maps::perf::PerfEventArray::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::perf::PerfEventArray::try_from(map: aya::maps::Map) -> core::result::Result +impl core::convert::TryFrom for aya::maps::ring_buf::RingBuf +pub type aya::maps::ring_buf::RingBuf::Error = aya::maps::MapError +pub fn aya::maps::ring_buf::RingBuf::try_from(map: aya::maps::Map) -> core::result::Result impl core::convert::TryFrom for aya::maps::stack_trace::StackTraceMap pub type aya::maps::stack_trace::StackTraceMap::Error = aya::maps::MapError -pub fn aya::maps::stack_trace::StackTraceMap::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> -impl<'a, V: aya::Pod, K: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::hash_map::HashMap<&'a aya::maps::MapData, V, K> -pub type aya::maps::hash_map::HashMap<&'a aya::maps::MapData, V, K>::Error = aya::maps::MapError -pub fn aya::maps::hash_map::HashMap<&'a aya::maps::MapData, V, K>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> -impl<'a, V: aya::Pod, K: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::hash_map::PerCpuHashMap<&'a aya::maps::MapData, V, K> -pub type aya::maps::hash_map::PerCpuHashMap<&'a aya::maps::MapData, V, K>::Error = aya::maps::MapError -pub fn aya::maps::hash_map::PerCpuHashMap<&'a aya::maps::MapData, V, K>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> -impl<'a, V: aya::Pod, K: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::lpm_trie::LpmTrie<&'a aya::maps::MapData, V, K> -pub type aya::maps::lpm_trie::LpmTrie<&'a aya::maps::MapData, V, K>::Error = aya::maps::MapError -pub fn aya::maps::lpm_trie::LpmTrie<&'a aya::maps::MapData, V, K>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> -impl<'a, V: aya::Pod, K: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::hash_map::HashMap<&'a mut aya::maps::MapData, V, K> -pub type aya::maps::hash_map::HashMap<&'a mut aya::maps::MapData, V, K>::Error = aya::maps::MapError -pub fn aya::maps::hash_map::HashMap<&'a mut aya::maps::MapData, V, K>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> -impl<'a, V: aya::Pod, K: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::hash_map::PerCpuHashMap<&'a mut aya::maps::MapData, V, K> -pub type aya::maps::hash_map::PerCpuHashMap<&'a mut aya::maps::MapData, V, K>::Error = aya::maps::MapError -pub fn aya::maps::hash_map::PerCpuHashMap<&'a mut aya::maps::MapData, V, K>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> -impl<'a, V: aya::Pod, K: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::lpm_trie::LpmTrie<&'a mut aya::maps::MapData, V, K> -pub type aya::maps::lpm_trie::LpmTrie<&'a mut aya::maps::MapData, V, K>::Error = aya::maps::MapError -pub fn aya::maps::lpm_trie::LpmTrie<&'a mut aya::maps::MapData, V, K>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::stack_trace::StackTraceMap::try_from(map: aya::maps::Map) -> core::result::Result +impl<'a, K: aya::Pod, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::hash_map::HashMap<&'a aya::maps::MapData, K, V> +pub type aya::maps::hash_map::HashMap<&'a aya::maps::MapData, K, V>::Error = aya::maps::MapError +pub fn aya::maps::hash_map::HashMap<&'a aya::maps::MapData, K, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a, K: aya::Pod, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::hash_map::PerCpuHashMap<&'a aya::maps::MapData, K, V> +pub type aya::maps::hash_map::PerCpuHashMap<&'a aya::maps::MapData, K, V>::Error = aya::maps::MapError +pub fn aya::maps::hash_map::PerCpuHashMap<&'a aya::maps::MapData, K, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a, K: aya::Pod, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::lpm_trie::LpmTrie<&'a aya::maps::MapData, K, V> +pub type aya::maps::lpm_trie::LpmTrie<&'a aya::maps::MapData, K, V>::Error = aya::maps::MapError +pub fn aya::maps::lpm_trie::LpmTrie<&'a aya::maps::MapData, K, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a, K: aya::Pod, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::hash_map::HashMap<&'a mut aya::maps::MapData, K, V> +pub type aya::maps::hash_map::HashMap<&'a mut aya::maps::MapData, K, V>::Error = aya::maps::MapError +pub fn aya::maps::hash_map::HashMap<&'a mut aya::maps::MapData, K, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl<'a, K: aya::Pod, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::hash_map::PerCpuHashMap<&'a mut aya::maps::MapData, K, V> +pub type aya::maps::hash_map::PerCpuHashMap<&'a mut aya::maps::MapData, K, V>::Error = aya::maps::MapError +pub fn aya::maps::hash_map::PerCpuHashMap<&'a mut aya::maps::MapData, K, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl<'a, K: aya::Pod, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::lpm_trie::LpmTrie<&'a mut aya::maps::MapData, K, V> +pub type aya::maps::lpm_trie::LpmTrie<&'a mut aya::maps::MapData, K, V>::Error = aya::maps::MapError +pub fn aya::maps::lpm_trie::LpmTrie<&'a mut aya::maps::MapData, K, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::PerCpuArray<&'a aya::maps::MapData, V> pub type aya::maps::PerCpuArray<&'a aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::PerCpuArray<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::PerCpuArray<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::SockHash<&'a aya::maps::MapData, V> pub type aya::maps::SockHash<&'a aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::SockHash<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::SockHash<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::array::Array<&'a aya::maps::MapData, V> pub type aya::maps::array::Array<&'a aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::array::Array<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::array::Array<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result 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> +pub fn aya::maps::bloom_filter::BloomFilter<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::queue::Queue<&'a aya::maps::MapData, V> pub type aya::maps::queue::Queue<&'a aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::queue::Queue<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::queue::Queue<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::stack::Stack<&'a aya::maps::MapData, V> pub type aya::maps::stack::Stack<&'a aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::stack::Stack<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::stack::Stack<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::PerCpuArray<&'a mut aya::maps::MapData, V> pub type aya::maps::PerCpuArray<&'a mut aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::PerCpuArray<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::PerCpuArray<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::SockHash<&'a mut aya::maps::MapData, V> pub type aya::maps::SockHash<&'a mut aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::SockHash<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::SockHash<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::array::Array<&'a mut aya::maps::MapData, V> pub type aya::maps::array::Array<&'a mut aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::array::Array<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::array::Array<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::bloom_filter::BloomFilter<&'a mut aya::maps::MapData, V> pub type aya::maps::bloom_filter::BloomFilter<&'a mut aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::bloom_filter::BloomFilter<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::bloom_filter::BloomFilter<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::queue::Queue<&'a mut aya::maps::MapData, V> pub type aya::maps::queue::Queue<&'a mut aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::queue::Queue<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::queue::Queue<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::stack::Stack<&'a mut aya::maps::MapData, V> pub type aya::maps::stack::Stack<&'a mut aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::stack::Stack<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::stack::Stack<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::CpuMap<&'a aya::maps::MapData> +pub type aya::maps::CpuMap<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::CpuMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::DevMap<&'a aya::maps::MapData> +pub type aya::maps::DevMap<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::DevMapHash<&'a aya::maps::MapData> +pub type aya::maps::DevMapHash<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMapHash<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::ProgramArray<&'a aya::maps::MapData> pub type aya::maps::ProgramArray<&'a aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::ProgramArray<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::ProgramArray<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::SockMap<&'a aya::maps::MapData> pub type aya::maps::SockMap<&'a aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::SockMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::SockMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::XskMap<&'a aya::maps::MapData> +pub type aya::maps::XskMap<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::XskMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::perf::AsyncPerfEventArray<&'a aya::maps::MapData> pub type aya::maps::perf::AsyncPerfEventArray<&'a aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::perf::AsyncPerfEventArray<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::perf::AsyncPerfEventArray<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::perf::PerfEventArray<&'a aya::maps::MapData> pub type aya::maps::perf::PerfEventArray<&'a aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::perf::PerfEventArray<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::perf::PerfEventArray<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::ring_buf::RingBuf<&'a aya::maps::MapData> +pub type aya::maps::ring_buf::RingBuf<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::ring_buf::RingBuf<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::stack_trace::StackTraceMap<&'a aya::maps::MapData> pub type aya::maps::stack_trace::StackTraceMap<&'a aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::stack_trace::StackTraceMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::stack_trace::StackTraceMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::CpuMap<&'a mut aya::maps::MapData> +pub type aya::maps::CpuMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::CpuMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::DevMap<&'a mut aya::maps::MapData> +pub type aya::maps::DevMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::DevMapHash<&'a mut aya::maps::MapData> +pub type aya::maps::DevMapHash<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMapHash<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::ProgramArray<&'a mut aya::maps::MapData> pub type aya::maps::ProgramArray<&'a mut aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::ProgramArray<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::ProgramArray<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::SockMap<&'a mut aya::maps::MapData> pub type aya::maps::SockMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::SockMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::SockMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::XskMap<&'a mut aya::maps::MapData> +pub type aya::maps::XskMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::XskMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::perf::AsyncPerfEventArray<&'a mut aya::maps::MapData> pub type aya::maps::perf::AsyncPerfEventArray<&'a mut aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::perf::AsyncPerfEventArray<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::perf::AsyncPerfEventArray<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::perf::PerfEventArray<&'a mut aya::maps::MapData> pub type aya::maps::perf::PerfEventArray<&'a mut aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::perf::PerfEventArray<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::perf::PerfEventArray<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::ring_buf::RingBuf<&'a mut aya::maps::MapData> +pub type aya::maps::ring_buf::RingBuf<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::ring_buf::RingBuf<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::stack_trace::StackTraceMap<&'a mut aya::maps::MapData> pub type aya::maps::stack_trace::StackTraceMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::stack_trace::StackTraceMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> -impl core::convert::TryFrom for aya::maps::hash_map::HashMap -pub type aya::maps::hash_map::HashMap::Error = aya::maps::MapError -pub fn aya::maps::hash_map::HashMap::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> -impl core::convert::TryFrom for aya::maps::hash_map::PerCpuHashMap -pub type aya::maps::hash_map::PerCpuHashMap::Error = aya::maps::MapError -pub fn aya::maps::hash_map::PerCpuHashMap::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> -impl core::convert::TryFrom for aya::maps::lpm_trie::LpmTrie -pub type aya::maps::lpm_trie::LpmTrie::Error = aya::maps::MapError -pub fn aya::maps::lpm_trie::LpmTrie::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::stack_trace::StackTraceMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::convert::TryFrom for aya::maps::hash_map::HashMap +pub type aya::maps::hash_map::HashMap::Error = aya::maps::MapError +pub fn aya::maps::hash_map::HashMap::try_from(map: aya::maps::Map) -> core::result::Result +impl core::convert::TryFrom for aya::maps::hash_map::PerCpuHashMap +pub type aya::maps::hash_map::PerCpuHashMap::Error = aya::maps::MapError +pub fn aya::maps::hash_map::PerCpuHashMap::try_from(map: aya::maps::Map) -> core::result::Result +impl core::convert::TryFrom for aya::maps::lpm_trie::LpmTrie +pub type aya::maps::lpm_trie::LpmTrie::Error = aya::maps::MapError +pub fn aya::maps::lpm_trie::LpmTrie::try_from(map: aya::maps::Map) -> core::result::Result impl core::convert::TryFrom for aya::maps::PerCpuArray pub type aya::maps::PerCpuArray::Error = aya::maps::MapError -pub fn aya::maps::PerCpuArray::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::PerCpuArray::try_from(map: aya::maps::Map) -> core::result::Result impl core::convert::TryFrom for aya::maps::SockHash pub type aya::maps::SockHash::Error = aya::maps::MapError -pub fn aya::maps::SockHash::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::SockHash::try_from(map: aya::maps::Map) -> core::result::Result impl core::convert::TryFrom for aya::maps::array::Array pub type aya::maps::array::Array::Error = aya::maps::MapError -pub fn aya::maps::array::Array::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::array::Array::try_from(map: aya::maps::Map) -> core::result::Result impl core::convert::TryFrom for aya::maps::bloom_filter::BloomFilter pub type aya::maps::bloom_filter::BloomFilter::Error = aya::maps::MapError -pub fn aya::maps::bloom_filter::BloomFilter::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::bloom_filter::BloomFilter::try_from(map: aya::maps::Map) -> core::result::Result impl core::convert::TryFrom for aya::maps::queue::Queue pub type aya::maps::queue::Queue::Error = aya::maps::MapError -pub fn aya::maps::queue::Queue::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::queue::Queue::try_from(map: aya::maps::Map) -> core::result::Result impl core::convert::TryFrom for aya::maps::stack::Stack pub type aya::maps::stack::Stack::Error = aya::maps::MapError -pub fn aya::maps::stack::Stack::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::stack::Stack::try_from(map: aya::maps::Map) -> core::result::Result impl core::fmt::Debug for aya::maps::Map pub fn aya::maps::Map::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Send for aya::maps::Map @@ -968,7 +1296,7 @@ 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::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::code: core::ffi::c_long pub aya::maps::MapError::CreateError::io_error: std::io::error::Error pub aya::maps::MapError::CreateError::name: alloc::string::String pub aya::maps::MapError::ElementNotFound @@ -989,14 +1317,19 @@ pub aya::maps::MapError::OutOfBounds::max_entries: u32 pub aya::maps::MapError::PinError pub aya::maps::MapError::PinError::error: aya::pin::PinError pub aya::maps::MapError::PinError::name: core::option::Option +pub aya::maps::MapError::ProgIdNotSupported pub aya::maps::MapError::ProgramNotLoaded pub aya::maps::MapError::SyscallError(crate::sys::SyscallError) pub aya::maps::MapError::Unsupported pub aya::maps::MapError::Unsupported::map_type: u32 impl core::convert::From for aya::BpfError pub fn aya::BpfError::from(source: aya::maps::MapError) -> Self +impl core::convert::From for aya::maps::xdp::XdpMapError +pub fn aya::maps::xdp::XdpMapError::from(source: aya::maps::MapError) -> Self impl core::convert::From for aya::programs::ProgramError pub fn aya::programs::ProgramError::from(source: aya::maps::MapError) -> Self +impl core::convert::From for aya::maps::MapError +pub fn aya::maps::MapError::from(e: aya_obj::maps::InvalidMapTypeError) -> Self impl core::error::Error for aya::maps::MapError pub fn aya::maps::MapError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)> impl core::fmt::Display for aya::maps::MapError @@ -1032,19 +1365,21 @@ pub fn aya::maps::array::Array::get(&self, index: &u32, flags: u64) -> cor pub fn aya::maps::array::Array::iter(&self) -> impl core::iter::traits::iterator::Iterator> + '_ pub fn aya::maps::array::Array::len(&self) -> u32 impl, V: aya::Pod> aya::maps::array::Array +pub fn aya::maps::array::Array::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl, V: aya::Pod> aya::maps::array::Array pub fn aya::maps::array::Array::set(&mut self, index: u32, 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::array::Array<&'a aya::maps::MapData, V> pub type aya::maps::array::Array<&'a aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::array::Array<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::array::Array<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::array::Array<&'a mut aya::maps::MapData, V> pub type aya::maps::array::Array<&'a mut aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::array::Array<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::array::Array<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl, V: aya::Pod> aya::maps::IterableMap for aya::maps::array::Array pub fn aya::maps::array::Array::get(&self, index: &u32) -> core::result::Result pub fn aya::maps::array::Array::map(&self) -> &aya::maps::MapData impl core::convert::TryFrom for aya::maps::array::Array pub type aya::maps::array::Array::Error = aya::maps::MapError -pub fn aya::maps::array::Array::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::array::Array::try_from(map: aya::maps::Map) -> core::result::Result impl core::marker::Send for aya::maps::array::Array where T: core::marker::Send, V: core::marker::Send impl core::marker::Sync for aya::maps::array::Array where T: core::marker::Sync, V: core::marker::Sync impl core::marker::Unpin for aya::maps::array::Array where T: core::marker::Unpin, V: core::marker::Unpin @@ -1067,17 +1402,17 @@ pub fn aya::maps::array::Array::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::array::Array pub fn aya::maps::array::Array::from(t: T) -> T pub struct aya::maps::AsyncPerfEventArray -impl + core::borrow::Borrow> aya::maps::perf::AsyncPerfEventArray +impl> aya::maps::perf::AsyncPerfEventArray pub fn aya::maps::perf::AsyncPerfEventArray::open(&mut self, index: u32, page_count: core::option::Option) -> core::result::Result, aya::maps::perf::PerfBufferError> impl core::convert::TryFrom for aya::maps::perf::AsyncPerfEventArray pub type aya::maps::perf::AsyncPerfEventArray::Error = aya::maps::MapError -pub fn aya::maps::perf::AsyncPerfEventArray::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::perf::AsyncPerfEventArray::try_from(map: aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::perf::AsyncPerfEventArray<&'a aya::maps::MapData> pub type aya::maps::perf::AsyncPerfEventArray<&'a aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::perf::AsyncPerfEventArray<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::perf::AsyncPerfEventArray<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::perf::AsyncPerfEventArray<&'a mut aya::maps::MapData> pub type aya::maps::perf::AsyncPerfEventArray<&'a mut aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::perf::AsyncPerfEventArray<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::perf::AsyncPerfEventArray<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl core::marker::Send for aya::maps::perf::AsyncPerfEventArray where T: core::marker::Send + core::marker::Sync impl core::marker::Sync for aya::maps::perf::AsyncPerfEventArray where T: core::marker::Send + core::marker::Sync impl core::marker::Unpin for aya::maps::perf::AsyncPerfEventArray @@ -1104,15 +1439,17 @@ impl, V: aya::Pod> aya::maps::bloom_ pub fn aya::maps::bloom_filter::BloomFilter::contains(&self, value: &V, 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, V: aya::Pod> aya::maps::bloom_filter::BloomFilter +pub fn aya::maps::bloom_filter::BloomFilter::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> 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> +pub fn aya::maps::bloom_filter::BloomFilter<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::bloom_filter::BloomFilter<&'a mut aya::maps::MapData, V> pub type aya::maps::bloom_filter::BloomFilter<&'a mut aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::bloom_filter::BloomFilter<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::bloom_filter::BloomFilter<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl core::convert::TryFrom for aya::maps::bloom_filter::BloomFilter pub type aya::maps::bloom_filter::BloomFilter::Error = aya::maps::MapError -pub fn aya::maps::bloom_filter::BloomFilter::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::bloom_filter::BloomFilter::try_from(map: aya::maps::Map) -> core::result::Result impl core::fmt::Debug for aya::maps::bloom_filter::BloomFilter pub fn aya::maps::bloom_filter::BloomFilter::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Send for aya::maps::bloom_filter::BloomFilter where T: core::marker::Send, V: core::marker::Send @@ -1136,6 +1473,124 @@ impl core::borrow::BorrowMut for aya::maps::bloom_filter::BloomFilter::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::bloom_filter::BloomFilter pub fn aya::maps::bloom_filter::BloomFilter::from(t: T) -> T +pub struct aya::maps::CpuMap +impl> aya::maps::CpuMap +pub fn aya::maps::CpuMap::get(&self, cpu_index: u32, flags: u64) -> core::result::Result +pub fn aya::maps::CpuMap::iter(&self) -> impl core::iter::traits::iterator::Iterator> + '_ +pub fn aya::maps::CpuMap::len(&self) -> u32 +impl> aya::maps::CpuMap +pub fn aya::maps::CpuMap::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl> aya::maps::CpuMap +pub fn aya::maps::CpuMap::set(&mut self, cpu_index: u32, queue_size: u32, program: core::option::Option<&aya::programs::ProgramFd>, flags: u64) -> core::result::Result<(), aya::maps::xdp::XdpMapError> +impl core::convert::TryFrom for aya::maps::CpuMap +pub type aya::maps::CpuMap::Error = aya::maps::MapError +pub fn aya::maps::CpuMap::try_from(map: aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::CpuMap<&'a aya::maps::MapData> +pub type aya::maps::CpuMap<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::CpuMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::CpuMap<&'a mut aya::maps::MapData> +pub type aya::maps::CpuMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::CpuMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::marker::Send for aya::maps::CpuMap where T: core::marker::Send +impl core::marker::Sync for aya::maps::CpuMap where T: core::marker::Sync +impl core::marker::Unpin for aya::maps::CpuMap where T: core::marker::Unpin +impl core::panic::unwind_safe::RefUnwindSafe for aya::maps::CpuMap where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for aya::maps::CpuMap where T: core::panic::unwind_safe::UnwindSafe +impl core::convert::Into for aya::maps::CpuMap where U: core::convert::From +pub fn aya::maps::CpuMap::into(self) -> U +impl core::convert::TryFrom for aya::maps::CpuMap where U: core::convert::Into +pub type aya::maps::CpuMap::Error = core::convert::Infallible +pub fn aya::maps::CpuMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::CpuMap where U: core::convert::TryFrom +pub type aya::maps::CpuMap::Error = >::Error +pub fn aya::maps::CpuMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya::maps::CpuMap where T: 'static + core::marker::Sized +pub fn aya::maps::CpuMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::CpuMap where T: core::marker::Sized +pub fn aya::maps::CpuMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::CpuMap where T: core::marker::Sized +pub fn aya::maps::CpuMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::CpuMap +pub fn aya::maps::CpuMap::from(t: T) -> T +pub struct aya::maps::DevMap +impl> aya::maps::DevMap +pub fn aya::maps::DevMap::get(&self, index: u32, flags: u64) -> core::result::Result +pub fn aya::maps::DevMap::iter(&self) -> impl core::iter::traits::iterator::Iterator> + '_ +pub fn aya::maps::DevMap::len(&self) -> u32 +impl> aya::maps::DevMap +pub fn aya::maps::DevMap::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl> aya::maps::DevMap +pub fn aya::maps::DevMap::set(&mut self, index: u32, target_if_index: u32, program: core::option::Option<&aya::programs::ProgramFd>, flags: u64) -> core::result::Result<(), aya::maps::xdp::XdpMapError> +impl core::convert::TryFrom for aya::maps::DevMap +pub type aya::maps::DevMap::Error = aya::maps::MapError +pub fn aya::maps::DevMap::try_from(map: aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::DevMap<&'a aya::maps::MapData> +pub type aya::maps::DevMap<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::DevMap<&'a mut aya::maps::MapData> +pub type aya::maps::DevMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::marker::Send for aya::maps::DevMap where T: core::marker::Send +impl core::marker::Sync for aya::maps::DevMap where T: core::marker::Sync +impl core::marker::Unpin for aya::maps::DevMap where T: core::marker::Unpin +impl core::panic::unwind_safe::RefUnwindSafe for aya::maps::DevMap where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for aya::maps::DevMap where T: core::panic::unwind_safe::UnwindSafe +impl core::convert::Into for aya::maps::DevMap where U: core::convert::From +pub fn aya::maps::DevMap::into(self) -> U +impl core::convert::TryFrom for aya::maps::DevMap where U: core::convert::Into +pub type aya::maps::DevMap::Error = core::convert::Infallible +pub fn aya::maps::DevMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::DevMap where U: core::convert::TryFrom +pub type aya::maps::DevMap::Error = >::Error +pub fn aya::maps::DevMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya::maps::DevMap where T: 'static + core::marker::Sized +pub fn aya::maps::DevMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::DevMap where T: core::marker::Sized +pub fn aya::maps::DevMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::DevMap where T: core::marker::Sized +pub fn aya::maps::DevMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::DevMap +pub fn aya::maps::DevMap::from(t: T) -> T +pub struct aya::maps::DevMapHash +impl> aya::maps::DevMapHash +pub fn aya::maps::DevMapHash::get(&self, key: u32, flags: u64) -> core::result::Result +pub fn aya::maps::DevMapHash::iter(&self) -> aya::maps::MapIter<'_, u32, DevMapValue, Self> +pub fn aya::maps::DevMapHash::keys(&self) -> aya::maps::MapKeys<'_, u32> +impl> aya::maps::DevMapHash +pub fn aya::maps::DevMapHash::insert(&mut self, key: u32, target_if_index: u32, program: core::option::Option<&aya::programs::ProgramFd>, flags: u64) -> core::result::Result<(), aya::maps::xdp::XdpMapError> +pub fn aya::maps::DevMapHash::remove(&mut self, key: u32) -> core::result::Result<(), aya::maps::MapError> +impl> aya::maps::DevMapHash +pub fn aya::maps::DevMapHash::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl core::convert::TryFrom for aya::maps::DevMapHash +pub type aya::maps::DevMapHash::Error = aya::maps::MapError +pub fn aya::maps::DevMapHash::try_from(map: aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::DevMapHash<&'a aya::maps::MapData> +pub type aya::maps::DevMapHash<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMapHash<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::DevMapHash<&'a mut aya::maps::MapData> +pub type aya::maps::DevMapHash<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::DevMapHash<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::marker::Send for aya::maps::DevMapHash where T: core::marker::Send +impl core::marker::Sync for aya::maps::DevMapHash where T: core::marker::Sync +impl core::marker::Unpin for aya::maps::DevMapHash where T: core::marker::Unpin +impl core::panic::unwind_safe::RefUnwindSafe for aya::maps::DevMapHash where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for aya::maps::DevMapHash where T: core::panic::unwind_safe::UnwindSafe +impl core::convert::Into for aya::maps::DevMapHash where U: core::convert::From +pub fn aya::maps::DevMapHash::into(self) -> U +impl core::convert::TryFrom for aya::maps::DevMapHash where U: core::convert::Into +pub type aya::maps::DevMapHash::Error = core::convert::Infallible +pub fn aya::maps::DevMapHash::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::DevMapHash where U: core::convert::TryFrom +pub type aya::maps::DevMapHash::Error = >::Error +pub fn aya::maps::DevMapHash::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya::maps::DevMapHash where T: 'static + core::marker::Sized +pub fn aya::maps::DevMapHash::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::DevMapHash where T: core::marker::Sized +pub fn aya::maps::DevMapHash::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::DevMapHash where T: core::marker::Sized +pub fn aya::maps::DevMapHash::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::DevMapHash +pub fn aya::maps::DevMapHash::from(t: T) -> T pub struct aya::maps::HashMap impl, K: aya::Pod, V: aya::Pod> aya::maps::hash_map::HashMap pub fn aya::maps::hash_map::HashMap::get(&self, key: &K, flags: u64) -> core::result::Result @@ -1144,18 +1599,20 @@ pub fn aya::maps::hash_map::HashMap::keys(&self) -> aya::maps::MapKeys< impl, K: aya::Pod, V: aya::Pod> aya::maps::hash_map::HashMap pub fn aya::maps::hash_map::HashMap::insert(&mut self, key: impl core::borrow::Borrow, value: impl core::borrow::Borrow, flags: u64) -> core::result::Result<(), aya::maps::MapError> pub fn aya::maps::hash_map::HashMap::remove(&mut self, key: &K) -> core::result::Result<(), aya::maps::MapError> -impl<'a, V: aya::Pod, K: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::hash_map::HashMap<&'a aya::maps::MapData, V, K> -pub type aya::maps::hash_map::HashMap<&'a aya::maps::MapData, V, K>::Error = aya::maps::MapError -pub fn aya::maps::hash_map::HashMap<&'a aya::maps::MapData, V, K>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> -impl<'a, V: aya::Pod, K: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::hash_map::HashMap<&'a mut aya::maps::MapData, V, K> -pub type aya::maps::hash_map::HashMap<&'a mut aya::maps::MapData, V, K>::Error = aya::maps::MapError -pub fn aya::maps::hash_map::HashMap<&'a mut aya::maps::MapData, V, K>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +impl, K: aya::Pod, V: aya::Pod> aya::maps::hash_map::HashMap +pub fn aya::maps::hash_map::HashMap::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl<'a, K: aya::Pod, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::hash_map::HashMap<&'a aya::maps::MapData, K, V> +pub type aya::maps::hash_map::HashMap<&'a aya::maps::MapData, K, V>::Error = aya::maps::MapError +pub fn aya::maps::hash_map::HashMap<&'a aya::maps::MapData, K, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a, K: aya::Pod, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::hash_map::HashMap<&'a mut aya::maps::MapData, K, V> +pub type aya::maps::hash_map::HashMap<&'a mut aya::maps::MapData, K, V>::Error = aya::maps::MapError +pub fn aya::maps::hash_map::HashMap<&'a mut aya::maps::MapData, K, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::convert::TryFrom for aya::maps::hash_map::HashMap +pub type aya::maps::hash_map::HashMap::Error = aya::maps::MapError +pub fn aya::maps::hash_map::HashMap::try_from(map: aya::maps::Map) -> core::result::Result impl, K: aya::Pod, V: aya::Pod> aya::maps::IterableMap for aya::maps::hash_map::HashMap pub fn aya::maps::hash_map::HashMap::get(&self, key: &K) -> core::result::Result pub fn aya::maps::hash_map::HashMap::map(&self) -> &aya::maps::MapData -impl core::convert::TryFrom for aya::maps::hash_map::HashMap -pub type aya::maps::hash_map::HashMap::Error = aya::maps::MapError -pub fn aya::maps::hash_map::HashMap::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> impl core::fmt::Debug for aya::maps::hash_map::HashMap pub fn aya::maps::hash_map::HashMap::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Send for aya::maps::hash_map::HashMap where K: core::marker::Send, T: core::marker::Send, V: core::marker::Send @@ -1187,18 +1644,20 @@ pub fn aya::maps::lpm_trie::LpmTrie::keys(&self) -> aya::maps::MapKeys< impl, K: aya::Pod, V: aya::Pod> aya::maps::lpm_trie::LpmTrie pub fn aya::maps::lpm_trie::LpmTrie::insert(&mut self, key: &aya::maps::lpm_trie::Key, value: impl core::borrow::Borrow, flags: u64) -> core::result::Result<(), aya::maps::MapError> pub fn aya::maps::lpm_trie::LpmTrie::remove(&mut self, key: &aya::maps::lpm_trie::Key) -> core::result::Result<(), aya::maps::MapError> -impl<'a, V: aya::Pod, K: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::lpm_trie::LpmTrie<&'a aya::maps::MapData, V, K> -pub type aya::maps::lpm_trie::LpmTrie<&'a aya::maps::MapData, V, K>::Error = aya::maps::MapError -pub fn aya::maps::lpm_trie::LpmTrie<&'a aya::maps::MapData, V, K>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> -impl<'a, V: aya::Pod, K: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::lpm_trie::LpmTrie<&'a mut aya::maps::MapData, V, K> -pub type aya::maps::lpm_trie::LpmTrie<&'a mut aya::maps::MapData, V, K>::Error = aya::maps::MapError -pub fn aya::maps::lpm_trie::LpmTrie<&'a mut aya::maps::MapData, V, K>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +impl, K: aya::Pod, V: aya::Pod> aya::maps::lpm_trie::LpmTrie +pub fn aya::maps::lpm_trie::LpmTrie::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl<'a, K: aya::Pod, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::lpm_trie::LpmTrie<&'a aya::maps::MapData, K, V> +pub type aya::maps::lpm_trie::LpmTrie<&'a aya::maps::MapData, K, V>::Error = aya::maps::MapError +pub fn aya::maps::lpm_trie::LpmTrie<&'a aya::maps::MapData, K, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a, K: aya::Pod, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::lpm_trie::LpmTrie<&'a mut aya::maps::MapData, K, V> +pub type aya::maps::lpm_trie::LpmTrie<&'a mut aya::maps::MapData, K, V>::Error = aya::maps::MapError +pub fn aya::maps::lpm_trie::LpmTrie<&'a mut aya::maps::MapData, K, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::convert::TryFrom for aya::maps::lpm_trie::LpmTrie +pub type aya::maps::lpm_trie::LpmTrie::Error = aya::maps::MapError +pub fn aya::maps::lpm_trie::LpmTrie::try_from(map: aya::maps::Map) -> core::result::Result impl, K: aya::Pod, V: aya::Pod> aya::maps::IterableMap, V> for aya::maps::lpm_trie::LpmTrie pub fn aya::maps::lpm_trie::LpmTrie::get(&self, key: &aya::maps::lpm_trie::Key) -> core::result::Result pub fn aya::maps::lpm_trie::LpmTrie::map(&self) -> &aya::maps::MapData -impl core::convert::TryFrom for aya::maps::lpm_trie::LpmTrie -pub type aya::maps::lpm_trie::LpmTrie::Error = aya::maps::MapError -pub fn aya::maps::lpm_trie::LpmTrie::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> impl core::fmt::Debug for aya::maps::lpm_trie::LpmTrie pub fn aya::maps::lpm_trie::LpmTrie::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Send for aya::maps::lpm_trie::LpmTrie where K: core::marker::Send, T: core::marker::Send, V: core::marker::Send @@ -1223,16 +1682,14 @@ pub fn aya::maps::lpm_trie::LpmTrie::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::lpm_trie::LpmTrie 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(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) -> Self -impl core::ops::drop::Drop for aya::maps::MapData -pub fn aya::maps::MapData::drop(&mut self) +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_id(id: u32) -> core::result::Result +pub fn aya::maps::MapData::from_pin>(path: P) -> core::result::Result +pub fn aya::maps::MapData::info(&self) -> core::result::Result +pub fn aya::maps::MapData::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> impl core::fmt::Debug for aya::maps::MapData pub fn aya::maps::MapData::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Send for aya::maps::MapData @@ -1248,10 +1705,6 @@ pub fn aya::maps::MapData::try_from(value: U) -> core::result::Result core::convert::TryInto for aya::maps::MapData where U: core::convert::TryFrom pub type aya::maps::MapData::Error = >::Error pub fn aya::maps::MapData::try_into(self) -> core::result::Result>::Error> -impl alloc::borrow::ToOwned for aya::maps::MapData where T: core::clone::Clone -pub type aya::maps::MapData::Owned = T -pub fn aya::maps::MapData::clone_into(&self, target: &mut T) -pub fn aya::maps::MapData::to_owned(&self) -> T impl core::any::Any for aya::maps::MapData where T: 'static + core::marker::Sized pub fn aya::maps::MapData::type_id(&self) -> core::any::TypeId impl core::borrow::Borrow for aya::maps::MapData where T: core::marker::Sized @@ -1261,8 +1714,10 @@ pub fn aya::maps::MapData::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::MapData pub fn aya::maps::MapData::from(t: T) -> T pub struct aya::maps::MapFd(_) -impl std::os::fd::raw::AsRawFd for aya::maps::MapFd -pub fn aya::maps::MapFd::as_raw_fd(&self) -> std::os::fd::raw::RawFd +impl std::os::fd::owned::AsFd for aya::maps::MapFd +pub fn aya::maps::MapFd::as_fd(&self) -> std::os::fd::owned::BorrowedFd<'_> +impl core::fmt::Debug for aya::maps::MapFd +pub fn aya::maps::MapFd::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Send for aya::maps::MapFd impl core::marker::Sync for aya::maps::MapFd impl core::marker::Unpin for aya::maps::MapFd @@ -1284,6 +1739,42 @@ impl core::borrow::BorrowMut for aya::maps::MapFd where T: core::marker::S pub fn aya::maps::MapFd::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::MapFd pub fn aya::maps::MapFd::from(t: T) -> T +pub struct aya::maps::MapInfo(_) +impl aya::maps::MapInfo +pub fn aya::maps::MapInfo::fd(&self) -> core::result::Result +pub fn aya::maps::MapInfo::from_id(id: u32) -> core::result::Result +pub fn aya::maps::MapInfo::from_pin>(path: P) -> core::result::Result +pub fn aya::maps::MapInfo::id(&self) -> u32 +pub fn aya::maps::MapInfo::key_size(&self) -> u32 +pub fn aya::maps::MapInfo::map_flags(&self) -> u32 +pub fn aya::maps::MapInfo::map_type(&self) -> u32 +pub fn aya::maps::MapInfo::max_entries(&self) -> u32 +pub fn aya::maps::MapInfo::name(&self) -> &[u8] +pub fn aya::maps::MapInfo::name_as_str(&self) -> core::option::Option<&str> +pub fn aya::maps::MapInfo::value_size(&self) -> u32 +impl core::fmt::Debug for aya::maps::MapInfo +pub fn aya::maps::MapInfo::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::marker::Send for aya::maps::MapInfo +impl core::marker::Sync for aya::maps::MapInfo +impl core::marker::Unpin for aya::maps::MapInfo +impl core::panic::unwind_safe::RefUnwindSafe for aya::maps::MapInfo +impl core::panic::unwind_safe::UnwindSafe for aya::maps::MapInfo +impl core::convert::Into for aya::maps::MapInfo where U: core::convert::From +pub fn aya::maps::MapInfo::into(self) -> U +impl core::convert::TryFrom for aya::maps::MapInfo where U: core::convert::Into +pub type aya::maps::MapInfo::Error = core::convert::Infallible +pub fn aya::maps::MapInfo::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::MapInfo where U: core::convert::TryFrom +pub type aya::maps::MapInfo::Error = >::Error +pub fn aya::maps::MapInfo::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya::maps::MapInfo where T: 'static + core::marker::Sized +pub fn aya::maps::MapInfo::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::MapInfo where T: core::marker::Sized +pub fn aya::maps::MapInfo::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::MapInfo where T: core::marker::Sized +pub fn aya::maps::MapInfo::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::MapInfo +pub fn aya::maps::MapInfo::from(t: T) -> T pub struct aya::maps::MapIter<'coll, K: aya::Pod, V, I: aya::maps::IterableMap> impl> core::iter::traits::iterator::Iterator for aya::maps::MapIter<'_, K, V, I> pub type aya::maps::MapIter<'_, K, V, I>::Item = core::result::Result<(K, V), aya::maps::MapError> @@ -1348,19 +1839,21 @@ pub fn aya::maps::PerCpuArray::get(&self, index: &u32, flags: u64) -> core pub fn aya::maps::PerCpuArray::iter(&self) -> impl core::iter::traits::iterator::Iterator, aya::maps::MapError>> + '_ pub fn aya::maps::PerCpuArray::len(&self) -> u32 impl, V: aya::Pod> aya::maps::PerCpuArray +pub fn aya::maps::PerCpuArray::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl, V: aya::Pod> aya::maps::PerCpuArray pub fn aya::maps::PerCpuArray::set(&mut self, index: u32, values: aya::maps::PerCpuValues, flags: u64) -> core::result::Result<(), aya::maps::MapError> impl<'a, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::PerCpuArray<&'a aya::maps::MapData, V> pub type aya::maps::PerCpuArray<&'a aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::PerCpuArray<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::PerCpuArray<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::PerCpuArray<&'a mut aya::maps::MapData, V> pub type aya::maps::PerCpuArray<&'a mut aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::PerCpuArray<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::PerCpuArray<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl, V: aya::Pod> aya::maps::IterableMap> for aya::maps::PerCpuArray pub fn aya::maps::PerCpuArray::get(&self, index: &u32) -> core::result::Result, aya::maps::MapError> pub fn aya::maps::PerCpuArray::map(&self) -> &aya::maps::MapData impl core::convert::TryFrom for aya::maps::PerCpuArray pub type aya::maps::PerCpuArray::Error = aya::maps::MapError -pub fn aya::maps::PerCpuArray::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::PerCpuArray::try_from(map: aya::maps::Map) -> core::result::Result impl core::marker::Send for aya::maps::PerCpuArray where T: core::marker::Send, V: core::marker::Send impl core::marker::Sync for aya::maps::PerCpuArray where T: core::marker::Sync, V: core::marker::Sync impl core::marker::Unpin for aya::maps::PerCpuArray where T: core::marker::Unpin, V: core::marker::Unpin @@ -1390,18 +1883,20 @@ pub fn aya::maps::hash_map::PerCpuHashMap::keys(&self) -> aya::maps::Ma impl, K: aya::Pod, V: aya::Pod> aya::maps::hash_map::PerCpuHashMap pub fn aya::maps::hash_map::PerCpuHashMap::insert(&mut self, key: impl core::borrow::Borrow, values: aya::maps::PerCpuValues, flags: u64) -> core::result::Result<(), aya::maps::MapError> pub fn aya::maps::hash_map::PerCpuHashMap::remove(&mut self, key: &K) -> core::result::Result<(), aya::maps::MapError> -impl<'a, V: aya::Pod, K: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::hash_map::PerCpuHashMap<&'a aya::maps::MapData, V, K> -pub type aya::maps::hash_map::PerCpuHashMap<&'a aya::maps::MapData, V, K>::Error = aya::maps::MapError -pub fn aya::maps::hash_map::PerCpuHashMap<&'a aya::maps::MapData, V, K>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> -impl<'a, V: aya::Pod, K: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::hash_map::PerCpuHashMap<&'a mut aya::maps::MapData, V, K> -pub type aya::maps::hash_map::PerCpuHashMap<&'a mut aya::maps::MapData, V, K>::Error = aya::maps::MapError -pub fn aya::maps::hash_map::PerCpuHashMap<&'a mut aya::maps::MapData, V, K>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +impl, K: aya::Pod, V: aya::Pod> aya::maps::hash_map::PerCpuHashMap +pub fn aya::maps::hash_map::PerCpuHashMap::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl<'a, K: aya::Pod, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::hash_map::PerCpuHashMap<&'a aya::maps::MapData, K, V> +pub type aya::maps::hash_map::PerCpuHashMap<&'a aya::maps::MapData, K, V>::Error = aya::maps::MapError +pub fn aya::maps::hash_map::PerCpuHashMap<&'a aya::maps::MapData, K, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a, K: aya::Pod, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::hash_map::PerCpuHashMap<&'a mut aya::maps::MapData, K, V> +pub type aya::maps::hash_map::PerCpuHashMap<&'a mut aya::maps::MapData, K, V>::Error = aya::maps::MapError +pub fn aya::maps::hash_map::PerCpuHashMap<&'a mut aya::maps::MapData, K, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::convert::TryFrom for aya::maps::hash_map::PerCpuHashMap +pub type aya::maps::hash_map::PerCpuHashMap::Error = aya::maps::MapError +pub fn aya::maps::hash_map::PerCpuHashMap::try_from(map: aya::maps::Map) -> core::result::Result impl, K: aya::Pod, V: aya::Pod> aya::maps::IterableMap> for aya::maps::hash_map::PerCpuHashMap pub fn aya::maps::hash_map::PerCpuHashMap::get(&self, key: &K) -> core::result::Result, aya::maps::MapError> pub fn aya::maps::hash_map::PerCpuHashMap::map(&self) -> &aya::maps::MapData -impl core::convert::TryFrom for aya::maps::hash_map::PerCpuHashMap -pub type aya::maps::hash_map::PerCpuHashMap::Error = aya::maps::MapError -pub fn aya::maps::hash_map::PerCpuHashMap::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> impl core::marker::Send for aya::maps::hash_map::PerCpuHashMap where K: core::marker::Send, T: core::marker::Send, V: core::marker::Send impl core::marker::Sync for aya::maps::hash_map::PerCpuHashMap where K: core::marker::Sync, T: core::marker::Sync, V: core::marker::Sync impl core::marker::Unpin for aya::maps::hash_map::PerCpuHashMap where K: core::marker::Unpin, T: core::marker::Unpin, V: core::marker::Unpin @@ -1424,11 +1919,11 @@ pub fn aya::maps::hash_map::PerCpuHashMap::borrow_mut(&mut self) -> &mu impl core::convert::From for aya::maps::hash_map::PerCpuHashMap pub fn aya::maps::hash_map::PerCpuHashMap::from(t: T) -> T pub struct aya::maps::PerCpuValues -impl core::convert::TryFrom> for aya::maps::PerCpuValues +impl core::convert::TryFrom> for aya::maps::PerCpuValues pub type aya::maps::PerCpuValues::Error = std::io::error::Error pub fn aya::maps::PerCpuValues::try_from(values: alloc::vec::Vec) -> core::result::Result impl core::ops::deref::Deref for aya::maps::PerCpuValues -pub type aya::maps::PerCpuValues::Target = alloc::boxed::Box<[T], alloc::alloc::Global> +pub type aya::maps::PerCpuValues::Target = alloc::boxed::Box<[T]> pub fn aya::maps::PerCpuValues::deref(&self) -> &Self::Target impl, K: aya::Pod, V: aya::Pod> aya::maps::IterableMap> for aya::maps::hash_map::PerCpuHashMap pub fn aya::maps::hash_map::PerCpuHashMap::get(&self, key: &K) -> core::result::Result, aya::maps::MapError> @@ -1460,17 +1955,17 @@ pub fn aya::maps::PerCpuValues::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::PerCpuValues pub fn aya::maps::PerCpuValues::from(t: T) -> T pub struct aya::maps::PerfEventArray -impl + core::borrow::Borrow> aya::maps::perf::PerfEventArray +impl> aya::maps::perf::PerfEventArray pub fn aya::maps::perf::PerfEventArray::open(&mut self, index: u32, page_count: core::option::Option) -> core::result::Result, aya::maps::perf::PerfBufferError> impl core::convert::TryFrom for aya::maps::perf::PerfEventArray pub type aya::maps::perf::PerfEventArray::Error = aya::maps::MapError -pub fn aya::maps::perf::PerfEventArray::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::perf::PerfEventArray::try_from(map: aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::perf::PerfEventArray<&'a aya::maps::MapData> pub type aya::maps::perf::PerfEventArray<&'a aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::perf::PerfEventArray<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::perf::PerfEventArray<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::perf::PerfEventArray<&'a mut aya::maps::MapData> pub type aya::maps::perf::PerfEventArray<&'a mut aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::perf::PerfEventArray<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::perf::PerfEventArray<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl core::marker::Send for aya::maps::perf::PerfEventArray where T: core::marker::Send + core::marker::Sync impl core::marker::Sync for aya::maps::perf::PerfEventArray where T: core::marker::Send + core::marker::Sync impl core::marker::Unpin for aya::maps::perf::PerfEventArray @@ -1498,15 +1993,17 @@ 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> +impl> aya::maps::ProgramArray +pub fn aya::maps::ProgramArray::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> 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> +pub fn aya::maps::ProgramArray::try_from(map: aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::ProgramArray<&'a aya::maps::MapData> pub type aya::maps::ProgramArray<&'a aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::ProgramArray<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::ProgramArray<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::ProgramArray<&'a mut aya::maps::MapData> pub type aya::maps::ProgramArray<&'a mut aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::ProgramArray<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::ProgramArray<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl core::marker::Send for aya::maps::ProgramArray where T: core::marker::Send impl core::marker::Sync for aya::maps::ProgramArray where T: core::marker::Sync impl core::marker::Unpin for aya::maps::ProgramArray where T: core::marker::Unpin @@ -1532,17 +2029,19 @@ pub struct aya::maps::Queue impl, V: aya::Pod> aya::maps::queue::Queue pub fn aya::maps::queue::Queue::capacity(&self) -> u32 impl, V: aya::Pod> aya::maps::queue::Queue +pub fn aya::maps::queue::Queue::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl, V: aya::Pod> aya::maps::queue::Queue pub fn aya::maps::queue::Queue::pop(&mut self, flags: u64) -> core::result::Result pub fn aya::maps::queue::Queue::push(&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::queue::Queue<&'a aya::maps::MapData, V> pub type aya::maps::queue::Queue<&'a aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::queue::Queue<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::queue::Queue<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::queue::Queue<&'a mut aya::maps::MapData, V> pub type aya::maps::queue::Queue<&'a mut aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::queue::Queue<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::queue::Queue<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl core::convert::TryFrom for aya::maps::queue::Queue pub type aya::maps::queue::Queue::Error = aya::maps::MapError -pub fn aya::maps::queue::Queue::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::queue::Queue::try_from(map: aya::maps::Map) -> core::result::Result impl core::marker::Send for aya::maps::queue::Queue where T: core::marker::Send, V: core::marker::Send impl core::marker::Sync for aya::maps::queue::Queue where T: core::marker::Sync, V: core::marker::Sync impl core::marker::Unpin for aya::maps::queue::Queue where T: core::marker::Unpin, V: core::marker::Unpin @@ -1564,27 +2063,64 @@ impl core::borrow::BorrowMut for aya::maps::queue::Queue where T: co pub fn aya::maps::queue::Queue::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::queue::Queue pub fn aya::maps::queue::Queue::from(t: T) -> T +pub struct aya::maps::RingBuf +impl aya::maps::ring_buf::RingBuf +pub fn aya::maps::ring_buf::RingBuf::next(&mut self) -> core::option::Option> +impl core::convert::TryFrom for aya::maps::ring_buf::RingBuf +pub type aya::maps::ring_buf::RingBuf::Error = aya::maps::MapError +pub fn aya::maps::ring_buf::RingBuf::try_from(map: aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::ring_buf::RingBuf<&'a aya::maps::MapData> +pub type aya::maps::ring_buf::RingBuf<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::ring_buf::RingBuf<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::ring_buf::RingBuf<&'a mut aya::maps::MapData> +pub type aya::maps::ring_buf::RingBuf<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::ring_buf::RingBuf<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl> std::os::fd::raw::AsRawFd for aya::maps::ring_buf::RingBuf +pub fn aya::maps::ring_buf::RingBuf::as_raw_fd(&self) -> std::os::fd::raw::RawFd +impl !core::marker::Send for aya::maps::ring_buf::RingBuf +impl !core::marker::Sync for aya::maps::ring_buf::RingBuf +impl core::marker::Unpin for aya::maps::ring_buf::RingBuf where T: core::marker::Unpin +impl core::panic::unwind_safe::RefUnwindSafe for aya::maps::ring_buf::RingBuf where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for aya::maps::ring_buf::RingBuf where T: core::panic::unwind_safe::UnwindSafe +impl core::convert::Into for aya::maps::ring_buf::RingBuf where U: core::convert::From +pub fn aya::maps::ring_buf::RingBuf::into(self) -> U +impl core::convert::TryFrom for aya::maps::ring_buf::RingBuf where U: core::convert::Into +pub type aya::maps::ring_buf::RingBuf::Error = core::convert::Infallible +pub fn aya::maps::ring_buf::RingBuf::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::ring_buf::RingBuf where U: core::convert::TryFrom +pub type aya::maps::ring_buf::RingBuf::Error = >::Error +pub fn aya::maps::ring_buf::RingBuf::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya::maps::ring_buf::RingBuf where T: 'static + core::marker::Sized +pub fn aya::maps::ring_buf::RingBuf::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::ring_buf::RingBuf where T: core::marker::Sized +pub fn aya::maps::ring_buf::RingBuf::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::ring_buf::RingBuf where T: core::marker::Sized +pub fn aya::maps::ring_buf::RingBuf::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::ring_buf::RingBuf +pub fn aya::maps::ring_buf::RingBuf::from(t: T) -> T pub struct aya::maps::SockHash impl, K: aya::Pod> aya::maps::SockHash -pub fn aya::maps::SockHash::fd(&self) -> core::result::Result +pub fn aya::maps::SockHash::fd(&self) -> &aya::maps::sock::SockMapFd pub fn aya::maps::SockHash::get(&self, key: &K, flags: u64) -> core::result::Result pub fn aya::maps::SockHash::iter(&self) -> aya::maps::MapIter<'_, K, std::os::fd::raw::RawFd, Self> pub fn aya::maps::SockHash::keys(&self) -> aya::maps::MapKeys<'_, K> impl, K: aya::Pod> aya::maps::SockHash pub fn aya::maps::SockHash::insert(&mut self, key: impl core::borrow::Borrow, value: I, flags: u64) -> core::result::Result<(), aya::maps::MapError> pub fn aya::maps::SockHash::remove(&mut self, key: &K) -> core::result::Result<(), aya::maps::MapError> +impl, V: aya::Pod> aya::maps::SockHash +pub fn aya::maps::SockHash::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> impl<'a, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::SockHash<&'a aya::maps::MapData, V> pub type aya::maps::SockHash<&'a aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::SockHash<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::SockHash<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::SockHash<&'a mut aya::maps::MapData, V> pub type aya::maps::SockHash<&'a mut aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::SockHash<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::SockHash<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl, K: aya::Pod> aya::maps::IterableMap for aya::maps::SockHash pub fn aya::maps::SockHash::get(&self, key: &K) -> core::result::Result pub fn aya::maps::SockHash::map(&self) -> &aya::maps::MapData impl core::convert::TryFrom for aya::maps::SockHash pub type aya::maps::SockHash::Error = aya::maps::MapError -pub fn aya::maps::SockHash::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::SockHash::try_from(map: aya::maps::Map) -> core::result::Result impl core::marker::Send for aya::maps::SockHash where K: core::marker::Send, T: core::marker::Send impl core::marker::Sync for aya::maps::SockHash where K: core::marker::Sync, T: core::marker::Sync impl core::marker::Unpin for aya::maps::SockHash where K: core::marker::Unpin, T: core::marker::Unpin @@ -1608,20 +2144,22 @@ impl core::convert::From for aya::maps::SockHash pub fn aya::maps::SockHash::from(t: T) -> T pub struct aya::maps::SockMap impl> aya::maps::SockMap -pub fn aya::maps::SockMap::fd(&self) -> core::result::Result +pub fn aya::maps::SockMap::fd(&self) -> &aya::maps::sock::SockMapFd pub fn aya::maps::SockMap::indices(&self) -> aya::maps::MapKeys<'_, u32> impl> aya::maps::SockMap pub fn aya::maps::SockMap::clear_index(&mut self, index: &u32) -> core::result::Result<(), aya::maps::MapError> pub fn aya::maps::SockMap::set(&mut self, index: u32, socket: &I, flags: u64) -> core::result::Result<(), aya::maps::MapError> +impl> aya::maps::SockMap +pub fn aya::maps::SockMap::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> impl core::convert::TryFrom for aya::maps::SockMap pub type aya::maps::SockMap::Error = aya::maps::MapError -pub fn aya::maps::SockMap::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::SockMap::try_from(map: aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::SockMap<&'a aya::maps::MapData> pub type aya::maps::SockMap<&'a aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::SockMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::SockMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::SockMap<&'a mut aya::maps::MapData> pub type aya::maps::SockMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::SockMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::SockMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl core::marker::Send for aya::maps::SockMap where T: core::marker::Send impl core::marker::Sync for aya::maps::SockMap where T: core::marker::Sync impl core::marker::Unpin for aya::maps::SockMap where T: core::marker::Unpin @@ -1647,17 +2185,19 @@ pub struct aya::maps::Stack impl, V: aya::Pod> aya::maps::stack::Stack pub fn aya::maps::stack::Stack::capacity(&self) -> u32 impl, V: aya::Pod> aya::maps::stack::Stack +pub fn aya::maps::stack::Stack::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl, V: aya::Pod> aya::maps::stack::Stack pub fn aya::maps::stack::Stack::pop(&mut self, flags: u64) -> core::result::Result pub fn aya::maps::stack::Stack::push(&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::stack::Stack<&'a aya::maps::MapData, V> pub type aya::maps::stack::Stack<&'a aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::stack::Stack<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::stack::Stack<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a, V: aya::Pod> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::stack::Stack<&'a mut aya::maps::MapData, V> pub type aya::maps::stack::Stack<&'a mut aya::maps::MapData, V>::Error = aya::maps::MapError -pub fn aya::maps::stack::Stack<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::stack::Stack<&'a mut aya::maps::MapData, V>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result impl core::convert::TryFrom for aya::maps::stack::Stack pub type aya::maps::stack::Stack::Error = aya::maps::MapError -pub fn aya::maps::stack::Stack::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::stack::Stack::try_from(map: aya::maps::Map) -> core::result::Result impl core::marker::Send for aya::maps::stack::Stack where T: core::marker::Send, V: core::marker::Send impl core::marker::Sync for aya::maps::stack::Stack where T: core::marker::Sync, V: core::marker::Sync impl core::marker::Unpin for aya::maps::stack::Stack where T: core::marker::Unpin, V: core::marker::Unpin @@ -1684,19 +2224,21 @@ impl> aya::maps::stack_trace::StackT pub fn aya::maps::stack_trace::StackTraceMap::get(&self, stack_id: &u32, flags: u64) -> core::result::Result pub fn aya::maps::stack_trace::StackTraceMap::iter(&self) -> aya::maps::MapIter<'_, u32, aya::maps::stack_trace::StackTrace, Self> pub fn aya::maps::stack_trace::StackTraceMap::stack_ids(&self) -> aya::maps::MapKeys<'_, u32> +impl> aya::maps::stack_trace::StackTraceMap +pub fn aya::maps::stack_trace::StackTraceMap::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> impl core::convert::TryFrom for aya::maps::stack_trace::StackTraceMap pub type aya::maps::stack_trace::StackTraceMap::Error = aya::maps::MapError -pub fn aya::maps::stack_trace::StackTraceMap::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::stack_trace::StackTraceMap::try_from(map: aya::maps::Map) -> core::result::Result impl<'a, T: core::borrow::Borrow> core::iter::traits::collect::IntoIterator for &'a aya::maps::stack_trace::StackTraceMap pub type &'a aya::maps::stack_trace::StackTraceMap::IntoIter = aya::maps::MapIter<'a, u32, aya::maps::stack_trace::StackTrace, aya::maps::stack_trace::StackTraceMap> pub type &'a aya::maps::stack_trace::StackTraceMap::Item = core::result::Result<(u32, aya::maps::stack_trace::StackTrace), aya::maps::MapError> pub fn &'a aya::maps::stack_trace::StackTraceMap::into_iter(self) -> Self::IntoIter impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::stack_trace::StackTraceMap<&'a aya::maps::MapData> pub type aya::maps::stack_trace::StackTraceMap<&'a aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::stack_trace::StackTraceMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::stack_trace::StackTraceMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::stack_trace::StackTraceMap<&'a mut aya::maps::MapData> pub type aya::maps::stack_trace::StackTraceMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError -pub fn aya::maps::stack_trace::StackTraceMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result, aya::maps::MapError> +pub fn aya::maps::stack_trace::StackTraceMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result 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 @@ -1723,6 +2265,43 @@ 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 struct aya::maps::XskMap +impl> aya::maps::XskMap +pub fn aya::maps::XskMap::len(&self) -> u32 +impl> aya::maps::XskMap +pub fn aya::maps::XskMap::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> +impl> aya::maps::XskMap +pub fn aya::maps::XskMap::set(&mut self, index: u32, socket_fd: impl std::os::fd::raw::AsRawFd, flags: u64) -> core::result::Result<(), aya::maps::MapError> +impl core::convert::TryFrom for aya::maps::XskMap +pub type aya::maps::XskMap::Error = aya::maps::MapError +pub fn aya::maps::XskMap::try_from(map: aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::XskMap<&'a aya::maps::MapData> +pub type aya::maps::XskMap<&'a aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::XskMap<&'a aya::maps::MapData>::try_from(map: &'a aya::maps::Map) -> core::result::Result +impl<'a> core::convert::TryFrom<&'a mut aya::maps::Map> for aya::maps::XskMap<&'a mut aya::maps::MapData> +pub type aya::maps::XskMap<&'a mut aya::maps::MapData>::Error = aya::maps::MapError +pub fn aya::maps::XskMap<&'a mut aya::maps::MapData>::try_from(map: &'a mut aya::maps::Map) -> core::result::Result +impl core::marker::Send for aya::maps::XskMap where T: core::marker::Send +impl core::marker::Sync for aya::maps::XskMap where T: core::marker::Sync +impl core::marker::Unpin for aya::maps::XskMap where T: core::marker::Unpin +impl core::panic::unwind_safe::RefUnwindSafe for aya::maps::XskMap where T: core::panic::unwind_safe::RefUnwindSafe +impl core::panic::unwind_safe::UnwindSafe for aya::maps::XskMap where T: core::panic::unwind_safe::UnwindSafe +impl core::convert::Into for aya::maps::XskMap where U: core::convert::From +pub fn aya::maps::XskMap::into(self) -> U +impl core::convert::TryFrom for aya::maps::XskMap where U: core::convert::Into +pub type aya::maps::XskMap::Error = core::convert::Infallible +pub fn aya::maps::XskMap::try_from(value: U) -> core::result::Result>::Error> +impl core::convert::TryInto for aya::maps::XskMap where U: core::convert::TryFrom +pub type aya::maps::XskMap::Error = >::Error +pub fn aya::maps::XskMap::try_into(self) -> core::result::Result>::Error> +impl core::any::Any for aya::maps::XskMap where T: 'static + core::marker::Sized +pub fn aya::maps::XskMap::type_id(&self) -> core::any::TypeId +impl core::borrow::Borrow for aya::maps::XskMap where T: core::marker::Sized +pub fn aya::maps::XskMap::borrow(&self) -> &T +impl core::borrow::BorrowMut for aya::maps::XskMap where T: core::marker::Sized +pub fn aya::maps::XskMap::borrow_mut(&mut self) -> &mut T +impl core::convert::From for aya::maps::XskMap +pub fn aya::maps::XskMap::from(t: T) -> T pub trait aya::maps::IterableMap pub fn aya::maps::IterableMap::get(&self, key: &K) -> core::result::Result pub fn aya::maps::IterableMap::map(&self) -> &aya::maps::MapData @@ -1747,12 +2326,12 @@ pub fn aya::maps::PerCpuArray::map(&self) -> &aya::maps::MapData 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 +pub fn aya::maps::loaded_maps() -> impl core::iter::traits::iterator::Iterator> pub mod aya::pin pub enum aya::pin::PinError -pub aya::pin::PinError::AlreadyPinned -pub aya::pin::PinError::AlreadyPinned::name: alloc::string::String pub aya::pin::PinError::InvalidPinPath -pub aya::pin::PinError::InvalidPinPath::error: alloc::string::String +pub aya::pin::PinError::InvalidPinPath::error: alloc::ffi::c_str::NulError +pub aya::pin::PinError::InvalidPinPath::path: std::path::PathBuf pub aya::pin::PinError::NoFd pub aya::pin::PinError::NoFd::name: alloc::string::String pub aya::pin::PinError::SyscallError(crate::sys::SyscallError) @@ -1792,7 +2371,7 @@ pub use aya::programs::CgroupSockoptAttachType pub mod aya::programs::cgroup_device pub struct aya::programs::cgroup_device::CgroupDevice impl aya::programs::cgroup_device::CgroupDevice -pub fn aya::programs::cgroup_device::CgroupDevice::attach(&mut self, cgroup: T) -> core::result::Result +pub fn aya::programs::cgroup_device::CgroupDevice::attach(&mut self, cgroup: T) -> core::result::Result pub fn aya::programs::cgroup_device::CgroupDevice::detach(&mut self, link_id: aya::programs::cgroup_device::CgroupDeviceLinkId) -> core::result::Result<(), aya::programs::ProgramError> 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 @@ -1801,11 +2380,11 @@ pub fn aya::programs::cgroup_device::CgroupDevice::fd(&self) -> core::result::Re 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::info(&self) -> 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) @@ -1870,7 +2449,7 @@ impl core::convert::From for aya::programs::cgroup_device::CgroupDeviceLin pub fn aya::programs::cgroup_device::CgroupDeviceLink::from(t: T) -> T pub struct aya::programs::cgroup_device::CgroupDeviceLinkId(_) impl core::cmp::Eq for aya::programs::cgroup_device::CgroupDeviceLinkId -impl core::cmp::PartialEq for aya::programs::cgroup_device::CgroupDeviceLinkId +impl core::cmp::PartialEq for aya::programs::cgroup_device::CgroupDeviceLinkId pub fn aya::programs::cgroup_device::CgroupDeviceLinkId::eq(&self, other: &aya::programs::cgroup_device::CgroupDeviceLinkId) -> bool impl core::fmt::Debug for aya::programs::cgroup_device::CgroupDeviceLinkId pub fn aya::programs::cgroup_device::CgroupDeviceLinkId::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -1935,7 +2514,7 @@ impl core::convert::From for aya::programs::cgroup_skb::CgroupSkbAttachTyp pub fn aya::programs::cgroup_skb::CgroupSkbAttachType::from(t: T) -> T pub struct aya::programs::cgroup_skb::CgroupSkb impl aya::programs::cgroup_skb::CgroupSkb -pub fn aya::programs::cgroup_skb::CgroupSkb::attach(&mut self, cgroup: T, attach_type: aya::programs::cgroup_skb::CgroupSkbAttachType) -> core::result::Result +pub fn aya::programs::cgroup_skb::CgroupSkb::attach(&mut self, cgroup: T, attach_type: aya::programs::cgroup_skb::CgroupSkbAttachType) -> core::result::Result pub fn aya::programs::cgroup_skb::CgroupSkb::detach(&mut self, link_id: aya::programs::cgroup_skb::CgroupSkbLinkId) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_skb::CgroupSkb::expected_attach_type(&self) -> &core::option::Option pub fn aya::programs::cgroup_skb::CgroupSkb::from_pin>(path: P, expected_attach_type: aya::programs::cgroup_skb::CgroupSkbAttachType) -> core::result::Result @@ -1944,11 +2523,11 @@ pub fn aya::programs::cgroup_skb::CgroupSkb::take_link(&mut self, link_id: aya:: impl aya::programs::cgroup_skb::CgroupSkb 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::info(&self) -> core::result::Result +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) @@ -2013,7 +2592,7 @@ impl core::convert::From for aya::programs::cgroup_skb::CgroupSkbLink pub fn aya::programs::cgroup_skb::CgroupSkbLink::from(t: T) -> T pub struct aya::programs::cgroup_skb::CgroupSkbLinkId(_) impl core::cmp::Eq for aya::programs::cgroup_skb::CgroupSkbLinkId -impl core::cmp::PartialEq for aya::programs::cgroup_skb::CgroupSkbLinkId +impl core::cmp::PartialEq for aya::programs::cgroup_skb::CgroupSkbLinkId pub fn aya::programs::cgroup_skb::CgroupSkbLinkId::eq(&self, other: &aya::programs::cgroup_skb::CgroupSkbLinkId) -> bool impl core::fmt::Debug for aya::programs::cgroup_skb::CgroupSkbLinkId pub fn aya::programs::cgroup_skb::CgroupSkbLinkId::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -2046,7 +2625,7 @@ pub mod aya::programs::cgroup_sock pub use aya::programs::cgroup_sock::CgroupSockAttachType pub struct aya::programs::cgroup_sock::CgroupSock impl aya::programs::cgroup_sock::CgroupSock -pub fn aya::programs::cgroup_sock::CgroupSock::attach(&mut self, cgroup: T) -> core::result::Result +pub fn aya::programs::cgroup_sock::CgroupSock::attach(&mut self, cgroup: T) -> core::result::Result pub fn aya::programs::cgroup_sock::CgroupSock::detach(&mut self, link_id: aya::programs::cgroup_sock::CgroupSockLinkId) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sock::CgroupSock::from_pin>(path: P, attach_type: aya_obj::programs::cgroup_sock::CgroupSockAttachType) -> core::result::Result pub fn aya::programs::cgroup_sock::CgroupSock::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> @@ -2054,11 +2633,11 @@ pub fn aya::programs::cgroup_sock::CgroupSock::take_link(&mut self, link_id: aya impl aya::programs::cgroup_sock::CgroupSock 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::info(&self) -> core::result::Result +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) @@ -2123,7 +2702,7 @@ impl core::convert::From for aya::programs::cgroup_sock::CgroupSockLink pub fn aya::programs::cgroup_sock::CgroupSockLink::from(t: T) -> T pub struct aya::programs::cgroup_sock::CgroupSockLinkId(_) impl core::cmp::Eq for aya::programs::cgroup_sock::CgroupSockLinkId -impl core::cmp::PartialEq for aya::programs::cgroup_sock::CgroupSockLinkId +impl core::cmp::PartialEq for aya::programs::cgroup_sock::CgroupSockLinkId pub fn aya::programs::cgroup_sock::CgroupSockLinkId::eq(&self, other: &aya::programs::cgroup_sock::CgroupSockLinkId) -> bool impl core::fmt::Debug for aya::programs::cgroup_sock::CgroupSockLinkId pub fn aya::programs::cgroup_sock::CgroupSockLinkId::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -2156,7 +2735,7 @@ pub mod aya::programs::cgroup_sock_addr pub use aya::programs::cgroup_sock_addr::CgroupSockAddrAttachType pub struct aya::programs::cgroup_sock_addr::CgroupSockAddr impl aya::programs::cgroup_sock_addr::CgroupSockAddr -pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::attach(&mut self, cgroup: T) -> core::result::Result +pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::attach(&mut self, cgroup: T) -> core::result::Result pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::detach(&mut self, link_id: aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::from_pin>(path: P, attach_type: aya_obj::programs::cgroup_sock_addr::CgroupSockAddrAttachType) -> core::result::Result pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> @@ -2164,11 +2743,11 @@ pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::take_link(&mut self, lin impl aya::programs::cgroup_sock_addr::CgroupSockAddr 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::info(&self) -> core::result::Result +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) @@ -2233,7 +2812,7 @@ impl core::convert::From for aya::programs::cgroup_sock_addr::CgroupSockAd pub fn aya::programs::cgroup_sock_addr::CgroupSockAddrLink::from(t: T) -> T pub struct aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId(_) impl core::cmp::Eq for aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId -impl core::cmp::PartialEq for aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId +impl core::cmp::PartialEq for aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId pub fn aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId::eq(&self, other: &aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId) -> bool impl core::fmt::Debug for aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId pub fn aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -2266,7 +2845,7 @@ pub mod aya::programs::cgroup_sockopt pub use aya::programs::cgroup_sockopt::CgroupSockoptAttachType pub struct aya::programs::cgroup_sockopt::CgroupSockopt impl aya::programs::cgroup_sockopt::CgroupSockopt -pub fn aya::programs::cgroup_sockopt::CgroupSockopt::attach(&mut self, cgroup: T) -> core::result::Result +pub fn aya::programs::cgroup_sockopt::CgroupSockopt::attach(&mut self, cgroup: T) -> core::result::Result pub fn aya::programs::cgroup_sockopt::CgroupSockopt::detach(&mut self, link_id: aya::programs::cgroup_sockopt::CgroupSockoptLinkId) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sockopt::CgroupSockopt::from_pin>(path: P, attach_type: aya_obj::programs::cgroup_sockopt::CgroupSockoptAttachType) -> core::result::Result pub fn aya::programs::cgroup_sockopt::CgroupSockopt::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> @@ -2274,11 +2853,11 @@ pub fn aya::programs::cgroup_sockopt::CgroupSockopt::take_link(&mut self, link_i impl aya::programs::cgroup_sockopt::CgroupSockopt 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::info(&self) -> core::result::Result +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) @@ -2343,7 +2922,7 @@ impl core::convert::From for aya::programs::cgroup_sockopt::CgroupSockoptL pub fn aya::programs::cgroup_sockopt::CgroupSockoptLink::from(t: T) -> T pub struct aya::programs::cgroup_sockopt::CgroupSockoptLinkId(_) impl core::cmp::Eq for aya::programs::cgroup_sockopt::CgroupSockoptLinkId -impl core::cmp::PartialEq for aya::programs::cgroup_sockopt::CgroupSockoptLinkId +impl core::cmp::PartialEq for aya::programs::cgroup_sockopt::CgroupSockoptLinkId pub fn aya::programs::cgroup_sockopt::CgroupSockoptLinkId::eq(&self, other: &aya::programs::cgroup_sockopt::CgroupSockoptLinkId) -> bool impl core::fmt::Debug for aya::programs::cgroup_sockopt::CgroupSockoptLinkId pub fn aya::programs::cgroup_sockopt::CgroupSockoptLinkId::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -2375,7 +2954,7 @@ pub fn aya::programs::cgroup_sockopt::CgroupSockoptLinkId::from(t: T) -> T pub mod aya::programs::cgroup_sysctl pub struct aya::programs::cgroup_sysctl::CgroupSysctl impl aya::programs::cgroup_sysctl::CgroupSysctl -pub fn aya::programs::cgroup_sysctl::CgroupSysctl::attach(&mut self, cgroup: T) -> core::result::Result +pub fn aya::programs::cgroup_sysctl::CgroupSysctl::attach(&mut self, cgroup: T) -> core::result::Result pub fn aya::programs::cgroup_sysctl::CgroupSysctl::detach(&mut self, link_id: aya::programs::cgroup_sysctl::CgroupSysctlLinkId) -> core::result::Result<(), aya::programs::ProgramError> 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 @@ -2384,11 +2963,11 @@ pub fn aya::programs::cgroup_sysctl::CgroupSysctl::fd(&self) -> core::result::Re 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::info(&self) -> 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) @@ -2453,7 +3032,7 @@ impl core::convert::From for aya::programs::cgroup_sysctl::CgroupSysctlLin pub fn aya::programs::cgroup_sysctl::CgroupSysctlLink::from(t: T) -> T pub struct aya::programs::cgroup_sysctl::CgroupSysctlLinkId(_) impl core::cmp::Eq for aya::programs::cgroup_sysctl::CgroupSysctlLinkId -impl core::cmp::PartialEq for aya::programs::cgroup_sysctl::CgroupSysctlLinkId +impl core::cmp::PartialEq for aya::programs::cgroup_sysctl::CgroupSysctlLinkId pub fn aya::programs::cgroup_sysctl::CgroupSysctlLinkId::eq(&self, other: &aya::programs::cgroup_sysctl::CgroupSysctlLinkId) -> bool impl core::fmt::Debug for aya::programs::cgroup_sysctl::CgroupSysctlLinkId pub fn aya::programs::cgroup_sysctl::CgroupSysctlLinkId::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -2527,11 +3106,11 @@ pub fn aya::programs::extension::Extension::fd(&self) -> core::result::Result<&a 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::info(&self) -> 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) @@ -2600,7 +3179,7 @@ impl core::convert::From for aya::programs::extension::ExtensionLink pub fn aya::programs::extension::ExtensionLink::from(t: T) -> T pub struct aya::programs::extension::ExtensionLinkId(_) impl core::cmp::Eq for aya::programs::extension::ExtensionLinkId -impl core::cmp::PartialEq for aya::programs::extension::ExtensionLinkId +impl core::cmp::PartialEq for aya::programs::extension::ExtensionLinkId pub fn aya::programs::extension::ExtensionLinkId::eq(&self, other: &aya::programs::extension::ExtensionLinkId) -> bool impl core::fmt::Debug for aya::programs::extension::ExtensionLinkId pub fn aya::programs::extension::ExtensionLinkId::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -2641,11 +3220,11 @@ pub fn aya::programs::fentry::FEntry::fd(&self) -> core::result::Result<&aya::pr 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::info(&self) -> 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) @@ -2714,7 +3293,7 @@ impl core::convert::From for aya::programs::fentry::FEntryLink pub fn aya::programs::fentry::FEntryLink::from(t: T) -> T pub struct aya::programs::fentry::FEntryLinkId(_) impl core::cmp::Eq for aya::programs::fentry::FEntryLinkId -impl core::cmp::PartialEq for aya::programs::fentry::FEntryLinkId +impl core::cmp::PartialEq for aya::programs::fentry::FEntryLinkId pub fn aya::programs::fentry::FEntryLinkId::eq(&self, other: &aya::programs::fentry::FEntryLinkId) -> bool impl core::fmt::Debug for aya::programs::fentry::FEntryLinkId pub fn aya::programs::fentry::FEntryLinkId::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -2755,11 +3334,11 @@ pub fn aya::programs::fexit::FExit::fd(&self) -> core::result::Result<&aya::prog 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::info(&self) -> 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) @@ -2828,7 +3407,7 @@ impl core::convert::From for aya::programs::fexit::FExitLink pub fn aya::programs::fexit::FExitLink::from(t: T) -> T pub struct aya::programs::fexit::FExitLinkId(_) impl core::cmp::Eq for aya::programs::fexit::FExitLinkId -impl core::cmp::PartialEq for aya::programs::fexit::FExitLinkId +impl core::cmp::PartialEq for aya::programs::fexit::FExitLinkId pub fn aya::programs::fexit::FExitLinkId::eq(&self, other: &aya::programs::fexit::FExitLinkId) -> bool impl core::fmt::Debug for aya::programs::fexit::FExitLinkId pub fn aya::programs::fexit::FExitLinkId::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -2860,7 +3439,7 @@ pub fn aya::programs::fexit::FExitLinkId::from(t: T) -> T pub mod aya::programs::kprobe pub enum aya::programs::kprobe::KProbeError pub aya::programs::kprobe::KProbeError::FileError -pub aya::programs::kprobe::KProbeError::FileError::filename: alloc::string::String +pub aya::programs::kprobe::KProbeError::FileError::filename: std::path::PathBuf pub aya::programs::kprobe::KProbeError::FileError::io_error: std::io::error::Error impl core::convert::From for aya::programs::ProgramError pub fn aya::programs::ProgramError::from(source: aya::programs::kprobe::KProbeError) -> Self @@ -2895,7 +3474,7 @@ impl core::convert::From for aya::programs::kprobe::KProbeError pub fn aya::programs::kprobe::KProbeError::from(t: T) -> T pub struct aya::programs::kprobe::KProbe impl aya::programs::kprobe::KProbe -pub fn aya::programs::kprobe::KProbe::attach(&mut self, fn_name: &str, offset: u64) -> core::result::Result +pub fn aya::programs::kprobe::KProbe::attach>(&mut self, fn_name: T, offset: u64) -> core::result::Result pub fn aya::programs::kprobe::KProbe::detach(&mut self, link_id: aya::programs::kprobe::KProbeLinkId) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::kprobe::KProbe::from_pin>(path: P, kind: aya::programs::ProbeKind) -> core::result::Result pub fn aya::programs::kprobe::KProbe::kind(&self) -> aya::programs::ProbeKind @@ -2904,11 +3483,11 @@ pub fn aya::programs::kprobe::KProbe::take_link(&mut self, link_id: aya::program impl aya::programs::kprobe::KProbe 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::info(&self) -> core::result::Result +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) @@ -2979,7 +3558,7 @@ impl core::convert::From for aya::programs::kprobe::KProbeLink pub fn aya::programs::kprobe::KProbeLink::from(t: T) -> T pub struct aya::programs::kprobe::KProbeLinkId(_) impl core::cmp::Eq for aya::programs::kprobe::KProbeLinkId -impl core::cmp::PartialEq for aya::programs::kprobe::KProbeLinkId +impl core::cmp::PartialEq for aya::programs::kprobe::KProbeLinkId pub fn aya::programs::kprobe::KProbeLinkId::eq(&self, other: &aya::programs::kprobe::KProbeLinkId) -> bool impl core::fmt::Debug for aya::programs::kprobe::KProbeLinkId pub fn aya::programs::kprobe::KProbeLinkId::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -3125,7 +3704,7 @@ impl core::convert::From for aya::programs::links::FdLink pub fn aya::programs::links::FdLink::from(t: T) -> T pub struct aya::programs::links::FdLinkId(_) impl core::cmp::Eq for aya::programs::links::FdLinkId -impl core::cmp::PartialEq for aya::programs::links::FdLinkId +impl core::cmp::PartialEq for aya::programs::links::FdLinkId pub fn aya::programs::links::FdLinkId::eq(&self, other: &aya::programs::links::FdLinkId) -> bool impl core::fmt::Debug for aya::programs::links::FdLinkId pub fn aya::programs::links::FdLinkId::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -3213,7 +3792,7 @@ impl core::convert::From for aya::programs::links::ProgAttachLink pub fn aya::programs::links::ProgAttachLink::from(t: T) -> T pub struct aya::programs::links::ProgAttachLinkId(_, _, _) impl core::cmp::Eq for aya::programs::links::ProgAttachLinkId -impl core::cmp::PartialEq for aya::programs::links::ProgAttachLinkId +impl core::cmp::PartialEq for aya::programs::links::ProgAttachLinkId pub fn aya::programs::links::ProgAttachLinkId::eq(&self, other: &aya::programs::links::ProgAttachLinkId) -> bool impl core::fmt::Debug for aya::programs::links::ProgAttachLinkId pub fn aya::programs::links::ProgAttachLinkId::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -3363,7 +3942,7 @@ impl core::convert::From for aya::programs::lirc_mode2::LircLink pub fn aya::programs::lirc_mode2::LircLink::from(t: T) -> T pub struct aya::programs::lirc_mode2::LircLinkId(_, _) impl core::cmp::Eq for aya::programs::lirc_mode2::LircLinkId -impl core::cmp::PartialEq for aya::programs::lirc_mode2::LircLinkId +impl core::cmp::PartialEq for aya::programs::lirc_mode2::LircLinkId pub fn aya::programs::lirc_mode2::LircLinkId::eq(&self, other: &aya::programs::lirc_mode2::LircLinkId) -> bool impl core::fmt::Debug for aya::programs::lirc_mode2::LircLinkId pub fn aya::programs::lirc_mode2::LircLinkId::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -3394,21 +3973,21 @@ impl core::convert::From for aya::programs::lirc_mode2::LircLinkId pub fn aya::programs::lirc_mode2::LircLinkId::from(t: T) -> T pub struct aya::programs::lirc_mode2::LircMode2 impl aya::programs::lirc_mode2::LircMode2 -pub fn aya::programs::lirc_mode2::LircMode2::attach(&mut self, lircdev: T) -> core::result::Result +pub fn aya::programs::lirc_mode2::LircMode2::attach(&mut self, lircdev: T) -> core::result::Result pub fn aya::programs::lirc_mode2::LircMode2::detach(&mut self, link_id: aya::programs::lirc_mode2::LircLinkId) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::lirc_mode2::LircMode2::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> -pub fn aya::programs::lirc_mode2::LircMode2::query(target_fd: T) -> core::result::Result, aya::programs::ProgramError> +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::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::info(&self) -> 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) @@ -3453,11 +4032,11 @@ pub fn aya::programs::lsm::Lsm::fd(&self) -> core::result::Result<&aya::programs 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::info(&self) -> 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) @@ -3526,7 +4105,7 @@ impl core::convert::From for aya::programs::lsm::LsmLink pub fn aya::programs::lsm::LsmLink::from(t: T) -> T pub struct aya::programs::lsm::LsmLinkId(_) impl core::cmp::Eq for aya::programs::lsm::LsmLinkId -impl core::cmp::PartialEq for aya::programs::lsm::LsmLinkId +impl core::cmp::PartialEq for aya::programs::lsm::LsmLinkId pub fn aya::programs::lsm::LsmLinkId::eq(&self, other: &aya::programs::lsm::LsmLinkId) -> bool impl core::fmt::Debug for aya::programs::lsm::LsmLinkId pub fn aya::programs::lsm::LsmLinkId::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -3586,7 +4165,7 @@ impl core::convert::From for aya::programs::perf_attach::PerfLink pub fn aya::programs::perf_attach::PerfLink::from(t: T) -> T pub struct aya::programs::perf_attach::PerfLinkId(_) impl core::cmp::Eq for aya::programs::perf_attach::PerfLinkId -impl core::cmp::PartialEq for aya::programs::perf_attach::PerfLinkId +impl core::cmp::PartialEq for aya::programs::perf_attach::PerfLinkId pub fn aya::programs::perf_attach::PerfLinkId::eq(&self, other: &aya::programs::perf_attach::PerfLinkId) -> bool impl core::fmt::Debug for aya::programs::perf_attach::PerfLinkId pub fn aya::programs::perf_attach::PerfLinkId::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -3740,11 +4319,11 @@ pub fn aya::programs::perf_event::PerfEvent::fd(&self) -> core::result::Result<& 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::info(&self) -> 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) @@ -3815,7 +4394,7 @@ impl core::convert::From for aya::programs::perf_event::PerfEventLink pub fn aya::programs::perf_event::PerfEventLink::from(t: T) -> T pub struct aya::programs::perf_event::PerfEventLinkId(_) impl core::cmp::Eq for aya::programs::perf_event::PerfEventLinkId -impl core::cmp::PartialEq for aya::programs::perf_event::PerfEventLinkId +impl core::cmp::PartialEq for aya::programs::perf_event::PerfEventLinkId pub fn aya::programs::perf_event::PerfEventLinkId::eq(&self, other: &aya::programs::perf_event::PerfEventLinkId) -> bool impl core::fmt::Debug for aya::programs::perf_event::PerfEventLinkId pub fn aya::programs::perf_event::PerfEventLinkId::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -3852,7 +4431,7 @@ pub aya::programs::tc::TcAttachType::Ingress impl core::clone::Clone for aya::programs::tc::TcAttachType pub fn aya::programs::tc::TcAttachType::clone(&self) -> aya::programs::tc::TcAttachType impl core::cmp::Eq for aya::programs::tc::TcAttachType -impl core::cmp::PartialEq for aya::programs::tc::TcAttachType +impl core::cmp::PartialEq for aya::programs::tc::TcAttachType pub fn aya::programs::tc::TcAttachType::eq(&self, other: &aya::programs::tc::TcAttachType) -> bool impl core::fmt::Debug for aya::programs::tc::TcAttachType pub fn aya::programs::tc::TcAttachType::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -3932,11 +4511,11 @@ pub fn aya::programs::tc::SchedClassifier::take_link(&mut self, link_id: aya::pr impl aya::programs::tc::SchedClassifier 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::info(&self) -> core::result::Result +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) @@ -3971,7 +4550,7 @@ impl core::convert::From for aya::programs::tc::SchedClassifier pub fn aya::programs::tc::SchedClassifier::from(t: T) -> T pub struct aya::programs::tc::SchedClassifierLink(_) impl aya::programs::tc::SchedClassifierLink -pub fn aya::programs::tc::SchedClassifierLink::attached(if_name: &str, attach_type: aya::programs::tc::TcAttachType, priority: u16, handle: u32) -> core::result::Result +pub fn aya::programs::tc::SchedClassifierLink::attached(if_name: &str, attach_type: aya::programs::tc::TcAttachType, priority: u16, handle: u32) -> core::result::Result pub fn aya::programs::tc::SchedClassifierLink::handle(&self) -> u32 pub fn aya::programs::tc::SchedClassifierLink::priority(&self) -> u16 impl aya::programs::links::Link for aya::programs::tc::SchedClassifierLink @@ -4005,7 +4584,7 @@ impl core::convert::From for aya::programs::tc::SchedClassifierLink pub fn aya::programs::tc::SchedClassifierLink::from(t: T) -> T pub struct aya::programs::tc::SchedClassifierLinkId(_) impl core::cmp::Eq for aya::programs::tc::SchedClassifierLinkId -impl core::cmp::PartialEq for aya::programs::tc::SchedClassifierLinkId +impl core::cmp::PartialEq for aya::programs::tc::SchedClassifierLinkId pub fn aya::programs::tc::SchedClassifierLinkId::eq(&self, other: &aya::programs::tc::SchedClassifierLinkId) -> bool impl core::fmt::Debug for aya::programs::tc::SchedClassifierLinkId pub fn aya::programs::tc::SchedClassifierLinkId::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -4074,11 +4653,11 @@ pub fn aya::programs::tp_btf::BtfTracePoint::fd(&self) -> core::result::Result<& 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::info(&self) -> 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) @@ -4147,7 +4726,7 @@ impl core::convert::From for aya::programs::tp_btf::BtfTracePointLink pub fn aya::programs::tp_btf::BtfTracePointLink::from(t: T) -> T pub struct aya::programs::tp_btf::BtfTracePointLinkId(_) impl core::cmp::Eq for aya::programs::tp_btf::BtfTracePointLinkId -impl core::cmp::PartialEq for aya::programs::tp_btf::BtfTracePointLinkId +impl core::cmp::PartialEq for aya::programs::tp_btf::BtfTracePointLinkId pub fn aya::programs::tp_btf::BtfTracePointLinkId::eq(&self, other: &aya::programs::tp_btf::BtfTracePointLinkId) -> bool impl core::fmt::Debug for aya::programs::tp_btf::BtfTracePointLinkId pub fn aya::programs::tp_btf::BtfTracePointLinkId::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -4223,11 +4802,11 @@ pub fn aya::programs::trace_point::TracePoint::fd(&self) -> core::result::Result 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::info(&self) -> 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) @@ -4298,7 +4877,7 @@ impl core::convert::From for aya::programs::trace_point::TracePointLink pub fn aya::programs::trace_point::TracePointLink::from(t: T) -> T pub struct aya::programs::trace_point::TracePointLinkId(_) impl core::cmp::Eq for aya::programs::trace_point::TracePointLinkId -impl core::cmp::PartialEq for aya::programs::trace_point::TracePointLinkId +impl core::cmp::PartialEq for aya::programs::trace_point::TracePointLinkId pub fn aya::programs::trace_point::TracePointLinkId::eq(&self, other: &aya::programs::trace_point::TracePointLinkId) -> bool impl core::fmt::Debug for aya::programs::trace_point::TracePointLinkId pub fn aya::programs::trace_point::TracePointLinkId::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -4330,7 +4909,7 @@ pub fn aya::programs::trace_point::TracePointLinkId::from(t: T) -> T pub mod aya::programs::uprobe pub enum aya::programs::uprobe::UProbeError pub aya::programs::uprobe::UProbeError::FileError -pub aya::programs::uprobe::UProbeError::FileError::filename: alloc::string::String +pub aya::programs::uprobe::UProbeError::FileError::filename: std::path::PathBuf pub aya::programs::uprobe::UProbeError::FileError::io_error: std::io::error::Error pub aya::programs::uprobe::UProbeError::InvalidLdSoCache pub aya::programs::uprobe::UProbeError::InvalidLdSoCache::io_error: alloc::sync::Arc @@ -4381,11 +4960,11 @@ pub fn aya::programs::uprobe::UProbe::take_link(&mut self, link_id: aya::program impl aya::programs::uprobe::UProbe 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::info(&self) -> core::result::Result +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) @@ -4456,7 +5035,7 @@ impl core::convert::From for aya::programs::uprobe::UProbeLink pub fn aya::programs::uprobe::UProbeLink::from(t: T) -> T pub struct aya::programs::uprobe::UProbeLinkId(_) impl core::cmp::Eq for aya::programs::uprobe::UProbeLinkId -impl core::cmp::PartialEq for aya::programs::uprobe::UProbeLinkId +impl core::cmp::PartialEq for aya::programs::uprobe::UProbeLinkId pub fn aya::programs::uprobe::UProbeLinkId::eq(&self, other: &aya::programs::uprobe::UProbeLinkId) -> bool impl core::fmt::Debug for aya::programs::uprobe::UProbeLinkId pub fn aya::programs::uprobe::UProbeLinkId::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -4526,18 +5105,17 @@ pub fn aya::programs::xdp::Xdp::attach(&mut self, interface: &str, flags: aya::p pub fn aya::programs::xdp::Xdp::attach_to_if_index(&mut self, if_index: u32, flags: aya::programs::xdp::XdpFlags) -> core::result::Result pub fn aya::programs::xdp::Xdp::attach_to_link(&mut self, link: aya::programs::xdp::XdpLink) -> core::result::Result pub fn aya::programs::xdp::Xdp::detach(&mut self, link_id: aya::programs::xdp::XdpLinkId) -> core::result::Result<(), aya::programs::ProgramError> +pub fn aya::programs::xdp::Xdp::from_pin>(path: P, attach_type: aya_obj::programs::xdp::XdpAttachType) -> core::result::Result 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::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 +pub fn aya::programs::xdp::Xdp::info(&self) -> 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) @@ -4625,25 +5203,25 @@ impl core::iter::traits::collect::IntoIterator for aya::programs::xdp::XdpFlags pub type aya::programs::xdp::XdpFlags::IntoIter = bitflags::iter::Iter pub type aya::programs::xdp::XdpFlags::Item = aya::programs::xdp::XdpFlags pub fn aya::programs::xdp::XdpFlags::into_iter(self) -> Self::IntoIter -impl core::ops::arith::Sub for aya::programs::xdp::XdpFlags +impl core::ops::arith::Sub for aya::programs::xdp::XdpFlags pub type aya::programs::xdp::XdpFlags::Output = aya::programs::xdp::XdpFlags pub fn aya::programs::xdp::XdpFlags::sub(self, other: Self) -> Self -impl core::ops::arith::SubAssign for aya::programs::xdp::XdpFlags +impl core::ops::arith::SubAssign for aya::programs::xdp::XdpFlags pub fn aya::programs::xdp::XdpFlags::sub_assign(&mut self, other: Self) -impl core::ops::bit::BitAnd for aya::programs::xdp::XdpFlags +impl core::ops::bit::BitAnd for aya::programs::xdp::XdpFlags pub type aya::programs::xdp::XdpFlags::Output = aya::programs::xdp::XdpFlags pub fn aya::programs::xdp::XdpFlags::bitand(self, other: Self) -> Self -impl core::ops::bit::BitAndAssign for aya::programs::xdp::XdpFlags +impl core::ops::bit::BitAndAssign for aya::programs::xdp::XdpFlags pub fn aya::programs::xdp::XdpFlags::bitand_assign(&mut self, other: Self) -impl core::ops::bit::BitOr for aya::programs::xdp::XdpFlags +impl core::ops::bit::BitOr for aya::programs::xdp::XdpFlags pub type aya::programs::xdp::XdpFlags::Output = aya::programs::xdp::XdpFlags pub fn aya::programs::xdp::XdpFlags::bitor(self, other: aya::programs::xdp::XdpFlags) -> Self -impl core::ops::bit::BitOrAssign for aya::programs::xdp::XdpFlags +impl core::ops::bit::BitOrAssign for aya::programs::xdp::XdpFlags pub fn aya::programs::xdp::XdpFlags::bitor_assign(&mut self, other: Self) -impl core::ops::bit::BitXor for aya::programs::xdp::XdpFlags +impl core::ops::bit::BitXor for aya::programs::xdp::XdpFlags pub type aya::programs::xdp::XdpFlags::Output = aya::programs::xdp::XdpFlags pub fn aya::programs::xdp::XdpFlags::bitxor(self, other: Self) -> Self -impl core::ops::bit::BitXorAssign for aya::programs::xdp::XdpFlags +impl core::ops::bit::BitXorAssign for aya::programs::xdp::XdpFlags pub fn aya::programs::xdp::XdpFlags::bitxor_assign(&mut self, other: Self) impl core::ops::bit::Not for aya::programs::xdp::XdpFlags pub type aya::programs::xdp::XdpFlags::Output = aya::programs::xdp::XdpFlags @@ -4718,7 +5296,7 @@ impl core::convert::From for aya::programs::xdp::XdpLink pub fn aya::programs::xdp::XdpLink::from(t: T) -> T pub struct aya::programs::xdp::XdpLinkId(_) impl core::cmp::Eq for aya::programs::xdp::XdpLinkId -impl core::cmp::PartialEq for aya::programs::xdp::XdpLinkId +impl core::cmp::PartialEq for aya::programs::xdp::XdpLinkId pub fn aya::programs::xdp::XdpLinkId::eq(&self, other: &aya::programs::xdp::XdpLinkId) -> bool impl core::fmt::Debug for aya::programs::xdp::XdpLinkId pub fn aya::programs::xdp::XdpLinkId::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -4814,7 +5392,7 @@ impl core::convert::From for aya::programs::extension::ExtensionError pub fn aya::programs::extension::ExtensionError::from(t: T) -> T pub enum aya::programs::KProbeError pub aya::programs::KProbeError::FileError -pub aya::programs::KProbeError::FileError::filename: alloc::string::String +pub aya::programs::KProbeError::FileError::filename: std::path::PathBuf pub aya::programs::KProbeError::FileError::io_error: std::io::error::Error impl core::convert::From for aya::programs::ProgramError pub fn aya::programs::ProgramError::from(source: aya::programs::kprobe::KProbeError) -> Self @@ -4985,6 +5563,7 @@ 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::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> +pub fn aya::programs::Program::info(&self) -> core::result::Result 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> @@ -5336,7 +5915,7 @@ pub aya::programs::TcAttachType::Ingress impl core::clone::Clone for aya::programs::tc::TcAttachType pub fn aya::programs::tc::TcAttachType::clone(&self) -> aya::programs::tc::TcAttachType impl core::cmp::Eq for aya::programs::tc::TcAttachType -impl core::cmp::PartialEq for aya::programs::tc::TcAttachType +impl core::cmp::PartialEq for aya::programs::tc::TcAttachType pub fn aya::programs::tc::TcAttachType::eq(&self, other: &aya::programs::tc::TcAttachType) -> bool impl core::fmt::Debug for aya::programs::tc::TcAttachType pub fn aya::programs::tc::TcAttachType::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -5442,7 +6021,7 @@ impl core::convert::From for aya::programs::trace_point::TracePointError pub fn aya::programs::trace_point::TracePointError::from(t: T) -> T pub enum aya::programs::UProbeError pub aya::programs::UProbeError::FileError -pub aya::programs::UProbeError::FileError::filename: alloc::string::String +pub aya::programs::UProbeError::FileError::filename: std::path::PathBuf pub aya::programs::UProbeError::FileError::io_error: std::io::error::Error pub aya::programs::UProbeError::InvalidLdSoCache pub aya::programs::UProbeError::InvalidLdSoCache::io_error: alloc::sync::Arc @@ -5527,11 +6106,11 @@ pub fn aya::programs::tp_btf::BtfTracePoint::fd(&self) -> core::result::Result<& 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::info(&self) -> 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) @@ -5566,7 +6145,7 @@ impl core::convert::From for aya::programs::tp_btf::BtfTracePoint pub fn aya::programs::tp_btf::BtfTracePoint::from(t: T) -> T pub struct aya::programs::CgroupDevice impl aya::programs::cgroup_device::CgroupDevice -pub fn aya::programs::cgroup_device::CgroupDevice::attach(&mut self, cgroup: T) -> core::result::Result +pub fn aya::programs::cgroup_device::CgroupDevice::attach(&mut self, cgroup: T) -> core::result::Result pub fn aya::programs::cgroup_device::CgroupDevice::detach(&mut self, link_id: aya::programs::cgroup_device::CgroupDeviceLinkId) -> core::result::Result<(), aya::programs::ProgramError> 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 @@ -5575,11 +6154,11 @@ pub fn aya::programs::cgroup_device::CgroupDevice::fd(&self) -> core::result::Re 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::info(&self) -> 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) @@ -5614,7 +6193,7 @@ impl core::convert::From for aya::programs::cgroup_device::CgroupDevice pub fn aya::programs::cgroup_device::CgroupDevice::from(t: T) -> T pub struct aya::programs::CgroupSkb impl aya::programs::cgroup_skb::CgroupSkb -pub fn aya::programs::cgroup_skb::CgroupSkb::attach(&mut self, cgroup: T, attach_type: aya::programs::cgroup_skb::CgroupSkbAttachType) -> core::result::Result +pub fn aya::programs::cgroup_skb::CgroupSkb::attach(&mut self, cgroup: T, attach_type: aya::programs::cgroup_skb::CgroupSkbAttachType) -> core::result::Result pub fn aya::programs::cgroup_skb::CgroupSkb::detach(&mut self, link_id: aya::programs::cgroup_skb::CgroupSkbLinkId) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_skb::CgroupSkb::expected_attach_type(&self) -> &core::option::Option pub fn aya::programs::cgroup_skb::CgroupSkb::from_pin>(path: P, expected_attach_type: aya::programs::cgroup_skb::CgroupSkbAttachType) -> core::result::Result @@ -5623,11 +6202,11 @@ pub fn aya::programs::cgroup_skb::CgroupSkb::take_link(&mut self, link_id: aya:: impl aya::programs::cgroup_skb::CgroupSkb 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::info(&self) -> core::result::Result +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) @@ -5662,7 +6241,7 @@ impl core::convert::From for aya::programs::cgroup_skb::CgroupSkb pub fn aya::programs::cgroup_skb::CgroupSkb::from(t: T) -> T pub struct aya::programs::CgroupSock impl aya::programs::cgroup_sock::CgroupSock -pub fn aya::programs::cgroup_sock::CgroupSock::attach(&mut self, cgroup: T) -> core::result::Result +pub fn aya::programs::cgroup_sock::CgroupSock::attach(&mut self, cgroup: T) -> core::result::Result pub fn aya::programs::cgroup_sock::CgroupSock::detach(&mut self, link_id: aya::programs::cgroup_sock::CgroupSockLinkId) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sock::CgroupSock::from_pin>(path: P, attach_type: aya_obj::programs::cgroup_sock::CgroupSockAttachType) -> core::result::Result pub fn aya::programs::cgroup_sock::CgroupSock::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> @@ -5670,11 +6249,11 @@ pub fn aya::programs::cgroup_sock::CgroupSock::take_link(&mut self, link_id: aya impl aya::programs::cgroup_sock::CgroupSock 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::info(&self) -> core::result::Result +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) @@ -5709,7 +6288,7 @@ impl core::convert::From for aya::programs::cgroup_sock::CgroupSock pub fn aya::programs::cgroup_sock::CgroupSock::from(t: T) -> T pub struct aya::programs::CgroupSockAddr impl aya::programs::cgroup_sock_addr::CgroupSockAddr -pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::attach(&mut self, cgroup: T) -> core::result::Result +pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::attach(&mut self, cgroup: T) -> core::result::Result pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::detach(&mut self, link_id: aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::from_pin>(path: P, attach_type: aya_obj::programs::cgroup_sock_addr::CgroupSockAddrAttachType) -> core::result::Result pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> @@ -5717,11 +6296,11 @@ pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::take_link(&mut self, lin impl aya::programs::cgroup_sock_addr::CgroupSockAddr 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::info(&self) -> core::result::Result +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) @@ -5756,7 +6335,7 @@ impl core::convert::From for aya::programs::cgroup_sock_addr::CgroupSockAd pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::from(t: T) -> T pub struct aya::programs::CgroupSockopt impl aya::programs::cgroup_sockopt::CgroupSockopt -pub fn aya::programs::cgroup_sockopt::CgroupSockopt::attach(&mut self, cgroup: T) -> core::result::Result +pub fn aya::programs::cgroup_sockopt::CgroupSockopt::attach(&mut self, cgroup: T) -> core::result::Result pub fn aya::programs::cgroup_sockopt::CgroupSockopt::detach(&mut self, link_id: aya::programs::cgroup_sockopt::CgroupSockoptLinkId) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sockopt::CgroupSockopt::from_pin>(path: P, attach_type: aya_obj::programs::cgroup_sockopt::CgroupSockoptAttachType) -> core::result::Result pub fn aya::programs::cgroup_sockopt::CgroupSockopt::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> @@ -5764,11 +6343,11 @@ pub fn aya::programs::cgroup_sockopt::CgroupSockopt::take_link(&mut self, link_i impl aya::programs::cgroup_sockopt::CgroupSockopt 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::info(&self) -> core::result::Result +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) @@ -5803,7 +6382,7 @@ impl core::convert::From for aya::programs::cgroup_sockopt::CgroupSockopt pub fn aya::programs::cgroup_sockopt::CgroupSockopt::from(t: T) -> T pub struct aya::programs::CgroupSysctl impl aya::programs::cgroup_sysctl::CgroupSysctl -pub fn aya::programs::cgroup_sysctl::CgroupSysctl::attach(&mut self, cgroup: T) -> core::result::Result +pub fn aya::programs::cgroup_sysctl::CgroupSysctl::attach(&mut self, cgroup: T) -> core::result::Result pub fn aya::programs::cgroup_sysctl::CgroupSysctl::detach(&mut self, link_id: aya::programs::cgroup_sysctl::CgroupSysctlLinkId) -> core::result::Result<(), aya::programs::ProgramError> 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 @@ -5812,11 +6391,11 @@ pub fn aya::programs::cgroup_sysctl::CgroupSysctl::fd(&self) -> core::result::Re 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::info(&self) -> 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) @@ -5861,11 +6440,11 @@ pub fn aya::programs::extension::Extension::fd(&self) -> core::result::Result<&a 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::info(&self) -> 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) @@ -5909,11 +6488,11 @@ pub fn aya::programs::fentry::FEntry::fd(&self) -> core::result::Result<&aya::pr 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::info(&self) -> 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) @@ -5957,11 +6536,11 @@ pub fn aya::programs::fexit::FExit::fd(&self) -> core::result::Result<&aya::prog 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::info(&self) -> 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) @@ -5996,7 +6575,7 @@ impl core::convert::From for aya::programs::fexit::FExit pub fn aya::programs::fexit::FExit::from(t: T) -> T pub struct aya::programs::KProbe impl aya::programs::kprobe::KProbe -pub fn aya::programs::kprobe::KProbe::attach(&mut self, fn_name: &str, offset: u64) -> core::result::Result +pub fn aya::programs::kprobe::KProbe::attach>(&mut self, fn_name: T, offset: u64) -> core::result::Result pub fn aya::programs::kprobe::KProbe::detach(&mut self, link_id: aya::programs::kprobe::KProbeLinkId) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::kprobe::KProbe::from_pin>(path: P, kind: aya::programs::ProbeKind) -> core::result::Result pub fn aya::programs::kprobe::KProbe::kind(&self) -> aya::programs::ProbeKind @@ -6005,11 +6584,11 @@ pub fn aya::programs::kprobe::KProbe::take_link(&mut self, link_id: aya::program impl aya::programs::kprobe::KProbe 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::info(&self) -> core::result::Result +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) @@ -6044,21 +6623,21 @@ impl core::convert::From for aya::programs::kprobe::KProbe pub fn aya::programs::kprobe::KProbe::from(t: T) -> T pub struct aya::programs::LircMode2 impl aya::programs::lirc_mode2::LircMode2 -pub fn aya::programs::lirc_mode2::LircMode2::attach(&mut self, lircdev: T) -> core::result::Result +pub fn aya::programs::lirc_mode2::LircMode2::attach(&mut self, lircdev: T) -> core::result::Result pub fn aya::programs::lirc_mode2::LircMode2::detach(&mut self, link_id: aya::programs::lirc_mode2::LircLinkId) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::lirc_mode2::LircMode2::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> -pub fn aya::programs::lirc_mode2::LircMode2::query(target_fd: T) -> core::result::Result, aya::programs::ProgramError> +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::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::info(&self) -> 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) @@ -6102,11 +6681,11 @@ pub fn aya::programs::lsm::Lsm::fd(&self) -> core::result::Result<&aya::programs 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::info(&self) -> 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) @@ -6150,11 +6729,11 @@ pub fn aya::programs::perf_event::PerfEvent::fd(&self) -> core::result::Result<& 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::info(&self) -> 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) @@ -6189,7 +6768,7 @@ 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 aya::programs::ProgramFd -pub fn aya::programs::ProgramFd::try_clone(&self) -> core::result::Result +pub fn aya::programs::ProgramFd::try_clone(&self) -> std::io::error::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 @@ -6219,7 +6798,7 @@ pub struct aya::programs::ProgramInfo(_) impl aya::programs::ProgramInfo 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::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 @@ -6266,11 +6845,11 @@ pub fn aya::programs::RawTracePoint::fd(&self) -> core::result::Result<&aya::pro 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::info(&self) -> 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) @@ -6314,11 +6893,11 @@ pub fn aya::programs::tc::SchedClassifier::take_link(&mut self, link_id: aya::pr impl aya::programs::tc::SchedClassifier 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::info(&self) -> core::result::Result +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) @@ -6353,7 +6932,7 @@ impl core::convert::From for aya::programs::tc::SchedClassifier pub fn aya::programs::tc::SchedClassifier::from(t: T) -> T pub struct aya::programs::SkLookup impl aya::programs::SkLookup -pub fn aya::programs::SkLookup::attach(&mut self, netns: T) -> core::result::Result +pub fn aya::programs::SkLookup::attach(&mut self, netns: T) -> core::result::Result pub fn aya::programs::SkLookup::detach(&mut self, link_id: SkLookupLinkId) -> core::result::Result<(), aya::programs::ProgramError> 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 @@ -6362,11 +6941,11 @@ pub fn aya::programs::SkLookup::fd(&self) -> core::result::Result<&aya::programs 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::info(&self) -> 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) @@ -6401,7 +6980,7 @@ impl core::convert::From for aya::programs::SkLookup pub fn aya::programs::SkLookup::from(t: T) -> T pub struct aya::programs::SkMsg impl aya::programs::SkMsg -pub fn aya::programs::SkMsg::attach(&mut self, map: aya::maps::sock::SockMapFd) -> core::result::Result +pub fn aya::programs::SkMsg::attach(&mut self, map: &aya::maps::sock::SockMapFd) -> core::result::Result pub fn aya::programs::SkMsg::detach(&mut self, link_id: SkMsgLinkId) -> core::result::Result<(), aya::programs::ProgramError> 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 @@ -6410,11 +6989,11 @@ pub fn aya::programs::SkMsg::fd(&self) -> core::result::Result<&aya::programs::P 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::info(&self) -> 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) @@ -6449,7 +7028,7 @@ impl core::convert::From for aya::programs::SkMsg pub fn aya::programs::SkMsg::from(t: T) -> T pub struct aya::programs::SkSkb impl aya::programs::SkSkb -pub fn aya::programs::SkSkb::attach(&mut self, map: aya::maps::sock::SockMapFd) -> core::result::Result +pub fn aya::programs::SkSkb::attach(&mut self, map: &aya::maps::sock::SockMapFd) -> core::result::Result pub fn aya::programs::SkSkb::detach(&mut self, link_id: SkSkbLinkId) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::SkSkb::from_pin>(path: P, kind: aya::programs::SkSkbKind) -> core::result::Result pub fn aya::programs::SkSkb::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> @@ -6457,11 +7036,11 @@ pub fn aya::programs::SkSkb::take_link(&mut self, link_id: SkSkbLinkId) -> core: impl aya::programs::SkSkb 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::info(&self) -> core::result::Result +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) @@ -6496,7 +7075,7 @@ impl core::convert::From for aya::programs::SkSkb pub fn aya::programs::SkSkb::from(t: T) -> T pub struct aya::programs::SockOps impl aya::programs::SockOps -pub fn aya::programs::SockOps::attach(&mut self, cgroup: T) -> core::result::Result +pub fn aya::programs::SockOps::attach(&mut self, cgroup: T) -> core::result::Result pub fn aya::programs::SockOps::detach(&mut self, link_id: SockOpsLinkId) -> core::result::Result<(), aya::programs::ProgramError> 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 @@ -6505,11 +7084,11 @@ pub fn aya::programs::SockOps::fd(&self) -> core::result::Result<&aya::programs: 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::info(&self) -> 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) @@ -6544,7 +7123,7 @@ impl core::convert::From for aya::programs::SockOps pub fn aya::programs::SockOps::from(t: T) -> T pub struct aya::programs::SocketFilter impl aya::programs::SocketFilter -pub fn aya::programs::SocketFilter::attach(&mut self, socket: T) -> core::result::Result +pub fn aya::programs::SocketFilter::attach(&mut self, socket: T) -> core::result::Result pub fn aya::programs::SocketFilter::detach(&mut self, link_id: SocketFilterLinkId) -> core::result::Result<(), aya::programs::ProgramError> 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 @@ -6553,11 +7132,11 @@ pub fn aya::programs::SocketFilter::fd(&self) -> core::result::Result<&aya::prog 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::info(&self) -> 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) @@ -6601,11 +7180,11 @@ pub fn aya::programs::trace_point::TracePoint::fd(&self) -> core::result::Result 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::info(&self) -> 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) @@ -6649,11 +7228,11 @@ pub fn aya::programs::uprobe::UProbe::take_link(&mut self, link_id: aya::program impl aya::programs::uprobe::UProbe 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::info(&self) -> core::result::Result +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) @@ -6692,18 +7271,17 @@ pub fn aya::programs::xdp::Xdp::attach(&mut self, interface: &str, flags: aya::p pub fn aya::programs::xdp::Xdp::attach_to_if_index(&mut self, if_index: u32, flags: aya::programs::xdp::XdpFlags) -> core::result::Result pub fn aya::programs::xdp::Xdp::attach_to_link(&mut self, link: aya::programs::xdp::XdpLink) -> core::result::Result pub fn aya::programs::xdp::Xdp::detach(&mut self, link_id: aya::programs::xdp::XdpLinkId) -> core::result::Result<(), aya::programs::ProgramError> +pub fn aya::programs::xdp::Xdp::from_pin>(path: P, attach_type: aya_obj::programs::xdp::XdpAttachType) -> core::result::Result 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::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 +pub fn aya::programs::xdp::Xdp::info(&self) -> 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) @@ -6791,25 +7369,25 @@ impl core::iter::traits::collect::IntoIterator for aya::programs::xdp::XdpFlags pub type aya::programs::xdp::XdpFlags::IntoIter = bitflags::iter::Iter pub type aya::programs::xdp::XdpFlags::Item = aya::programs::xdp::XdpFlags pub fn aya::programs::xdp::XdpFlags::into_iter(self) -> Self::IntoIter -impl core::ops::arith::Sub for aya::programs::xdp::XdpFlags +impl core::ops::arith::Sub for aya::programs::xdp::XdpFlags pub type aya::programs::xdp::XdpFlags::Output = aya::programs::xdp::XdpFlags pub fn aya::programs::xdp::XdpFlags::sub(self, other: Self) -> Self -impl core::ops::arith::SubAssign for aya::programs::xdp::XdpFlags +impl core::ops::arith::SubAssign for aya::programs::xdp::XdpFlags pub fn aya::programs::xdp::XdpFlags::sub_assign(&mut self, other: Self) -impl core::ops::bit::BitAnd for aya::programs::xdp::XdpFlags +impl core::ops::bit::BitAnd for aya::programs::xdp::XdpFlags pub type aya::programs::xdp::XdpFlags::Output = aya::programs::xdp::XdpFlags pub fn aya::programs::xdp::XdpFlags::bitand(self, other: Self) -> Self -impl core::ops::bit::BitAndAssign for aya::programs::xdp::XdpFlags +impl core::ops::bit::BitAndAssign for aya::programs::xdp::XdpFlags pub fn aya::programs::xdp::XdpFlags::bitand_assign(&mut self, other: Self) -impl core::ops::bit::BitOr for aya::programs::xdp::XdpFlags +impl core::ops::bit::BitOr for aya::programs::xdp::XdpFlags pub type aya::programs::xdp::XdpFlags::Output = aya::programs::xdp::XdpFlags pub fn aya::programs::xdp::XdpFlags::bitor(self, other: aya::programs::xdp::XdpFlags) -> Self -impl core::ops::bit::BitOrAssign for aya::programs::xdp::XdpFlags +impl core::ops::bit::BitOrAssign for aya::programs::xdp::XdpFlags pub fn aya::programs::xdp::XdpFlags::bitor_assign(&mut self, other: Self) -impl core::ops::bit::BitXor for aya::programs::xdp::XdpFlags +impl core::ops::bit::BitXor for aya::programs::xdp::XdpFlags pub type aya::programs::xdp::XdpFlags::Output = aya::programs::xdp::XdpFlags pub fn aya::programs::xdp::XdpFlags::bitxor(self, other: Self) -> Self -impl core::ops::bit::BitXorAssign for aya::programs::xdp::XdpFlags +impl core::ops::bit::BitXorAssign for aya::programs::xdp::XdpFlags pub fn aya::programs::xdp::XdpFlags::bitxor_assign(&mut self, other: Self) impl core::ops::bit::Not for aya::programs::xdp::XdpFlags pub type aya::programs::xdp::XdpFlags::Output = aya::programs::xdp::XdpFlags @@ -6938,14 +7516,15 @@ pub fn aya::programs::loaded_programs() -> impl core::iter::traits::iterator::It pub mod aya::util pub struct aya::util::KernelVersion impl aya::util::KernelVersion +pub fn aya::util::KernelVersion::code(self) -> u32 pub fn aya::util::KernelVersion::current() -> core::result::Result pub fn aya::util::KernelVersion::new(major: u8, minor: u8, patch: u16) -> Self impl core::clone::Clone for aya::util::KernelVersion pub fn aya::util::KernelVersion::clone(&self) -> aya::util::KernelVersion impl core::cmp::Eq for aya::util::KernelVersion -impl core::cmp::PartialEq for aya::util::KernelVersion +impl core::cmp::PartialEq for aya::util::KernelVersion pub fn aya::util::KernelVersion::eq(&self, other: &aya::util::KernelVersion) -> bool -impl core::cmp::PartialOrd for aya::util::KernelVersion +impl core::cmp::PartialOrd for aya::util::KernelVersion pub fn aya::util::KernelVersion::partial_cmp(&self, other: &aya::util::KernelVersion) -> core::option::Option impl core::fmt::Debug for aya::util::KernelVersion pub fn aya::util::KernelVersion::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result @@ -6988,11 +7567,8 @@ pub aya::BpfError::BtfRelocationError(aya_obj::btf::relocation::BtfRelocationErr pub aya::BpfError::FileError pub aya::BpfError::FileError::error: std::io::error::Error pub aya::BpfError::FileError::path: std::path::PathBuf -pub aya::BpfError::InvalidPath -pub aya::BpfError::InvalidPath::error: alloc::string::String pub aya::BpfError::MapError(aya::maps::MapError) pub aya::BpfError::NoBTF -pub aya::BpfError::NoPinPath pub aya::BpfError::ParseError(aya_obj::obj::ParseError) pub aya::BpfError::ProgramError(aya::programs::ProgramError) pub aya::BpfError::RelocationError(aya_obj::relocation::BpfRelocationError) @@ -7041,11 +7617,12 @@ impl core::convert::From for aya::BpfError pub fn aya::BpfError::from(t: T) -> T pub struct aya::Bpf impl aya::Bpf -pub fn aya::Bpf::load(data: &[u8]) -> core::result::Result -pub fn aya::Bpf::load_file>(path: P) -> core::result::Result +pub fn aya::Bpf::load(data: &[u8]) -> core::result::Result +pub fn aya::Bpf::load_file>(path: P) -> core::result::Result pub fn aya::Bpf::map(&self, name: &str) -> core::option::Option<&aya::maps::Map> pub fn aya::Bpf::map_mut(&mut self, name: &str) -> core::option::Option<&mut aya::maps::Map> pub fn aya::Bpf::maps(&self) -> impl core::iter::traits::iterator::Iterator +pub fn aya::Bpf::maps_mut(&mut self) -> impl core::iter::traits::iterator::Iterator pub fn aya::Bpf::program(&self, name: &str) -> core::option::Option<&aya::programs::Program> pub fn aya::Bpf::program_mut(&mut self, name: &str) -> core::option::Option<&mut aya::programs::Program> pub fn aya::Bpf::programs(&self) -> impl core::iter::traits::iterator::Iterator @@ -7082,12 +7659,12 @@ pub fn aya::BpfLoader<'a>::extension(&mut self, name: &'a str) -> &mut aya::BpfL pub fn aya::BpfLoader<'a>::load(&mut self, data: &[u8]) -> core::result::Result pub fn aya::BpfLoader<'a>::load_file>(&mut self, path: P) -> core::result::Result pub fn aya::BpfLoader<'a>::map_pin_path>(&mut self, path: P) -> &mut aya::BpfLoader<'a> -pub fn aya::BpfLoader<'a>::new() -> aya::BpfLoader<'a> +pub fn aya::BpfLoader<'a>::new() -> Self pub fn aya::BpfLoader<'a>::set_global>>(&mut self, name: &'a str, value: T, must_exist: bool) -> &mut aya::BpfLoader<'a> pub fn aya::BpfLoader<'a>::set_max_entries(&mut self, name: &'a str, size: u32) -> &mut aya::BpfLoader<'a> pub fn aya::BpfLoader<'a>::verifier_log_level(&mut self, level: aya::VerifierLogLevel) -> &mut aya::BpfLoader<'a> -impl<'a> core::default::Default for aya::BpfLoader<'a> -pub fn aya::BpfLoader<'a>::default() -> Self +impl core::default::Default for aya::BpfLoader<'_> +pub fn aya::BpfLoader<'_>::default() -> Self impl<'a> core::fmt::Debug for aya::BpfLoader<'a> pub fn aya::BpfLoader<'a>::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl<'a> core::marker::Send for aya::BpfLoader<'a> @@ -7193,25 +7770,25 @@ impl core::iter::traits::collect::IntoIterator for aya::VerifierLogLevel pub type aya::VerifierLogLevel::IntoIter = bitflags::iter::Iter pub type aya::VerifierLogLevel::Item = aya::VerifierLogLevel pub fn aya::VerifierLogLevel::into_iter(self) -> Self::IntoIter -impl core::ops::arith::Sub for aya::VerifierLogLevel +impl core::ops::arith::Sub for aya::VerifierLogLevel pub type aya::VerifierLogLevel::Output = aya::VerifierLogLevel pub fn aya::VerifierLogLevel::sub(self, other: Self) -> Self -impl core::ops::arith::SubAssign for aya::VerifierLogLevel +impl core::ops::arith::SubAssign for aya::VerifierLogLevel pub fn aya::VerifierLogLevel::sub_assign(&mut self, other: Self) -impl core::ops::bit::BitAnd for aya::VerifierLogLevel +impl core::ops::bit::BitAnd for aya::VerifierLogLevel pub type aya::VerifierLogLevel::Output = aya::VerifierLogLevel pub fn aya::VerifierLogLevel::bitand(self, other: Self) -> Self -impl core::ops::bit::BitAndAssign for aya::VerifierLogLevel +impl core::ops::bit::BitAndAssign for aya::VerifierLogLevel pub fn aya::VerifierLogLevel::bitand_assign(&mut self, other: Self) -impl core::ops::bit::BitOr for aya::VerifierLogLevel +impl core::ops::bit::BitOr for aya::VerifierLogLevel pub type aya::VerifierLogLevel::Output = aya::VerifierLogLevel pub fn aya::VerifierLogLevel::bitor(self, other: aya::VerifierLogLevel) -> Self -impl core::ops::bit::BitOrAssign for aya::VerifierLogLevel +impl core::ops::bit::BitOrAssign for aya::VerifierLogLevel pub fn aya::VerifierLogLevel::bitor_assign(&mut self, other: Self) -impl core::ops::bit::BitXor for aya::VerifierLogLevel +impl core::ops::bit::BitXor for aya::VerifierLogLevel pub type aya::VerifierLogLevel::Output = aya::VerifierLogLevel pub fn aya::VerifierLogLevel::bitxor(self, other: Self) -> Self -impl core::ops::bit::BitXorAssign for aya::VerifierLogLevel +impl core::ops::bit::BitXorAssign for aya::VerifierLogLevel pub fn aya::VerifierLogLevel::bitxor_assign(&mut self, other: Self) impl core::ops::bit::Not for aya::VerifierLogLevel pub type aya::VerifierLogLevel::Output = aya::VerifierLogLevel @@ -7247,6 +7824,8 @@ pub fn aya::VerifierLogLevel::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::VerifierLogLevel pub fn aya::VerifierLogLevel::from(t: T) -> T pub unsafe trait aya::Pod: core::marker::Copy + 'static +impl aya::Pod for aya_obj::generated::linux_bindings_x86_64::bpf_cpumap_val +impl aya::Pod for aya_obj::generated::linux_bindings_x86_64::bpf_devmap_val impl aya::Pod for i128 impl aya::Pod for i16 impl aya::Pod for i32 diff --git a/xtask/src/codegen/aya.rs b/xtask/src/codegen/aya.rs index 950b862c..7556cab6 100644 --- a/xtask/src/codegen/aya.rs +++ b/xtask/src/codegen/aya.rs @@ -1,6 +1,6 @@ -use anyhow::anyhow; use std::path::{Path, PathBuf}; +use anyhow::anyhow; use aya_tool::{bindgen, write_to_file}; use crate::codegen::{Architecture, SysrootOptions}; diff --git a/xtask/src/codegen/aya_bpf_bindings.rs b/xtask/src/codegen/aya_bpf_bindings.rs index d594a5fe..8e417445 100644 --- a/xtask/src/codegen/aya_bpf_bindings.rs +++ b/xtask/src/codegen/aya_bpf_bindings.rs @@ -1,9 +1,9 @@ -use anyhow::anyhow; -use proc_macro2::TokenStream; -use quote::ToTokens; use std::path::{Path, PathBuf}; +use anyhow::anyhow; use aya_tool::{bindgen, write_to_file_fmt}; +use proc_macro2::TokenStream; +use quote::ToTokens; use syn::{parse_str, Item}; use crate::codegen::{ diff --git a/xtask/src/docs.rs b/xtask/src/docs.rs index 0fb13d35..4acc6df1 100644 --- a/xtask/src/docs.rs +++ b/xtask/src/docs.rs @@ -1,7 +1,8 @@ +use std::{ffi::OsString, fs, io::Write as _, process::Command}; + use anyhow::{Context as _, Result}; use cargo_metadata::Metadata; use indoc::{indoc, writedoc}; -use std::{ffi::OsString, fs, io::Write as _, process::Command}; use xtask::exec; pub fn docs(metadata: Metadata) -> Result<()> { @@ -67,10 +68,10 @@ pub fn docs(metadata: Metadata) -> Result<()> { fs::write( site.join("robots.txt"), - indoc! {r#" + indoc! {r" User-Agent:* Disallow: / - "#}, + "}, ) .context("can't write robots.txt")?; diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index 9e5c8737..47c6c56c 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs @@ -1,10 +1,6 @@ +use std::process::Command; + use anyhow::{bail, Context as _, Result}; -use std::{ - fs, - path::{Path, PathBuf}, - process::Command, -}; -use which::which; pub const AYA_BUILD_INTEGRATION_BPF: &str = "AYA_BUILD_INTEGRATION_BPF"; pub const LIBBPF_DIR: &str = "xtask/libbpf"; @@ -19,25 +15,29 @@ pub fn exec(cmd: &mut Command) -> Result<()> { Ok(()) } -// Create a symlink in the out directory to work around the fact that cargo ignores anything -// in `$CARGO_HOME`, which is also where `cargo install` likes to place binaries. Cargo will -// stat through the symlink and discover that the binary has changed. -// -// This was introduced in https://github.com/rust-lang/cargo/commit/99f841c. -// -// TODO(https://github.com/rust-lang/cargo/pull/12369): Remove this when the fix is available. -pub fn create_symlink_to_binary(out_dir: &Path, binary_name: &str) -> Result { - let binary = which(binary_name).unwrap(); - let symlink = out_dir.join(binary_name); - match fs::remove_file(&symlink) { - Ok(()) => {} - Err(err) => { - if err.kind() != std::io::ErrorKind::NotFound { - return Err(err).context(format!("failed to remove symlink {}", symlink.display())); +#[derive(Debug)] +pub struct Errors(Vec); + +impl Errors { + pub fn new(errors: Vec) -> Self { + Self(errors) + } +} + +impl std::fmt::Display for Errors +where + E: std::fmt::Debug, +{ + 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(()) } - std::os::unix::fs::symlink(binary, &symlink) - .with_context(|| format!("failed to create symlink {}", symlink.display()))?; - Ok(symlink) } + +impl std::error::Error for Errors where E: std::fmt::Debug {} diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 01105c00..9060f16e 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -3,10 +3,11 @@ mod docs; mod public_api; mod run; +use std::process::Command; + use anyhow::{Context as _, Result}; use cargo_metadata::{Metadata, MetadataCommand}; use clap::Parser; -use std::process::Command; use xtask::{exec, LIBBPF_DIR}; #[derive(Parser)] diff --git a/xtask/src/public_api.rs b/xtask/src/public_api.rs index b5b58f07..0ca83f65 100644 --- a/xtask/src/public_api.rs +++ b/xtask/src/public_api.rs @@ -10,6 +10,7 @@ use cargo_metadata::{Metadata, Package}; use clap::Parser; use dialoguer::{theme::ColorfulTheme, Confirm}; use diff::{lines, Result as Diff}; +use xtask::Errors; #[derive(Debug, Parser)] pub struct Options { @@ -37,34 +38,36 @@ pub fn public_api(options: Options, metadata: Metadata) -> Result<()> { workspace_root, packages, .. - } = &metadata; + } = metadata; - let errors = packages - .iter() - .fold(String::new(), |mut buf, Package { name, publish, .. }| { - if !matches!(publish, Some(publish) if publish.is_empty()) { - match check_package_api(name, toolchain, bless, workspace_root.as_std_path()) { - Ok(diff) => { - if !diff.is_empty() { - writeln!( - &mut buf, - "{name} public API changed; re-run with --bless. diff:\n{diff}" - ) - .unwrap(); - } - } - Err(err) => { - writeln!(&mut buf, "{name} failed to check public API: {err}").unwrap(); - } + let errors: Vec<_> = packages + .into_iter() + .map(|Package { name, publish, .. }| { + if matches!(publish, Some(publish) if publish.is_empty()) { + Ok(()) + } else { + let diff = check_package_api(&name, toolchain, bless, workspace_root.as_std_path()) + .with_context(|| format!("{name} failed to check public API"))?; + if diff.is_empty() { + Ok(()) + } else { + Err(anyhow::anyhow!( + "{name} public API changed; re-run with --bless. diff:\n{diff}" + )) } } - buf - }); + }) + .filter_map(|result| match result { + Ok(()) => None, + Err(err) => Some(err), + }) + .collect(); - if !errors.is_empty() { - bail!("public API errors:\n{errors}") + if errors.is_empty() { + Ok(()) + } else { + Err(Errors::new(errors).into()) } - Ok(()) } fn check_package_api( diff --git a/xtask/src/run.rs b/xtask/src/run.rs index 15ee7035..5625e037 100644 --- a/xtask/src/run.rs +++ b/xtask/src/run.rs @@ -2,7 +2,7 @@ use std::{ env::consts::{ARCH, OS}, ffi::OsString, fmt::Write as _, - fs::{copy, create_dir_all, metadata, File}, + fs::{copy, create_dir_all, OpenOptions}, io::{BufRead as _, BufReader, ErrorKind, Write as _}, path::{Path, PathBuf}, process::{Child, ChildStdin, Command, Output, Stdio}, @@ -13,7 +13,7 @@ use std::{ use anyhow::{anyhow, bail, Context as _, Result}; use cargo_metadata::{Artifact, CompilerMessage, Message, Target}; use clap::Parser; -use xtask::{exec, AYA_BUILD_INTEGRATION_BPF}; +use xtask::{exec, Errors, AYA_BUILD_INTEGRATION_BPF}; #[derive(Parser)] enum Environment { @@ -104,24 +104,6 @@ where Ok(executables) } -#[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 { @@ -302,9 +284,13 @@ pub fn run(opts: Options) -> Result<()> { 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 initrd_image_file = OpenOptions::new() + .create_new(true) + .write(true) + .open(&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 @@ -363,27 +349,27 @@ pub fn run(opts: Options) -> Result<()> { 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() { + "linux" => { + const KVM: &str = "/dev/kvm"; + match OpenOptions::new().read(true).write(true).open(KVM) { + Ok(_file) => { qemu.args(["-accel", "kvm"]); } + Err(error) => match error.kind() { + ErrorKind::NotFound | ErrorKind::PermissionDenied => {} + _kind => { + return Err(error) + .with_context(|| format!("failed to open {KVM}")); + } + }, } - Err(error) => { - if error.kind() != ErrorKind::NotFound { - Err(error).context("failed to check existence of /dev/kvm")?; - } - } - }, + } "macos" => { qemu.args(["-accel", "hvf"]); } @@ -476,20 +462,30 @@ pub fn run(opts: Options) -> Result<()> { 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(()) - } + const TERMINATE_AFTER_COUNT: &[(&str, usize)] = + &[("end Kernel panic", 0), ("watchdog: BUG: soft lockup", 1)]; + let mut counts = [0; TERMINATE_AFTER_COUNT.len()]; + + let mut terminate_if_kernel_hang = + move |line: &str, stdin: &Arc>| -> anyhow::Result<()> { + if let Some(i) = TERMINATE_AFTER_COUNT + .iter() + .position(|(marker, _)| line.contains(marker)) + { + counts[i] += 1; + + let (marker, max) = TERMINATE_AFTER_COUNT[i]; + if counts[i] > max { + println!("{marker} detected > {max} times; 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(); @@ -498,8 +494,7 @@ pub fn run(opts: Options) -> Result<()> { 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)?; + terminate_if_kernel_hang(&line, &stdin)?; } anyhow::Ok(()) }) @@ -510,8 +505,7 @@ pub fn run(opts: Options) -> Result<()> { 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)?; + terminate_if_kernel_hang(&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: ") { @@ -547,7 +541,7 @@ pub fn run(opts: Options) -> Result<()> { if errors.is_empty() { Ok(()) } else { - Err(Errors(errors).into()) + Err(Errors::new(errors).into()) } } }