Skip to content

Commit e73ade6

Browse files

File tree

10 files changed

+255
-10
lines changed

10 files changed

+255
-10
lines changed

.github/workflows/test.yml

+18-9
Original file line numberDiff line numberDiff line change
@@ -64,25 +64,28 @@ jobs:
6464
- name: Run root tests
6565
run: cd libbpf-rs && cargo test --profile=${{ matrix.profile }} --locked --verbose -- ':root:'
6666

67-
run-tcp-ca:
68-
name: Run tcp_ca example
67+
run-examples:
68+
name: Run chosen examples
6969
runs-on: ubuntu-latest
7070
steps:
7171
- uses: actions/checkout@v4
7272
- name: Install deps
73-
run: sudo apt-get install --yes --no-install-recommends libelf-dev
73+
run: |
74+
sudo apt-get install --yes --no-install-recommends libelf-dev linux-headers-$(uname -r)
75+
sudo ln -s /usr/include/asm-generic /usr/include/asm
7476
- uses: dtolnay/rust-toolchain@nightly
7577
with:
7678
components: rustfmt
7779
- uses: Swatinem/rust-cache@v2
78-
- name: Run tcp_ca
80+
- name: Run examples
7981
#env:
8082
# CFLAGS: '-fsanitize=leak'
8183
# CXXFLAGS: '-fsanitize=leak'
8284
# RUSTFLAGS: '-Zsanitizer=leak'
8385
run: |
84-
cargo build --package tcp_ca
86+
cargo build --package tcp_ca --package ringbuf_multi
8587
sudo target/debug/tcp_ca
88+
sudo target/debug/ringbuf_multi
8689
8790
build-features:
8891
name: Build [${{ matrix.args }}]
@@ -123,7 +126,9 @@ jobs:
123126
steps:
124127
- uses: actions/checkout@v4
125128
- name: Install deps
126-
run: sudo apt-get install --yes --no-install-recommends libelf-dev
129+
run: |
130+
sudo apt-get install --yes --no-install-recommends libelf-dev linux-headers-$(uname -r)
131+
sudo ln -s /usr/include/asm-generic /usr/include/asm
127132
- name: Install Nightly Rust
128133
uses: dtolnay/rust-toolchain@nightly
129134
- run: cargo +nightly -Z minimal-versions update
@@ -213,7 +218,9 @@ jobs:
213218
steps:
214219
- uses: actions/checkout@v4
215220
- name: Install deps
216-
run: sudo apt-get install --yes --no-install-recommends libelf-dev
221+
run: |
222+
sudo apt-get install --yes --no-install-recommends libelf-dev linux-headers-$(uname -r)
223+
sudo ln -s /usr/include/asm-generic /usr/include/asm
217224
- uses: dtolnay/rust-toolchain@stable
218225
with:
219226
components: rustfmt
@@ -242,7 +249,9 @@ jobs:
242249
steps:
243250
- uses: actions/checkout@v4
244251
- name: Install deps
245-
run: sudo apt-get install --yes --no-install-recommends libelf-dev
252+
run: |
253+
sudo apt-get install --yes --no-install-recommends libelf-dev linux-headers-$(uname -r)
254+
sudo ln -s /usr/include/asm-generic /usr/include/asm
246255
- uses: dtolnay/rust-toolchain@stable
247256
- run: cargo doc --locked --no-deps
248257

@@ -255,7 +264,7 @@ jobs:
255264
build-minimum,
256265
cargo-doc,
257266
clippy,
258-
run-tcp-ca,
267+
run-examples,
259268
rustfmt,
260269
test,
261270
]

Cargo.lock

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ members = [
1313
"libbpf-rs/dev",
1414
"examples/bpf_query",
1515
"examples/capable",
16+
"examples/netfilter_blocklist",
17+
"examples/ringbuf_multi",
1618
"examples/runqslower",
1719
"examples/tc_port_whitelist",
1820
"examples/tcp_ca",
1921
"examples/tcp_option",
2022
"examples/tproxy",
21-
"examples/netfilter_blocklist",
2223
]
2324
resolver = "2"

examples/ringbuf_multi/Cargo.toml

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "ringbuf_multi"
3+
version = "0.1.0"
4+
edition.workspace = true
5+
authors = ["Daniel Müller <[email protected]>"]
6+
license = "LGPL-2.1-only OR BSD-2-Clause"
7+
8+
[build-dependencies]
9+
libbpf-cargo = { path = "../../libbpf-cargo" }
10+
vmlinux = { git = "https://github.com/libbpf/vmlinux.h.git", rev = "83a228cf37fc65f2d14e4896a04922b5ee531a94" }
11+
12+
[dependencies]
13+
libbpf-rs = { path = "../../libbpf-rs" }
14+
libc = "0.2"
15+
plain = "0.2"

examples/ringbuf_multi/LICENSE

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../LICENSE
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../LICENSE.BSD-2-Clause
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../LICENSE.LGPL-2.1

examples/ringbuf_multi/build.rs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use std::env;
2+
use std::ffi::OsStr;
3+
use std::path::PathBuf;
4+
5+
use libbpf_cargo::SkeletonBuilder;
6+
7+
const SRC: &str = "src/bpf/ringbuf_multi.bpf.c";
8+
9+
fn main() {
10+
let out = PathBuf::from(
11+
env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR must be set in build script"),
12+
)
13+
.join("src")
14+
.join("bpf")
15+
.join("ringbuf_multi.skel.rs");
16+
17+
let arch = env::var("CARGO_CFG_TARGET_ARCH")
18+
.expect("CARGO_CFG_TARGET_ARCH must be set in build script");
19+
20+
SkeletonBuilder::new()
21+
.source(SRC)
22+
.clang_args([
23+
OsStr::new("-I"),
24+
vmlinux::include_path_root().join(arch).as_os_str(),
25+
])
26+
.build_and_generate(&out)
27+
.unwrap();
28+
println!("cargo:rerun-if-changed={SRC}");
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
// Copyright (c) 2020 Facebook
3+
4+
#include <linux/bpf.h>
5+
#include <bpf/bpf_helpers.h>
6+
7+
char _license[] SEC("license") = "GPL";
8+
9+
struct sample {
10+
int pid;
11+
int seq;
12+
long value;
13+
char comm[16];
14+
};
15+
16+
struct ringbuf_map {
17+
__uint(type, BPF_MAP_TYPE_RINGBUF);
18+
/* libbpf will adjust to valid page size */
19+
__uint(max_entries, 1000);
20+
} ringbuf1 SEC(".maps"),
21+
ringbuf2 SEC(".maps");
22+
23+
struct {
24+
__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
25+
__uint(max_entries, 4);
26+
__type(key, int);
27+
__array(values, struct ringbuf_map);
28+
} ringbuf_arr SEC(".maps") = {
29+
.values = {
30+
[0] = &ringbuf1,
31+
[2] = &ringbuf2,
32+
},
33+
};
34+
35+
struct {
36+
__uint(type, BPF_MAP_TYPE_HASH_OF_MAPS);
37+
__uint(max_entries, 1);
38+
__type(key, int);
39+
__array(values, struct ringbuf_map);
40+
} ringbuf_hash SEC(".maps") = {
41+
.values = {
42+
[0] = &ringbuf1,
43+
},
44+
};
45+
46+
struct sample nosample = {};
47+
48+
/* inputs */
49+
int pid = 0;
50+
int target_ring = 0;
51+
long value = 0;
52+
53+
/* outputs */
54+
long total = 0;
55+
long dropped = 0;
56+
long skipped = 0;
57+
58+
SEC("tp/syscalls/sys_enter_getpgid")
59+
int test_ringbuf(void *ctx)
60+
{
61+
int cur_pid = bpf_get_current_pid_tgid() >> 32;
62+
struct sample *sample;
63+
void *rb;
64+
65+
if (cur_pid != pid)
66+
return 0;
67+
68+
rb = bpf_map_lookup_elem(&ringbuf_arr, &target_ring);
69+
if (!rb) {
70+
skipped += 1;
71+
return 1;
72+
}
73+
74+
sample = bpf_ringbuf_reserve(rb, sizeof(*sample), 0);
75+
if (!sample) {
76+
dropped += 1;
77+
return 1;
78+
}
79+
80+
sample->pid = pid;
81+
bpf_get_current_comm(sample->comm, sizeof(sample->comm));
82+
sample->value = value;
83+
84+
sample->seq = total;
85+
total += 1;
86+
87+
bpf_ringbuf_submit(sample, 0);
88+
89+
return 0;
90+
}

examples/ringbuf_multi/src/main.rs

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2+
3+
use core::time::Duration;
4+
use std::ffi::c_int;
5+
use std::mem::MaybeUninit;
6+
7+
use plain::Plain;
8+
9+
use libbpf_rs::skel::OpenSkel;
10+
use libbpf_rs::skel::Skel;
11+
use libbpf_rs::skel::SkelBuilder;
12+
use libbpf_rs::Result;
13+
14+
mod ringbuf_multi {
15+
include!(concat!(
16+
env!("CARGO_MANIFEST_DIR"),
17+
"/src/bpf/ringbuf_multi.skel.rs"
18+
));
19+
}
20+
21+
use ringbuf_multi::*;
22+
23+
unsafe impl Plain for types::sample {}
24+
25+
fn process_sample(ring: c_int, data: &[u8]) -> i32 {
26+
let s = plain::from_bytes::<types::sample>(data).unwrap();
27+
28+
match s.seq {
29+
0 => {
30+
assert_eq!(ring, 1);
31+
assert_eq!(s.value, 333);
32+
0
33+
}
34+
1 => {
35+
assert_eq!(ring, 2);
36+
assert_eq!(s.value, 777);
37+
0
38+
}
39+
_ => unreachable!(),
40+
}
41+
}
42+
43+
fn main() -> Result<()> {
44+
let skel_builder = RingbufMultiSkelBuilder::default();
45+
let mut open_object = MaybeUninit::uninit();
46+
let open_skel = skel_builder.open(&mut open_object)?;
47+
let mut skel = open_skel.load()?;
48+
49+
// Only trigger BPF program for current process.
50+
let pid = unsafe { libc::getpid() };
51+
skel.maps.bss_data.pid = pid;
52+
53+
let mut builder = libbpf_rs::RingBufferBuilder::new();
54+
builder
55+
.add(&skel.maps.ringbuf1, |data| process_sample(1, data))
56+
.expect("failed to add ringbuf");
57+
builder
58+
.add(&skel.maps.ringbuf2, |data| process_sample(2, data))
59+
.expect("failed to add ringbuf");
60+
let ringbuf = builder.build().unwrap();
61+
62+
let () = skel.attach()?;
63+
64+
// trigger few samples, some will be skipped
65+
skel.maps.bss_data.target_ring = 0;
66+
skel.maps.bss_data.value = 333;
67+
let _pgid = unsafe { libc::getpgid(pid) };
68+
69+
// skipped, no ringbuf in slot 1
70+
skel.maps.bss_data.target_ring = 1;
71+
skel.maps.bss_data.value = 555;
72+
let _pgid = unsafe { libc::getpgid(pid) };
73+
74+
skel.maps.bss_data.target_ring = 2;
75+
skel.maps.bss_data.value = 777;
76+
let _pgid = unsafe { libc::getpgid(pid) };
77+
78+
// poll for samples, should get 2 ringbufs back
79+
let n = ringbuf.poll_raw(Duration::MAX);
80+
assert_eq!(n, 2);
81+
println!("successfully polled {n} samples");
82+
83+
// expect extra polling to return nothing
84+
let n = ringbuf.poll_raw(Duration::from_secs(0));
85+
assert!(n == 0, "{n}");
86+
Ok(())
87+
}

0 commit comments

Comments
 (0)