aya/
lib.rs

1//! [![](https://aya-rs.dev/assets/images/aya_logo_docs.svg)](https://aya-rs.dev)
2//!
3//! A library to work with eBPF programs.
4//!
5//! eBPF is a technology that allows running user-supplied programs inside the
6//! Linux kernel. For more info see
7//! [https://ebpf.io/what-is-ebpf](https://ebpf.io/what-is-ebpf).
8//!
9//! Aya is an eBPF library built with a focus on operability and developer experience. It does not
10//! rely on [libbpf](https://github.com/libbpf/libbpf) nor [bcc](https://github.com/iovisor/bcc) -
11//! it's built from the ground up purely in Rust, using only the [libc](https://crates.io/libc)
12//! crate to execute syscalls. With BTF support and when linked with musl, it offers a true
13//! [compile once, run everywhere
14//! solution](https://facebookmicrosites.github.io/bpf/blog/2020/02/19/bpf-portability-and-co-re.html),
15//! where a single self-contained binary can be deployed on many linux distributions
16//! and kernel versions.
17//!
18//! Some of the major features provided include:
19//!
20//! * Support for the **BPF Type Format** (BTF), which is transparently enabled when
21//!   supported by the target kernel. This allows eBPF programs compiled against
22//!   one kernel version to run on different kernel versions without the need to
23//!   recompile.
24//! * Support for function call relocation and global data maps, which
25//!   allows eBPF programs to make **function calls** and use **global variables
26//!   and initializers**.
27//! * **Async support** with both [tokio] and [async-std].
28//! * Easy to deploy and fast to build: aya doesn't require a kernel build or
29//!   compiled headers, and not even a C toolchain; a release build completes in a matter
30//!   of seconds.
31//!
32//! [tokio]: https://docs.rs/tokio
33//! [async-std]: https://docs.rs/async-std
34
35#![doc(
36    html_logo_url = "https://aya-rs.dev/assets/images/crabby.svg",
37    html_favicon_url = "https://aya-rs.dev/assets/images/crabby.svg"
38)]
39#![cfg_attr(docsrs, feature(doc_cfg))]
40#![deny(
41    clippy::all,
42    clippy::use_self,
43    absolute_paths_not_starting_with_crate,
44    deprecated_in_future,
45    elided_lifetimes_in_paths,
46    explicit_outlives_requirements,
47    ffi_unwind_calls,
48    keyword_idents,
49    //let_underscore_drop,
50    macro_use_extern_crate,
51    meta_variable_misuse,
52    missing_abi,
53    //missing_copy_implementations,
54    missing_docs,
55    non_ascii_idents,
56    noop_method_call,
57    rust_2021_incompatible_closure_captures,
58    rust_2021_incompatible_or_patterns,
59    rust_2021_prefixes_incompatible_syntax,
60    rust_2021_prelude_collisions,
61    single_use_lifetimes,
62    trivial_numeric_casts,
63    unreachable_pub,
64    //unsafe_op_in_unsafe_fn,
65    unstable_features,
66    unused_crate_dependencies,
67    unused_extern_crates,
68    unused_import_braces,
69    unused_lifetimes,
70    unused_macro_rules,
71    //unused_qualifications, https://github.com/rust-lang/rust/commit/9ccc7b7 added size_of to the prelude, but we need to continue to qualify it so that we build on older compilers.
72    //unused_results,
73)]
74#![allow(clippy::missing_safety_doc, clippy::len_without_is_empty)]
75#![cfg_attr(
76    all(feature = "async_tokio", feature = "async_std"),
77    allow(unused_crate_dependencies)
78)]
79
80mod bpf;
81pub mod maps;
82pub mod pin;
83pub mod programs;
84pub mod sys;
85pub mod util;
86
87use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd};
88
89use aya_obj as obj;
90use aya_obj::generated;
91pub use bpf::*;
92pub use obj::btf::{Btf, BtfError};
93pub use object::Endianness;
94#[doc(hidden)]
95pub use sys::netlink_set_link_up;
96
97// See https://github.com/rust-lang/rust/pull/124210; this structure exists to avoid crashing the
98// process when we try to close a fake file descriptor.
99#[derive(Debug)]
100struct MockableFd {
101    #[cfg(not(test))]
102    fd: OwnedFd,
103    #[cfg(test)]
104    fd: Option<OwnedFd>,
105}
106
107impl MockableFd {
108    #[cfg(test)]
109    const fn mock_signed_fd() -> i32 {
110        1337
111    }
112
113    #[cfg(test)]
114    const fn mock_unsigned_fd() -> u32 {
115        1337
116    }
117
118    #[cfg(not(test))]
119    fn from_fd(fd: OwnedFd) -> Self {
120        Self { fd }
121    }
122
123    #[cfg(test)]
124    fn from_fd(fd: OwnedFd) -> Self {
125        let fd = Some(fd);
126        Self { fd }
127    }
128
129    #[cfg(not(test))]
130    fn inner(&self) -> &OwnedFd {
131        let Self { fd } = self;
132        fd
133    }
134
135    #[cfg(test)]
136    fn inner(&self) -> &OwnedFd {
137        let Self { fd } = self;
138        fd.as_ref().unwrap()
139    }
140
141    #[cfg(not(test))]
142    fn into_inner(self) -> OwnedFd {
143        self.fd
144    }
145
146    #[cfg(test)]
147    fn into_inner(mut self) -> OwnedFd {
148        self.fd.take().unwrap()
149    }
150
151    fn try_clone(&self) -> std::io::Result<Self> {
152        let fd = self.inner();
153        let fd = fd.try_clone()?;
154        Ok(Self::from_fd(fd))
155    }
156}
157
158impl<T> From<T> for MockableFd
159where
160    OwnedFd: From<T>,
161{
162    fn from(value: T) -> Self {
163        let fd = OwnedFd::from(value);
164        Self::from_fd(fd)
165    }
166}
167
168impl AsFd for MockableFd {
169    fn as_fd(&self) -> BorrowedFd<'_> {
170        self.inner().as_fd()
171    }
172}
173
174impl AsRawFd for MockableFd {
175    fn as_raw_fd(&self) -> RawFd {
176        self.inner().as_raw_fd()
177    }
178}
179
180impl FromRawFd for MockableFd {
181    unsafe fn from_raw_fd(fd: RawFd) -> Self {
182        let fd = OwnedFd::from_raw_fd(fd);
183        Self::from_fd(fd)
184    }
185}
186
187#[cfg(test)]
188impl Drop for MockableFd {
189    fn drop(&mut self) {
190        use std::os::fd::AsRawFd as _;
191
192        let Self { fd } = self;
193        let fd = fd.take().unwrap();
194        if fd.as_raw_fd() < Self::mock_signed_fd() {
195            std::mem::drop(fd)
196        } else {
197            std::mem::forget(fd)
198        }
199    }
200}