Skip to content

gamemann/xdpstats-rs

Repository files navigation

XDP Stats Build Workflow XDP Stats Run Workflow

A tool that utilizes an awesome Rust library called Aya to deploy a simple XDP stats program. This tool increments counters for packets and bytes using a per CPU array map and displays the counters inside of the user-space program. There is a matched stat which is only incremented when packets arrive on a configured protocol (TARGET_PROTO, default: UDP) and port (TARGET_PORT, default: 8080).

Preview

The goal of this project is to replicate functionality from my XDP Stats project I made years ago in C using Rust and Aya along with adding additional features. The XDP/eBPF kernel program is written in Rust as well!

You can display the counters in rate per second or as a total count as seen in the demo above. With that said, there's also an included watch mode that displays stats in a TUI (by passing the -w flag). This is useful for monitoring stats in real time!

πŸš€ Features

  • Support for calculating packet counters in both the XDP eBPF program and inside of AF_XDP sockets.
  • Supports the option to have matched packets dropped or TX'd (with FIB lookup support!).
    • This is great if you want to test both drop and TX actions!
    • If FIB lookup isn't enabled, the ethernet, IP, and transport headers are swapped and the packet is sent back out the same interface it arrived on.
  • Support for attaching to multiple interfaces.
  • Display packet counters including total packets/bytes for different types of stats including matched, error, bad, dropped, and passed packets.
  • Support for displaying stats in rate per second instead of total count.
  • Support for a watch mode that displays stats in a TUI and updates in real time (as seen in the demo above).

🚨 Experimental

This project is in early development. While the core features are functional, users may encounter bugs depending on specific configurations. If you find a bug or have a suggestion, please open an issue.

βš™οΈ Preparing

I developed this project using Debian 13 and the following commands should prepare your environment to run this project. I'd recommend giving this documentation a read as well!

# Install required packages through apt.
sudo apt install -y git curl cmake pkg-config libssl-dev llvm-19-dev libclang-19-dev libpolly-19-dev libelf-dev libpcap-dev

# Install Rust using rustup.
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# We need the Rust stable and nightly toolchains.
rustup install stable
rustup toolchain install nightly --component rust-src

# Install linker.
cargo install bpf-linker

# This is optional, but will be needed if you want to generate your own Aya project:
# cargo install cargo-generate

# cargo generate https://github.com/aya-rs/aya-template

NOTE - The default README that comes with Aya projects may be found here. This README contains more information for other operating systems!

πŸ› οΈ Building & Running

Building and running this project is simple as long as you've ran the steps in the preparing section above.

You can use git to clone the project.

# Clone repository using Git
git clone https://github.com/gamemann/xdpstats-rs.git

# Change to project directory.
cd xdpstats-rs

You can then build and run the project using the following commands.

# Only build project.
cargo build

# Build project for release.
cargo build --release

# Build and run project in dev mode.
cargo run # Will fail if eth0 doesn't exist.

# Run project in release mode.,
cargo run --release

# Run project in release mode on interface 'enp1s0'.
cargo run --release -- -i enp1s0

# If you want to install to $PATH (/usr/bin), please use the included script!
sudo ./install_to_path.sh

# Now use it like a normal command!
sudo xdpstats -i enp1s0 -w -p

Features

There are three features you may build the tool with: afxdp, tx, tx_fib.

Feature Description
afxdp Forwards matched packets to AF_XDP sockets to calculate.
tx Sends the packet back out through the same interface and swaps the packet headers including ethernet addresses, IP addresses, and layer 4 ports.
tx_fib Instead of swapping ports when TX'ing the packet, performs a FIB (Forwarding Information Base) lookup to determine the next hop.

To build the tool, you may pass F or --features when running or building.

For example:

# Build with AF_XDP support.
cargo build --features afxdp

# Build with TX support.
cargo build --features tx

# Build with TX_FIB support.
cargo build --features tx,tx_fib

# Build with AF_XDP and TX support.
cargo build --features afxdp,tx

# Build for release (AFXDP + TX).
cargo build --release --features afxdp,tx

πŸ“ Command Line Options

The following command line options are supported.

Args Default Description
-i --iface eth0 The interface(s) to attach the XDP program to. You may separate interfaces with commas (e.g. eth0,eth1).
-l --list - If set, lists all setting values and exits.
-L --log info The log level to use. Supported values are trace, debug, info, warn, and error.
-B --backlog 200 The amount of log lines to keep in the buffer if using the watch mode.
-w --watch - If set, enables watch mode which displays log lines and stats in a TUI.
-d --duration 0 How long to run the program for in seconds (0 = unlimited util CTRL + C).
-s --skb - If set, attempts to load the XDP program in SKB mode which is slower, but more compatible.
-o --offload - If set, attempts to offload the XDP program to the NIC hardware (only certain NICs support this).
-z --replace - If set, passes the REPLACE flag when attaching the XDP program which replaces the XDP program if it is already loaded. For some reason this results in a crash. Otherwise it would be set by default.
-p --per-sec false If set, displays stats in rate per second instead of total count.
-N --sec-name xdp_stats The section name to use for the XDP program in the eBPF ELF file. This is only needed if you change the section name in the eBPF program.

Additional Settings For afxdp Feature

Here are settings for AF_XDP sockets.

Args Default Description
-n --num-socks 0 The amount of AF_XDP sockets to create if using AF_XDP mode (0 = Auto).
-b --batch-size 64 The batch size to use when polling AF_XDP sockets.
-r --rx-sz 2048 The RX ring size to use for AF_XDP sockets.
-t --tx-sz 2048 The TX ring size to use for AF_XDP sockets.
-c --cq-sz 2048 The completion queue size to use for AF_XDP sockets.
-F --fq-sz 2048 The fill queue size to use for AF_XDP sockets.
-f --frame-sz 2048 The maximum amount of bytes a frame can hold for AF_XDP sockets.
-m --frame-cnt 4096 The amount of frames to use for AF_XDP sockets.
-u --wakeup false If set, enables wakeup mode for AF_XDP sockets which uses interrupts instead of busy polling.
-x --zero-copy false If set, enables zero copy mode for AF_XDP sockets which allows packets to be sent and received without copying data between user-space and kernel-space.
-S --shared-umem false If set, allows multiple AF_XDP sockets to share the same UMEM which can reduce memory usage.
-q --queue-id None The queue ID to use for AF_XDP sockets (0 = Auto; set to core ID from 0).
-p --poll-timeout 100 The amount of time in milliseconds to wait when polling AF_XDP sockets.

πŸ“ Compile Time Configuration

There are constants you may change in the xdpstats-common/src/config.rs file. You will need to rebuild the tool after changing these values!

/* CONFIG OPTIONS */
/* -------------------------------- */
// The target protocol to match.
// You may use IpProto::Tcp, IpProto::Icmp, etc.
pub const TARGET_PROTOCOL: u8 = IpProto::Udp as u8;

// The target port to match packets on.
// Set this to 0 for no port matching.
pub const TARGET_PORT: u16 = 8080;

// The path to the ELF file to load with eBPF.
// Relative to $OUT_DIR env var, but you shouldn't need to change this.
pub const PATH_ELF_FILE: &str = "xdpstats";

// Max CPUs supported by the program.
pub const MAX_CPUS: usize = 256;
/* -------------------------------- */
/* CONFIG OPTIONS END */

πŸ“Œ Notes

Additional XDP Sections

There are four additional XDP sections that may be loaded with the -N --sec argument.

  • xdp_stats_pass_simple - A simple XDP program that literally only returns XDP_PASS. This is useful for testing and debugging. This does not increment the per-CPU stats map. Therefore you'll be relying on packet counters from the NIC (usually accessible through ethtool -S <iface>).
  • xdp_stats_drop_simple - A simple XDP program that literally only returns XDP_DROP. This is useful for testing and debugging. This does not increment the per-CPU stats map. Therefore you'll be relying on packet counters from the NIC (usually accessible through ethtool -S <iface>).
  • xdp_stats_pass_simple_stats - Does what xdp_stats_pass_simple does, but also increments the passed stat for every packet.
  • xdp_stats_drop_simple_stats - Does what xdp_stats_drop_simple does, but also increments the dropped stat for every packet.

✍️ Credits

About

A tool that increments and displays packet counters for matched, bad, passed, and more for XDP! Matched packets have the option to be dropped or TX'd (with swapping ports + FIB lookup support). Dropping and forwarding the packets through AF_XDP sockets is also supported!!

Topics

Resources

License

Apache-2.0 and 2 other licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
GPL-2.0
LICENSE-GPL2
MIT
LICENSE-MIT

Stars

8 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors