Skip to content

Commit

Permalink
add xdp crate
Browse files Browse the repository at this point in the history
Signed-off-by: iGxnon <[email protected]>
  • Loading branch information
iGxnon committed Oct 3, 2024
1 parent 92ef2f6 commit 483eb00
Show file tree
Hide file tree
Showing 9 changed files with 248 additions and 9 deletions.
4 changes: 4 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
[target.'cfg(all())']
rustflags = ["--cfg", "tokio_unstable"]

[alias]
x = "run --package xtask --"
xtask = "run --package xtask --"
32 changes: 24 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
[package]
name = "raknet-rs"
version = "0.1.3"
edition = "2021"
license = "Apache-2.0"
authors = ["iGxnon"]
readme = "README.md"
resolver = "2"
description = "Raknet protocol implementation by rust"
homepage = "https://github.com/MemoriesOfTime/raknet-rs"
repository = "https://github.com/MemoriesOfTime/raknet-rs"
readme = "README.md"
categories = ["network-programming"]
keywords = ["raknet", "network", "udp"]
edition = { workspace = true }
license = { workspace = true }
authors = { workspace = true }
homepage = { workspace = true }
repository = { workspace = true }
categories = { workspace = true }
keywords = { workspace = true }

[dependencies]
async-channel = "2.3.1"
Expand Down Expand Up @@ -50,6 +50,22 @@ lto = true

[lints]
workspace = true
#
#############################
## workspace configuration ##
#############################
#
[workspace]
members = ["xdp/ebpf", "xdp/raknet-xdp"]

[workspace.package]
edition = "2021"
license = "Apache-2.0"
authors = ["iGxnon"]
homepage = "https://github.com/MemoriesOfTime/raknet-rs"
repository = "https://github.com/MemoriesOfTime/raknet-rs"
categories = ["network-programming"]
keywords = ["raknet", "network", "udp"]

[workspace.lints.rust]
keyword_idents = "warn"
Expand Down
2 changes: 1 addition & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ default:
just --list

fix:
cargo fmt
cargo fmt --all
cargo sort --workspace
cargo machete --fix

Expand Down
5 changes: 5 additions & 0 deletions xdp/ebpf/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[build]
target = ["bpfeb-unknown-none", "bpfel-unknown-none"]

[unstable]
build-std = ["core"]
27 changes: 27 additions & 0 deletions xdp/ebpf/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[package]
name = "ebpf"
version = "0.1.0"
publish = false
edition = { workspace = true }
license = { workspace = true }
authors = { workspace = true }
homepage = { workspace = true }
repository = { workspace = true }
categories = { workspace = true }
keywords = { workspace = true }

[dependencies]
# These crates are not published so use a git dependency for now. See https://github.com/aya-rs/aya/issues/464
aya-bpf = { git = "https://github.com/aya-rs/aya", tag = "aya-v0.12.0" }
aya-log-ebpf = { git = "https://github.com/aya-rs/aya", tag = "aya-v0.12.0" }

[features]
default = []
trace = []

[[bin]]
name = "raknet-xdp-ebpf"
path = "src/main.rs"

[lints]
workspace = true
50 changes: 50 additions & 0 deletions xdp/ebpf/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#![no_std]
#![no_main]

use aya_bpf::bindings::xdp_action;
use aya_bpf::macros::{map, xdp};
use aya_bpf::maps::{HashMap, XskMap};
use aya_bpf::programs::XdpContext;

// Never panic
#[cfg(not(test))]
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
unsafe { core::hint::unreachable_unchecked() }
}

#[map]
static XDP_SOCKETS: XskMap = XskMap::with_max_entries(1024, 0);

#[map]
static XDP_PORTS: HashMap<u16, u8> = HashMap::with_max_entries(1024, 0);

#[xdp]
pub fn raknet_xdp(ctx: XdpContext) -> u32 {
let action = redirect_udp(&ctx);

#[cfg(feature = "trace")]
{
use aya_log_ebpf as log;

match action {
xdp_action::XDP_DROP => log::trace!(&ctx, "ACTION: DROP"),
xdp_action::XDP_PASS => log::trace!(&ctx, "ACTION: PASS"),
xdp_action::XDP_REDIRECT => log::trace!(&ctx, "ACTION: REDIRECT"),
xdp_action::XDP_ABORTED => log::trace!(&ctx, "ACTION: ABORTED"),
_ => (),
}
}

action
}

fn redirect_udp(ctx: &XdpContext) -> u32 {
let start = ctx.data() as *mut u8;
let len = ctx.data_end() - ctx.data();
// Safety: It was checked to be in XdpContext
let _data = unsafe { core::slice::from_raw_parts_mut(start, len) };
// TODO: parse data and check whether it is a valid UDP frame

xdp_action::XDP_PASS
}
22 changes: 22 additions & 0 deletions xdp/raknet-xdp/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "raknet-xdp"
version = "0.1.0"
edition = { workspace = true }
license = { workspace = true }
authors = { workspace = true }
homepage = { workspace = true }
repository = { workspace = true }
categories = { workspace = true }
keywords = { workspace = true }

[dependencies]
aya = { version = "0.12", default-features = false }

[dev-dependencies]
env_logger = "0.11"

[build-dependencies]
cargo_metadata = "0.18"

[lints]
workspace = true
110 changes: 110 additions & 0 deletions xdp/raknet-xdp/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
use std::io::{BufRead, BufReader};
use std::path::PathBuf;
use std::process::{Child, Command, Stdio};
use std::{env, fs};

use cargo_metadata::{
Artifact, CompilerMessage, Message, Metadata, MetadataCommand, Package, Target,
};

const RECOMPILE_OPT: &str = "RAK_XDP_EBPF_COMPILE";
const TRACE_OPT: &str = "RAK_XDP_EBFP_TRACE";

fn main() {
println!("cargo:rerun-if-env-changed={}", RECOMPILE_OPT);
println!("cargo:rerun-if-env-changed={}", TRACE_OPT);

let enable_trace = env::var(TRACE_OPT).unwrap_or_default();
let out_dir = env::var_os("OUT_DIR").unwrap();
let out_dir = PathBuf::from(out_dir);
let endian = env::var_os("CARGO_CFG_TARGET_ENDIAN").unwrap();
let target = if endian == "big" {
"bpfeb-unknown-none"
} else if endian == "little" {
"bpfel-unknown-none"
} else {
panic!("unsupported endian={:?}", endian)
};
let Metadata { packages, .. } = MetadataCommand::new().no_deps().exec().unwrap();
let ebpf_package = packages
.into_iter()
.find(|Package { name, .. }| name == "ebpf")
.unwrap();
let Package { manifest_path, .. } = ebpf_package;
let ebpf_dir = manifest_path.parent().unwrap();

println!("cargo:rerun-if-changed={}", ebpf_dir.as_str());

// build all bins in ebpf
let mut cmd = Command::new("cargo");
cmd.current_dir(ebpf_dir);
cmd.args([
"build",
"-Z",
"build-std=core",
"--bins",
"--message-format=json",
"--release",
"--target",
target,
]);
if matches!(enable_trace.to_lowercase().as_str(), "1" | "on" | "true") {
cmd.args(["--features", "trace"]);
}

let mut child = cmd
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap_or_else(|err| panic!("failed to spawn {cmd:?}: {err}"));
let Child { stdout, stderr, .. } = &mut child;

// Trampoline stdout to cargo warnings.
let stderr = BufReader::new(stderr.take().unwrap());
let stderr = std::thread::spawn(move || {
for line in stderr.lines() {
let line = line.unwrap();
println!("cargo:warning={line}");
}
});

let stdout = BufReader::new(stdout.take().unwrap());
let mut executables = Vec::new();
for message in Message::parse_stream(stdout) {
#[allow(clippy::collapsible_match)]
match message.expect("valid JSON") {
Message::CompilerArtifact(Artifact {
executable,
target: Target { name, .. },
..
}) => {
if let Some(executable) = executable {
executables.push((name, executable.into_std_path_buf()));
}
}
Message::CompilerMessage(CompilerMessage { message: msg, .. }) => {
for line in msg.rendered.unwrap_or_default().split('\n') {
println!("cargo:warning={line}");
}
}
Message::TextLine(line) => {
println!("cargo:warning={line}");
}
_ => {}
}
}

let status = child
.wait()
.unwrap_or_else(|err| panic!("failed to wait for {cmd:?}: {err}"));
assert_eq!(status.code(), Some(0), "{cmd:?} failed: {status:?}");

stderr.join().map_err(std::panic::resume_unwind).unwrap();

// copy to $OUT_DIR
for (name, binary) in executables {
let dst = out_dir.join(name);
let _: u64 = fs::copy(&binary, &dst)
.unwrap_or_else(|err| panic!("failed to copy {binary:?} to {dst:?}: {err}"));
}
}
5 changes: 5 additions & 0 deletions xdp/raknet-xdp/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use aya::include_bytes_aligned;

pub const DEFAULT_PROGRAM: &[u8] =
include_bytes_aligned!(concat!(env!("OUT_DIR"), "/raknet-xdp-ebpf"));
pub const DEFAULT_PROGRAM_NAME: &str = "raknet_xdp";

0 comments on commit 483eb00

Please sign in to comment.