Skip to content

Commit 6723fdc

Browse files
author
Don Johnson
committed
added cleaner script (#25)
* added cleaner script * updated based on recommendation --------- Co-authored-by: Don Johnson <[email protected]>
1 parent 03dd301 commit 6723fdc

File tree

11 files changed

+269
-0
lines changed

11 files changed

+269
-0
lines changed

bitswing/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/target

bitswing/Cargo.toml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[workspace]
2+
members = ["bpf", "user"]
3+
4+
[package]
5+
name = "bitswing-workspace"
6+
version = "0.1.0"
7+
edition = "2021"
8+
9+
[lib]
10+
name = "bitswing_workspace"
11+
path = "src/lib.rs"

bitswing/Config.toml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[general]
2+
interface = "eth0"
3+
default_rate_limit_bps = 500000
4+
5+
[[rules]]
6+
port = 80
7+
rate_limit_bps = 1000000
8+
9+
[[rules]]
10+
port = 443
11+
rate_limit_bps = 1500000

bitswing/Makefile

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Makefile for BitSwing
2+
3+
# Project directories
4+
BPF_DIR := bpf
5+
USER_DIR := user
6+
7+
# BPF build output (assuming a release build)
8+
BPF_TARGET := $(BPF_DIR)/target/bpfel-unknown-none/release/bitswing-bpf
9+
10+
# User-space binary (release build)
11+
USER_TARGET := $(USER_DIR)/target/release/bitswing-user
12+
13+
# If you need a special Docker image to cross-compile eBPF, set it here:
14+
AYA_BUILDER_IMAGE := ghcr.io/aya-rs/aya-builder-x86_64-unknown-linux-gnu:latest
15+
16+
# Phony targets don't correspond to actual files
17+
.PHONY: all bpf user clean run install
18+
19+
## Default target: build everything
20+
all: bpf user
21+
22+
## Build the BPF crate
23+
bpf:
24+
# Option 1: Native build (requires rustup target add bpfel-unknown-none)
25+
# cd $(BPF_DIR) && cargo build --release --target bpfel-unknown-none
26+
#
27+
# Option 2: Use Docker-based builder (uncomment if you use aya-builder)
28+
# docker run --rm -v $(shell pwd):/workdir -w /workdir/$(BPF_DIR) \
29+
# $(AYA_BUILDER_IMAGE) cargo build --release --target bpfel-unknown-none
30+
#
31+
# For now, we'll assume local native build:
32+
cd $(BPF_DIR) && cargo build --release --target bpfel-unknown-none
33+
34+
## Build the user-space crate
35+
user:
36+
cd $(USER_DIR) && cargo build --release
37+
38+
## Clean all build artifacts
39+
clean:
40+
cd $(BPF_DIR) && cargo clean
41+
cd $(USER_DIR) && cargo clean
42+
43+
## Run the user-space binary (requires sudo if attaching XDP)
44+
run: all
45+
@echo "Running BitSwing user-space daemon..."
46+
sudo $(USER_TARGET)
47+
48+
## Optional: Install the user binary (and optionally the BPF bytecode) to /usr/local/bin
49+
install: all
50+
@echo "Installing user binary to /usr/local/bin..."
51+
sudo cp $(USER_TARGET) /usr/local/bin/bitswing
52+
@echo "Installing BPF bytecode to /usr/local/lib/bitswing/..."
53+
sudo mkdir -p /usr/local/lib/bitswing
54+
sudo cp $(BPF_TARGET) /usr/local/lib/bitswing/bitswing-bpf
55+
@echo "Install complete."

bitswing/README.md

Whitespace-only changes.

bitswing/bpf/src/Cargo.toml

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "bitswing-bpf"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
aya-bpf = "0.15.1"
8+
9+
[lib]
10+
crate-type = ["cdylib"]

bitswing/bpf/src/shaper.rs

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
use aya_bpf::{
5+
bindings::xdp_action::XDP_PASS,
6+
macros::{map, xdp},
7+
maps::HashMap,
8+
programs::XdpContext,
9+
};
10+
use core::mem;
11+
12+
#[repr(C)]
13+
pub struct RateLimit {
14+
pub bps: u32,
15+
}
16+
17+
#[map(name = "RATE_LIMIT_MAP")]
18+
static mut RATE_LIMIT_MAP: HashMap<u16, RateLimit> = HashMap::with_max_entries(1024, 0);
19+
20+
#[xdp(name = "shaper")]
21+
pub fn shaper(ctx: XdpContext) -> u32 {
22+
if try_shaper(&ctx).is_err() {
23+
XDP_PASS
24+
} else {
25+
XDP_PASS
26+
}
27+
}
28+
29+
fn try_shaper(ctx: &XdpContext) -> Result<(), i64> {
30+
let data = ctx.data();
31+
let data_end = ctx.data_end();
32+
33+
// Check length for at least an Ethernet header
34+
if data + mem::size_of::<aya_bpf::bindings::ethhdr>() > data_end {
35+
return Ok(());
36+
}
37+
38+
// Hard-coded example: port = 80
39+
if let Some(limit) = unsafe { RATE_LIMIT_MAP.get(&80u16) } {
40+
let _bps = limit.bps;
41+
// Real shaping logic would track usage & drop/mark packets as needed
42+
}
43+
Ok(())
44+
}

bitswing/snap.sh

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#!/bin/bash
2+
3+
# Output file for the snapshot
4+
output_file="filesystem_snapshot_$(date +%Y%m%d_%H%M%S).txt"
5+
6+
# Function to process files
7+
process_file() {
8+
local file="$1"
9+
10+
# Skip files ending with .sum
11+
if [[ "$file" == *.sum ]]; then
12+
return
13+
fi
14+
15+
# Add file separator and path to output
16+
echo -e "\n=== File: $file ===" >> "$output_file"
17+
18+
# Check if file is binary
19+
if [[ -f "$file" ]] && ! [[ -x "$file" ]] && file "$file" | grep -q "text"; then
20+
# For text files, add content
21+
echo -e "\n--- Content ---" >> "$output_file"
22+
cat "$file" >> "$output_file"
23+
else
24+
# For binary files, just note that it's binary
25+
echo -e "\n[Binary file]" >> "$output_file"
26+
fi
27+
}
28+
29+
# Main function to traverse directory
30+
traverse_directory() {
31+
local dir="$1"
32+
33+
# Find all files and directories, excluding specified patterns
34+
find "$dir" \
35+
-not \( -path "*/target/*" -o -path "*/target" \) \
36+
-not \( -path "*/.git/*" -o -path "*/.git" \) \
37+
-not \( -path "*/.cargo/*" -o -path "*/.cargo" \) \
38+
-not \( -path "*/.rustup/*" -o -path "*/.rustup" \) \
39+
-type f -o -type d | while read -r item; do
40+
41+
if [[ -f "$item" ]]; then
42+
process_file "$item"
43+
elif [[ -d "$item" ]]; then
44+
echo -e "\n=== Directory: $item ===" >> "$output_file"
45+
fi
46+
done
47+
}
48+
49+
# Initialize output file with header
50+
echo "File System Snapshot - Generated on $(date)" > "$output_file"
51+
echo "Current working directory: $(pwd)" >> "$output_file"
52+
echo -e "\n----------------------------------------" >> "$output_file"
53+
54+
# Start traversal from current directory
55+
traverse_directory "."
56+
57+
echo "Snapshot has been generated in: $output_file"

bitswing/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#![allow(dead_code)]
2+
3+
pub fn placeholder() {
4+
// No-op function, just to have a valid library target.
5+
}

bitswing/user/Cargo.toml

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "bitswing-user"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
aya = "0.13.1"
8+
serde = { version = "1.0", features = ["derive"] }
9+
toml = "0.8"

bitswing/user/src/main.rs

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
use aya::{Bpf, include_bytes_aligned, maps::HashMap, programs::Xdp};
2+
use aya::programs::xdp::XdpFlags;
3+
use serde::Deserialize;
4+
use std::fs;
5+
6+
#[derive(Deserialize)]
7+
struct General {
8+
interface: String,
9+
default_rate_limit_bps: u32,
10+
}
11+
12+
#[derive(Deserialize)]
13+
struct Rule {
14+
port: u16,
15+
rate_limit_bps: u32,
16+
}
17+
18+
#[derive(Deserialize)]
19+
struct Config {
20+
general: General,
21+
rules: Vec<Rule>,
22+
}
23+
24+
#[repr(C)]
25+
#[derive(Copy, Clone)]
26+
pub struct RateLimit {
27+
pub bps: u32,
28+
}
29+
30+
static BPF_BYTES: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/bitswing-bpf"));
31+
32+
fn main() -> Result<(), Box<dyn std::error::Error>> {
33+
// Read TOML config
34+
let config_str = fs::read_to_string("Config.toml")?;
35+
let config: Config = toml::from_str(&config_str)?;
36+
37+
// Load BPF bytecode
38+
let mut bpf = Bpf::load(BPF_BYTES)?;
39+
let mut shaper = bpf.program_mut("shaper").ok_or("program not found")?;
40+
shaper.load()?;
41+
if let Some(xdp) = shaper.try_into_xdp() {
42+
xdp.attach(&config.general.interface, XdpFlags::SKB_MODE)?;
43+
}
44+
45+
// Populate BPF map
46+
let mut rate_map = HashMap::<u16, RateLimit>::try_from(bpf.map_mut("RATE_LIMIT_MAP")?)?;
47+
let default_limit = RateLimit {
48+
bps: config.general.default_rate_limit_bps,
49+
};
50+
// Use port=0 as a "catch-all" or fallback
51+
rate_map.insert(&0, &default_limit, 0)?;
52+
53+
// Insert per-port rules
54+
for rule in &config.rules {
55+
let limit = RateLimit { bps: rule.rate_limit_bps };
56+
rate_map.insert(&rule.port, &limit, 0)?;
57+
}
58+
59+
println!(
60+
"BitSwing running on {}. Press Ctrl+C to stop.",
61+
config.general.interface
62+
);
63+
loop {
64+
std::thread::park();
65+
}
66+
}

0 commit comments

Comments
 (0)