Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,15 @@ rust-version = "1.85.0"
anyhow = { version = "1", default-features = false }
assert_matches = { version = "1.5.0", default-features = false }
async-io = { version = "2.0", default-features = false }
async-global-executor = { version = "3.1.0", default-features = false }
base64 = { version = "0.22.1", default-features = false }
bindgen = { version = "0.71", default-features = false }
bitflags = { version = "2.2.1", default-features = false }
bytes = { version = "1", default-features = false }
cargo_metadata = { version = "0.19.0", default-features = false }
clap = { version = "4", default-features = false }
const-assert = { version = "1.0.1", default-features = false }
compio = { version = "0.14.0", default-features = false }
dialoguer = { version = "0.11", default-features = false }
diff = { version = "0.1.13", default-features = false }
env_logger = { version = "0.11", default-features = false }
Expand Down
12 changes: 10 additions & 2 deletions aya-log/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,23 @@ rust-version.workspace = true
[lints]
workspace = true

[features]
async_tokio = ["aya/async_tokio", "dep:tokio"]
async_std = ["aya/async_std", "async-global-executor/async-io"]
async_compio = ["aya/async_compio", "dep:compio"]

[dependencies]
aya = { path = "../aya", version = "^0.13.1", features = ["async_tokio"] }
aya = { path = "../aya", version = "^0.13.1" }
aya-log-common = { path = "../aya-log-common", version = "^0.1.15", default-features = false }
bytes = { workspace = true }
log = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["rt"] }
tokio = { workspace = true, features = ["rt"], optional = true }
async-global-executor = { workspace = true, optional = true }
compio = { workspace = true, optional = true }

[dev-dependencies]
compio = { workspace = true, features = ["io-uring"] }
env_logger = { workspace = true }
testing_logger = { workspace = true }

Expand Down
37 changes: 35 additions & 2 deletions aya-log/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,23 @@ use std::{

const MAP_NAME: &str = "AYA_LOGS";

// check async feature mutual exclusivity
#[cfg(all(feature = "async_tokio", feature = "async_std"))]
compile_error!("Cannot enable both async_tokio and async_std features at the same time");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a very good change, thanks for doing that! I agree that async* features should be mutually exclusive.

The CI jobs are red, because they use cargo hack with --feature-powerset flag, which tries out all combinations of features. To make it work, you will need to add the

--mutually-exclusive-features async_compio,async_tokio,async_std

flag in the following places:

- name: Run miri
run: |
set -euxo pipefail
cargo +nightly hack miri test --all-targets --feature-powerset \
--exclude aya-ebpf \
--exclude aya-ebpf-bindings \
--exclude aya-log-ebpf \
--exclude integration-ebpf \
--exclude integration-test \
--workspace

- name: Build
run: |
set -euxo pipefail
cargo hack build --all-targets --feature-powerset \
--exclude aya-ebpf \
--exclude aya-ebpf-bindings \
--exclude aya-log-ebpf \
--exclude integration-ebpf \
--exclude xtask \
--workspace

- name: Test
env:
RUST_BACKTRACE: full
run: |
set -euxo pipefail
cargo hack test --all-targets --feature-powerset \
--exclude aya-ebpf \
--exclude aya-ebpf-bindings \
--exclude aya-log-ebpf \
--exclude integration-ebpf \
--exclude integration-test \
--exclude xtask \
--workspace

- name: Doctests
env:
RUST_BACKTRACE: full
run: |
set -euxo pipefail
cargo hack test --doc --feature-powerset \
--exclude aya-ebpf \
--exclude aya-ebpf-bindings \
--exclude aya-log-ebpf \
--exclude init \
--exclude integration-ebpf \
--exclude integration-test \
--exclude xtask \
--workspace

- name: Build
env:
CARGO_CFG_BPF_TARGET_ARCH: ${{ matrix.bpf_target_arch }}
run: |
set -euxo pipefail
cargo +nightly hack build \
--target ${{ matrix.target }} \
-Z build-std=core \
--package aya-ebpf \
--package aya-log-ebpf \
--feature-powerset

- name: Test
env:
CARGO_CFG_BPF_TARGET_ARCH: ${{ matrix.bpf_target_arch }}
RUST_BACKTRACE: full
run: |
set -euxo pipefail
cargo hack test \
--doc \
--package aya-ebpf \
--package aya-log-ebpf \
--feature-powerset


#[cfg(all(feature = "async_tokio", feature = "async_compio"))]
compile_error!("Cannot enable both async_tokio and async_compio features at the same time");

#[cfg(all(feature = "async_std", feature = "async_compio"))]
compile_error!("Cannot enable both async_std and async_compio features at the same time");

#[cfg(not(any(
feature = "async_tokio",
feature = "async_std",
feature = "async_compio"
)))]
compile_error!("Must enable at least one async feature: async_tokio, async_std, or async_compio");

use aya::{
Ebpf, Pod,
maps::{
Expand Down Expand Up @@ -165,7 +182,8 @@ impl EbpfLogger {
let mut buf = logs.open(cpu_id, None)?;

let log = logger.clone();
tokio::spawn(async move {

let fut = async move {
let mut buffers = vec![BytesMut::with_capacity(LOG_BUF_CAPACITY); 10];

loop {
Expand All @@ -175,7 +193,22 @@ impl EbpfLogger {
log_buf(buf.as_ref(), &*log).unwrap();
}
}
});
};

#[cfg(feature = "async_tokio")]
{
tokio::spawn(fut);
}

#[cfg(feature = "async_std")]
{
async_global_executor::spawn(fut).detach();
}

#[cfg(feature = "async_compio")]
{
compio::runtime::spawn(fut).detach();
}
}
Ok(())
}
Expand Down
2 changes: 2 additions & 0 deletions aya/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ async-io = { workspace = true, optional = true }
aya-obj = { path = "../aya-obj", version = "^0.2.1", features = ["std"] }
bitflags = { workspace = true }
bytes = { workspace = true }
compio = { workspace = true, optional = true, features = ["runtime"] }
hashbrown = { workspace = true }
libc = { workspace = true }
log = { workspace = true }
Expand All @@ -36,6 +37,7 @@ tempfile = { workspace = true }
[features]
async_std = ["dep:async-io"]
async_tokio = ["tokio/net"]
async_compio = ["dep:compio"]
default = []

[package.metadata.docs.rs]
Expand Down
9 changes: 7 additions & 2 deletions aya/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@
//! * Support for function call relocation and global data maps, which
//! allows eBPF programs to make **function calls** and use **global variables
//! and initializers**.
//! * **Async support** with both [tokio] and [async-std].
//! * **Async support** with [tokio], [async-std] and [compio].
//! * Easy to deploy and fast to build: aya doesn't require a kernel build or
//! compiled headers, and not even a C toolchain; a release build completes in a matter
//! of seconds.
//!
//! [tokio]: https://docs.rs/tokio
//! [async-std]: https://docs.rs/async-std
//! [compio]: https://docs.rs/compio

#![doc(
html_logo_url = "https://aya-rs.dev/assets/images/crabby.svg",
Expand Down Expand Up @@ -68,7 +69,11 @@
//unused_results,
)]
#![cfg_attr(
all(feature = "async_tokio", feature = "async_std"),
all(
feature = "async_tokio",
feature = "async_std",
feature = "async_compio"
),
expect(unused_crate_dependencies)
)]

Expand Down
19 changes: 15 additions & 4 deletions aya/src/maps/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,19 @@ pub use bloom_filter::BloomFilter;
pub use hash_map::{HashMap, PerCpuHashMap};
pub use info::{MapInfo, MapType, loaded_maps};
pub use lpm_trie::LpmTrie;
#[cfg(any(feature = "async_tokio", feature = "async_std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "async_tokio", feature = "async_std"))))]
#[cfg(any(
feature = "async_tokio",
feature = "async_std",
feature = "async_compio"
))]
#[cfg_attr(
docsrs,
doc(cfg(any(
feature = "async_tokio",
feature = "async_std",
feature = "async_compio"
)))
)]
pub use perf::AsyncPerfEventArray;
pub use perf::PerfEventArray;
pub use queue::Queue;
Expand Down Expand Up @@ -487,8 +498,8 @@ impl_try_from_map!(() {
SockMap,
StackTraceMap,
XskMap,
#[cfg(any(feature = "async_tokio", feature = "async_std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "async_tokio", feature = "async_std"))))]
#[cfg(any(feature = "async_tokio", feature = "async_std", feature = "async_compio"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "async_tokio", feature = "async_std", feature = "async_compio"))))]
AsyncPerfEventArray from PerfEventArray,
});

Expand Down
34 changes: 30 additions & 4 deletions aya/src/maps/perf/async_perf_event_array.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
// check async feature mutual exclusivity
#[cfg(all(feature = "async_tokio", feature = "async_std"))]
compile_error!("Cannot enable both async_tokio and async_std features at the same time");

#[cfg(all(feature = "async_tokio", feature = "async_compio"))]
compile_error!("Cannot enable both async_tokio and async_compio features at the same time");

#[cfg(all(feature = "async_std", feature = "async_compio"))]
compile_error!("Cannot enable both async_std and async_compio features at the same time");

#[cfg(feature = "async_compio")]
use std::os::fd::AsRawFd as _;
use std::{
borrow::{Borrow, BorrowMut},
path::Path,
Expand All @@ -7,9 +19,17 @@ use std::{
//
// We should eventually split async functionality out into separate crates "aya-async-tokio" and
// "async-async-std". Presently we arbitrarily choose tokio over async-std when both are requested.
#[cfg(all(not(feature = "async_tokio"), feature = "async_std"))]
#[cfg(feature = "async_std")]
use async_io::Async;
use bytes::BytesMut;
#[cfg(feature = "async_compio")]
use compio::{
driver::{
SharedFd,
op::{Interest, PollOnce},
},
runtime,
};
#[cfg(feature = "async_tokio")]
use tokio::io::unix::AsyncFd;

Expand Down Expand Up @@ -103,7 +123,7 @@ impl<T: BorrowMut<MapData>> AsyncPerfEventArray<T> {
let buf = perf_map.open(index, page_count)?;
#[cfg(feature = "async_tokio")]
let buf = AsyncFd::new(buf)?;
#[cfg(all(not(feature = "async_tokio"), feature = "async_std"))]
#[cfg(feature = "async_std")]
let buf = Async::new(buf)?;
Ok(AsyncPerfEventArrayBuffer { buf })
}
Expand Down Expand Up @@ -139,7 +159,7 @@ pub struct AsyncPerfEventArrayBuffer<T: BorrowMut<MapData>> {
#[cfg(feature = "async_tokio")]
buf: AsyncFd<PerfEventArrayBuffer<T>>,

#[cfg(all(not(feature = "async_tokio"), feature = "async_std"))]
#[cfg(feature = "async_std")]
buf: Async<PerfEventArrayBuffer<T>>,
}

Expand All @@ -164,14 +184,20 @@ impl<T: BorrowMut<MapData>> AsyncPerfEventArrayBuffer<T> {
#[cfg(feature = "async_tokio")]
let buf = guard.get_inner_mut();

#[cfg(all(not(feature = "async_tokio"), feature = "async_std"))]
#[cfg(feature = "async_std")]
let buf = {
if !buf.get_ref().readable() {
buf.readable().await?;
}
unsafe { buf.get_mut() }
};

#[cfg(feature = "async_compio")]
{
let poll_once = PollOnce::new(SharedFd::new(buf.as_raw_fd()), Interest::Readable);
runtime::submit(poll_once).await.0?;
}

let events = buf.read_events(buffers)?;
const EMPTY: Events = Events { read: 0, lost: 0 };
if events != EMPTY {
Expand Down
30 changes: 26 additions & 4 deletions aya/src/maps/perf/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,36 @@
//! `perf` API.
//!
//! See [`PerfEventArray`] and [`AsyncPerfEventArray`].
#[cfg(any(feature = "async_tokio", feature = "async_std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "async_tokio", feature = "async_std"))))]
#[cfg(any(
feature = "async_tokio",
feature = "async_std",
feature = "async_compio"
))]
#[cfg_attr(
docsrs,
doc(cfg(any(
feature = "async_tokio",
feature = "async_std",
feature = "async_compio"
)))
)]
mod async_perf_event_array;
mod perf_buffer;
mod perf_event_array;

#[cfg(any(feature = "async_tokio", feature = "async_std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "async_tokio", feature = "async_std"))))]
#[cfg(any(
feature = "async_tokio",
feature = "async_std",
feature = "async_compio"
))]
#[cfg_attr(
docsrs,
doc(cfg(any(
feature = "async_tokio",
feature = "async_std",
feature = "async_compio"
)))
)]
pub use async_perf_event_array::*;
pub use perf_buffer::*;
pub use perf_event_array::*;
Loading