Skip to content

Commit 64a2b2a

Browse files
committed
aya-{common,ebpf}: Add spin lock support
Add a new `aya-common` crate with a `SpinLock` struct, that wraps `bpf_spin_lock` and allows to use it in BPF maps. Add an extension trait `EbpfSpinLock` that provides a `lock` method, which is a wrapper over `bpf_spin_lock` helper. It returns a `SpinLockGuard` that calls `bpf_spin_unlock` helper once dropped. Test that functionality with a simple XDP counter program.
1 parent c42157f commit 64a2b2a

File tree

19 files changed

+244
-0
lines changed

19 files changed

+244
-0
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ jobs:
7777
run: |
7878
set -euxo pipefail
7979
cargo +nightly hack miri test --all-targets --feature-powerset \
80+
--exclude aya-common \
8081
--exclude aya-ebpf \
8182
--exclude aya-ebpf-bindings \
8283
--exclude aya-log-ebpf \
@@ -129,6 +130,7 @@ jobs:
129130
run: |
130131
set -euxo pipefail
131132
cargo hack build --all-targets --feature-powerset \
133+
--exclude aya-common \
132134
--exclude aya-ebpf \
133135
--exclude aya-ebpf-bindings \
134136
--exclude aya-log-ebpf \
@@ -142,6 +144,7 @@ jobs:
142144
run: |
143145
set -euxo pipefail
144146
cargo hack test --all-targets \
147+
--exclude aya-common \
145148
--exclude aya-ebpf \
146149
--exclude aya-ebpf-bindings \
147150
--exclude aya-log-ebpf \
@@ -155,6 +158,7 @@ jobs:
155158
run: |
156159
set -euxo pipefail
157160
cargo hack test --doc \
161+
--exclude aya-common \
158162
--exclude aya-ebpf \
159163
--exclude aya-ebpf-bindings \
160164
--exclude aya-log-ebpf \

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
members = [
33
"aya",
44
"aya-build",
5+
"aya-common",
56
"aya-log",
67
"aya-log-common",
78
"aya-log-parser",

aya-common/Cargo.toml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[package]
2+
description = "Library shared across eBPF and user-space"
3+
documentation = "https://docs.rs/aya-common"
4+
keywords = ["bpf", "ebpf", "common"]
5+
name = "aya-common"
6+
version = "0.1.0"
7+
8+
authors.workspace = true
9+
edition.workspace = true
10+
homepage.workspace = true
11+
license.workspace = true
12+
repository.workspace = true
13+
rust-version.workspace = true
14+
15+
[lints]
16+
workspace = true
17+
18+
[dependencies]
19+
aya-ebpf-bindings = { version = "^0.1.2", path = "../ebpf/aya-ebpf-bindings" }
20+
21+
[features]
22+
user = ["aya-ebpf-bindings/user"]

aya-common/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#![cfg_attr(
2+
target_arch = "bpf",
3+
expect(unused_crate_dependencies, reason = "compiler_builtins")
4+
)]
5+
#![no_std]
6+
7+
mod spin_lock;
8+
9+
pub use spin_lock::SpinLock;

aya-common/src/spin_lock.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/// A spin lock that can be used to protect shared data in eBPF maps
2+
pub type SpinLock = aya_ebpf_bindings::bindings::bpf_spin_lock;

ebpf/aya-ebpf-bindings/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ repository.workspace = true
1313
workspace = true
1414

1515
[dependencies]
16+
aya = { path = "../../aya", version = "^0.13.1", optional = true }
1617
aya-ebpf-cty = { version = "^0.2.3", path = "../aya-ebpf-cty" }
1718

1819
[build-dependencies]
1920
aya-build = { version = "^0.1.3", path = "../../aya-build" }
21+
22+
[features]
23+
user = ["dep:aya"]

ebpf/aya-ebpf-bindings/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,7 @@ pub mod bindings {
118118
pub id: ::aya_ebpf_cty::c_uint,
119119
pub pinning: ::aya_ebpf_cty::c_uint,
120120
}
121+
122+
#[cfg(feature = "user")]
123+
unsafe impl aya::Pod for bpf_spin_lock {}
121124
}

ebpf/aya-ebpf/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ rust-version.workspace = true
1414
workspace = true
1515

1616
[dependencies]
17+
aya-common = { version = "^0.1.0", path = "../../aya-common" }
1718
aya-ebpf-bindings = { version = "^0.1.2", path = "../aya-ebpf-bindings" }
1819
aya-ebpf-cty = { version = "^0.2.3", path = "../aya-ebpf-cty" }
1920
aya-ebpf-macros = { version = "^0.1.2", path = "../../aya-ebpf-macros" }

ebpf/aya-ebpf/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ pub mod btf_maps;
4545
pub mod helpers;
4646
pub mod maps;
4747
pub mod programs;
48+
pub mod spin_lock;
4849

4950
use core::{
5051
mem::MaybeUninit,

ebpf/aya-ebpf/src/spin_lock.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
pub use aya_common::SpinLock;
2+
3+
use crate::helpers;
4+
5+
/// An RAII implementation of a scope of a spin lock. When this structure is
6+
/// dropped (falls out of scope), the lock will be unlocked.
7+
#[must_use = "if unused the spin lock will immediately unlock"]
8+
pub struct SpinLockGuard<'a> {
9+
spin_lock: &'a mut SpinLock,
10+
}
11+
12+
impl Drop for SpinLockGuard<'_> {
13+
fn drop(&mut self) {
14+
// SAFETY: Call to an eBPF helper. `self.spin_lock` is always
15+
// initialized.
16+
unsafe {
17+
helpers::bpf_spin_unlock(core::ptr::from_mut(self.spin_lock));
18+
}
19+
}
20+
}
21+
22+
mod sealed {
23+
use super::{SpinLock, SpinLockGuard, helpers};
24+
25+
pub trait EbpfSpinLock {
26+
fn lock(&mut self) -> SpinLockGuard<'_>;
27+
}
28+
29+
impl EbpfSpinLock for SpinLock {
30+
fn lock(&mut self) -> SpinLockGuard<'_> {
31+
// SAFETY: Call to an eBPF helper. `self` is always initialized.
32+
unsafe {
33+
helpers::bpf_spin_lock(core::ptr::from_mut(self));
34+
}
35+
SpinLockGuard { spin_lock: self }
36+
}
37+
}
38+
}
39+
40+
/// Extension trait for [`SpinLock`] exposing eBPF-only helpers. These helpers
41+
/// are not available in user-space.
42+
pub trait EbpfSpinLockExt: sealed::EbpfSpinLock {
43+
fn lock(&mut self) -> SpinLockGuard<'_>;
44+
}
45+
46+
impl<T> EbpfSpinLockExt for T
47+
where
48+
T: sealed::EbpfSpinLock,
49+
{
50+
/// Acquires a spin lock and returns a [`SpinLockGuard`]. The lock is
51+
/// acquired as long as the guard is alive.
52+
#[inline]
53+
fn lock(&mut self) -> SpinLockGuard<'_> {
54+
sealed::EbpfSpinLock::lock(self)
55+
}
56+
}

0 commit comments

Comments
 (0)