mirror of https://github.com/aya-rs/aya
examples: Add an XDP example
Signed-off-by: Dave Tucker <dave@dtucker.co.uk>pull/33/head
parent
7251b9bc53
commit
79343c445a
@ -0,0 +1,2 @@
|
|||||||
|
[workspace]
|
||||||
|
members = ["user", "bpf"]
|
@ -0,0 +1,17 @@
|
|||||||
|
aya-examples
|
||||||
|
============
|
||||||
|
|
||||||
|
# Prerequisites
|
||||||
|
|
||||||
|
1. Install a rust nightly toolchain: `rustup install nightly`
|
||||||
|
1. Install bpf-linker: `cargo install bpf-linker`
|
||||||
|
|
||||||
|
# Build
|
||||||
|
|
||||||
|
From the project root directory, run `cargo xtask examples`
|
||||||
|
|
||||||
|
# Run
|
||||||
|
|
||||||
|
## XDP
|
||||||
|
|
||||||
|
`sudo ./examples/target/debug/xdp_userspace wlp2s0`
|
@ -0,0 +1,20 @@
|
|||||||
|
[package]
|
||||||
|
name = "bpf"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
user = [ "aya" ]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
aya-bpf = { path = "../../bpf/aya-bpf" }
|
||||||
|
aya = { path = "../../aya", optional=true }
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "xdp"
|
||||||
|
path = "src/xdp/main.rs"
|
@ -0,0 +1,3 @@
|
|||||||
|
#![no_std]
|
||||||
|
|
||||||
|
pub mod xdp;
|
@ -0,0 +1,38 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use aya_bpf::bindings::xdp_action;
|
||||||
|
use aya_bpf::cty::c_long;
|
||||||
|
use aya_bpf::macros::{map, xdp};
|
||||||
|
use aya_bpf::maps::Array;
|
||||||
|
use aya_bpf::programs::XdpContext;
|
||||||
|
|
||||||
|
use bpf::xdp::XdpData;
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[map]
|
||||||
|
static mut xdp_stats_map : Array<XdpData> = Array::with_max_entries(1,0);
|
||||||
|
|
||||||
|
#[xdp(name = "xdp_stats")]
|
||||||
|
pub fn xdp_stats(ctx: XdpContext) -> u32 {
|
||||||
|
match unsafe { try_xdp_stats(ctx) } {
|
||||||
|
Ok(ret) => ret,
|
||||||
|
Err(_) => xdp_action::XDP_DROP,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn try_xdp_stats(_ctx: XdpContext) -> Result<u32, c_long> {
|
||||||
|
let data = match xdp_stats_map.get(0) {
|
||||||
|
Some(data) => data,
|
||||||
|
None => return Err(0)
|
||||||
|
};
|
||||||
|
let xdp_data = XdpData{
|
||||||
|
packet_count: data.packet_count + 1,
|
||||||
|
};
|
||||||
|
xdp_stats_map.set(0, &xdp_data, 0)?;
|
||||||
|
Ok(xdp_action::XDP_PASS)
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct XdpData {
|
||||||
|
pub packet_count : u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "user")]
|
||||||
|
unsafe impl aya::Pod for XdpData {}
|
@ -0,0 +1,14 @@
|
|||||||
|
[package]
|
||||||
|
name = "user"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
aya = { path = "../../aya" }
|
||||||
|
bpf = { path = "../bpf", features=["user"] }
|
||||||
|
anyhow = "1.0.42"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "xdp_userspace"
|
||||||
|
path = "src/xdp.rs"
|
@ -0,0 +1,53 @@
|
|||||||
|
use aya::Bpf;
|
||||||
|
use aya::maps::{Array, MapRefMut};
|
||||||
|
use aya::programs::{Xdp, XdpFlags};
|
||||||
|
use std::{
|
||||||
|
convert::TryFrom,
|
||||||
|
convert::TryInto,
|
||||||
|
env,
|
||||||
|
fs,
|
||||||
|
thread,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use bpf::xdp::XdpData;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
if let Err(e) = try_main() {
|
||||||
|
eprintln!("error: {:#}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_main() -> Result<(), anyhow::Error> {
|
||||||
|
let path = match env::args().nth(1) {
|
||||||
|
Some(iface) => iface,
|
||||||
|
None => panic!("not path provided"),
|
||||||
|
};
|
||||||
|
let iface = match env::args().nth(2) {
|
||||||
|
Some(iface) => iface,
|
||||||
|
None => "eth0".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let data = fs::read(path)?;
|
||||||
|
let mut bpf = Bpf::load(
|
||||||
|
&data,
|
||||||
|
None)?;
|
||||||
|
|
||||||
|
// get the `xdp_stats` program compiled into `xdp`.
|
||||||
|
let probe: &mut Xdp = bpf.program_mut("xdp_stats")?.try_into()?;
|
||||||
|
|
||||||
|
// load the program into the kernel
|
||||||
|
probe.load()?;
|
||||||
|
|
||||||
|
// attach to the interface
|
||||||
|
probe.attach(&iface, XdpFlags::default())?;
|
||||||
|
|
||||||
|
let xdp_stats_map : Array::<MapRefMut, XdpData> = Array::try_from(bpf.map_mut("xdp_stats_map")?)?;
|
||||||
|
|
||||||
|
for _i in 1..10 {
|
||||||
|
let data = xdp_stats_map.get(&0, 0)?;
|
||||||
|
println!("packets received: {}", data.packet_count);
|
||||||
|
thread::sleep(Duration::from_secs(1));
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
|
#[derive(StructOpt)]
|
||||||
|
pub struct Options {}
|
||||||
|
|
||||||
|
pub fn examples(_opts: Options) -> Result<(), anyhow::Error> {
|
||||||
|
let dir = PathBuf::from("examples");
|
||||||
|
|
||||||
|
// build bpf examples
|
||||||
|
let status = Command::new("cargo")
|
||||||
|
.current_dir(&dir)
|
||||||
|
.args(&["+nightly", "build", "--verbose", "--release", "--package=bpf", "--target=bpfel-unknown-none", "-Z", "build-std=core"])
|
||||||
|
.status()
|
||||||
|
.expect("failed to build bpf examples");
|
||||||
|
assert!(status.success());
|
||||||
|
|
||||||
|
// build userspace examples
|
||||||
|
let status = Command::new("cargo")
|
||||||
|
.current_dir(&dir)
|
||||||
|
.args(&["build", "--verbose", "--package=user"])
|
||||||
|
.status()
|
||||||
|
.expect("failed to build userspace examples");
|
||||||
|
assert!(status.success());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in New Issue