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