14 KiB
Stack Research
Domain: Rust eBPF-based network monitoring TUI tool (cross-platform: Linux + macOS) Researched: 2026-03-21 Confidence: MEDIUM-HIGH (eBPF/Linux stack is well-established; macOS backend strategy has more uncertainty)
Recommended Stack
Core Technologies
| Technology | Version | Purpose | Why Recommended |
|---|---|---|---|
| Rust (nightly) | nightly-2026-xx | Language + eBPF compilation | Nightly required for eBPF target (bpfel-unknown-none, -Z build-std=core). Pin a specific nightly via rust-toolchain.toml for reproducibility. |
| Aya | 0.13.x | eBPF library (userspace loader + kernel program SDK) | Pure Rust eBPF, no libbpf/bcc dependency. BTF support for kernel portability. Async tokio integration via AsyncPerfEventArray and RingBufAsync. The standard choice for Rust eBPF -- no real competitor in the Rust ecosystem. |
| aya-ebpf | 0.1.x | eBPF kernel-side program macros | Companion to aya. Provides #[kprobe], #[tracepoint], #[cgroup_skb] macros for writing eBPF programs in Rust. |
| Ratatui | 0.30.x | Terminal UI framework | Undisputed standard for Rust TUIs. Immediate-mode rendering, sub-millisecond performance, huge widget library. Table, sparklines, and layout primitives are exactly what a top-like tool needs. |
| Crossterm | 0.28.x+ | Terminal backend for Ratatui | Default backend for ratatui. Cross-platform (Linux, macOS). Pure Rust, no ncurses dependency. |
| Tokio | 1.43+ (LTS) | Async runtime | Required by Aya's async features (AsyncPerfEventArray, RingBufAsync). Handles concurrent event processing from eBPF maps and TUI rendering loop. Use the LTS release for stability. |
| clap | 4.6.x | CLI argument parsing | De facto standard. Derive macros for zero-boilerplate argument definitions. Supports --port, --log, --pid flags naturally. |
Platform-Specific Backend (Data Collection)
This is the most architecturally significant decision. eBPF only works on Linux. macOS needs a different backend behind a shared trait interface.
| Technology | Platform | Purpose | Why Recommended |
|---|---|---|---|
| Aya (eBPF kprobes/tracepoints) | Linux | Kernel-level connection tracing | Lowest overhead. Attach to tcp_connect, tcp_close, tcp_sendmsg, udp_sendmsg etc. Data flows via RingBuf or PerfEventArray to userspace. |
| pcap (libpcap bindings) | macOS (primary) | Packet capture with PKTAP | macOS PKTAP embeds PID and process name directly in packet headers. The pcap crate (v2.3.x) wraps libpcap which is pre-installed on macOS. PKTAP is the closest macOS equivalent to eBPF for network monitoring. |
| sysinfo | Both | Process name/metadata enrichment | Cross-platform process information (PID to name mapping, etc.). Supplements both backends. |
| procfs | Linux only | /proc/net/* parsing (fallback) | Fallback for connection state when eBPF data is incomplete. Parse /proc/net/tcp, /proc/net/udp for socket-to-PID mapping. |
Supporting Libraries
| Library | Version | Purpose | When to Use |
|---|---|---|---|
| csv | 1.4.x | CSV log file writing | --log output.csv mode. BurntSushi's csv crate is the only sensible choice -- fast, serde-integrated, battle-tested (129M+ downloads). |
| serde + serde_json | 1.x | Serialization framework | Derive Serialize for connection records. Used by csv crate for struct-to-row mapping. |
| anyhow | 1.x | Error handling (application) | Ergonomic error handling in the binary crate. Use thiserror in library code if you extract one. |
| thiserror | 2.x | Error handling (library) | Typed errors for the platform abstraction layer and data collection backends. |
| nix | 0.29.x | Unix system calls | Low-level syscall access (socket options, process info, privilege checking). Cross-platform Unix support. |
| libc | 0.2.x | FFI type definitions | Required by aya and nix. Transitive dependency but worth pinning. |
| log + env_logger | 0.4.x / 0.11.x | Logging | Debug logging during development. Not for the TUI output -- for internal diagnostics. |
| signal-hook | 0.3.x | Signal handling | Graceful shutdown on SIGINT/SIGTERM. Important for root-privilege tools that manipulate kernel state. |
Build and Development Tools
| Tool | Purpose | Notes |
|---|---|---|
| bpf-linker | Links eBPF object files | cargo install bpf-linker. On macOS, install with --no-default-features and ensure LLVM 21+ is available. |
| cargo-generate | Project scaffolding | Use aya-template for initial project structure. Optional after initial setup. |
| rust-toolchain.toml | Pin nightly version | Critical for reproducible eBPF builds. Pin both nightly channel and bpfel-unknown-none target. |
| cargo xtask | Build orchestration | Aya projects use an xtask pattern: a workspace member that builds the eBPF program and embeds it in the userspace binary. Standard pattern -- follow it. |
| cross | Cross-compilation | For building Linux binaries from macOS (CI/CD). Not needed for local dev if targeting native platform. |
Project Structure (Aya Convention)
tcptop/
Cargo.toml # Workspace root
xtask/ # Build tool (compiles eBPF, embeds in binary)
Cargo.toml
src/main.rs
tcptop-ebpf/ # eBPF kernel programs (no_std, nightly)
Cargo.toml
src/main.rs # kprobes, tracepoints
tcptop/ # Userspace binary
Cargo.toml
src/
main.rs # CLI parsing, TUI loop
collector/ # Platform abstraction trait
mod.rs # trait NetworkCollector
linux.rs # Aya eBPF implementation
macos.rs # PKTAP/libpcap implementation
tui/ # Ratatui rendering
model/ # Connection state, aggregation
Installation
# Prerequisites (Linux)
rustup toolchain install nightly
rustup target add bpfel-unknown-none --toolchain nightly
cargo install bpf-linker
# Prerequisites (macOS -- for cross-compiling eBPF or developing userspace)
brew install llvm
cargo install bpf-linker --no-default-features
# Project dependencies (in workspace Cargo.toml for userspace crate)
cargo add aya tokio --features tokio/full
cargo add ratatui crossterm
cargo add clap --features derive
cargo add csv serde --features serde/derive
cargo add anyhow thiserror
cargo add sysinfo nix --features nix/net,nix/process
cargo add pcap # macOS backend
cargo add signal-hook
cargo add log env_logger
# eBPF crate dependencies (tcptop-ebpf/Cargo.toml)
# aya-ebpf = "0.1"
# aya-log-ebpf = "0.1"
Alternatives Considered
| Recommended | Alternative | When to Use Alternative |
|---|---|---|
| Aya | libbpf-rs (Rust bindings for libbpf) | If you need C-based eBPF programs or have existing .bpf.c code to integrate. Aya is better for pure-Rust projects. |
| Aya | RedBPF | Never -- RedBPF is largely unmaintained and has been superseded by Aya in the Rust ecosystem. |
| Ratatui | cursive | If you want a callback-based (retained mode) TUI instead of immediate mode. Ratatui is better for data-heavy dashboards that redraw frequently. |
| Crossterm | termion | If you want a simpler API and only target Unix. Crossterm is better because it already works on both platforms and is ratatui's default. |
| Tokio | async-std | Aya supports both, but tokio has far more ecosystem support and is the standard async runtime. No reason to choose async-std. |
| clap | argh (Google) | Only if you need minimal binary size and don't need rich help text. clap is better for user-facing CLI tools. |
| pcap (macOS) | DTrace via FFI | DTrace is powerful but the Rust FFI story is poor, scripting interface is awkward from Rust, and PKTAP via libpcap is simpler and provides process attribution natively. |
| pcap (macOS) | Network Extension Framework | Requires app sandbox, provisioning profiles, and Apple Developer account. Massive overkill for a CLI tool. |
What NOT to Use
| Avoid | Why | Use Instead |
|---|---|---|
| RedBPF | Largely abandoned, last meaningful update 2022. Aya has won the Rust eBPF space. | Aya |
| tui-rs (original) | Deprecated. Ratatui is the maintained fork that the community migrated to in 2023. | Ratatui |
| termion | Doesn't support Windows (not relevant here), but more importantly crossterm is ratatui's default and better maintained. | Crossterm |
| ncurses / pancurses | C dependency, complex linking, less Rust-idiomatic. | Ratatui + Crossterm (pure Rust) |
| raw /proc parsing for all data | Fragile, slow (polling), and misses short-lived connections. | eBPF (event-driven, kernel-level) with /proc as fallback only |
| npcap / WinPcap | Windows only. Out of scope. | pcap (libpcap) for macOS |
| pnet (Rust networking) | Lower-level than needed, doesn't provide PKTAP integration, would require reimplementing what libpcap gives you. | pcap crate |
Stack Patterns by Variant
If Linux-only (no macOS support needed):
- Skip the pcap dependency entirely
- Skip the platform abstraction trait (simplifies architecture)
- Use Aya directly in the main collector module
- This significantly reduces complexity
If macOS is a first-class target:
- Must implement the
NetworkCollectortrait with two backends - macOS backend uses pcap with PKTAP for packet capture + process attribution
- Connection state tracking (TCP states, byte counts) must be done in userspace on macOS since PKTAP gives raw packets, not connection events
- Consider shipping macOS as "monitoring mode" (less kernel integration) vs Linux as "full mode"
If you want to develop eBPF programs from macOS:
- bpf-linker compiles eBPF bytecode on macOS (cross-compilation works)
- But you cannot load/test eBPF programs on macOS -- need a Linux VM or remote machine
- Use Lima or OrbStack for local Linux VM testing on Apple Silicon
Version Compatibility
| Package | Compatible With | Notes |
|---|---|---|
| aya 0.13.x | tokio 1.x | Use features = ["async_tokio"] on aya |
| aya-ebpf 0.1.x | Rust nightly | Must use nightly toolchain with bpfel-unknown-none target |
| ratatui 0.30.x | crossterm 0.28.x+ | Ratatui re-exports crossterm types; check ratatui's Cargo.toml for exact pin |
| bpf-linker | LLVM 21+ | On macOS, brew install llvm and set LLVM_SYS_210_PREFIX |
| pcap 2.3.x | libpcap (system) | Pre-installed on macOS. On Linux, apt install libpcap-dev. |
| clap 4.6.x | serde 1.x | Optional serde integration for config file parsing |
| Rust nightly | aya-ebpf, bpf-linker | Only the eBPF crate needs nightly. Userspace crate can use stable Rust via workspace toolchain override. |
Key Architecture Decisions Driven by Stack
-
Workspace with xtask pattern: Aya projects conventionally split into workspace members (ebpf crate, userspace crate, xtask build tool). Follow this convention -- it is well-documented and the community expects it.
-
Nightly only for eBPF crate: Use
rust-toolchain.tomlat workspace root with nightly, but the userspace code should be written to compile on stable (future-proofing for when aya-ebpf stabilizes). -
Platform abstraction is mandatory: The
NetworkCollectortrait is the most important architectural boundary. Define it early. Linux backend (Aya) produces connection events; macOS backend (pcap/PKTAP) produces raw packets that must be assembled into connection events. -
Async everywhere in userspace: Tokio runtime drives both the eBPF event loop (RingBuf/PerfEventArray polling) and the TUI tick loop. Use
tokio::select!to multiplex between data events and TUI input events. -
Root privilege handling: Both eBPF loading and libpcap capture require elevated privileges. Check at startup, provide clear error message, fail fast.
Confidence Assessment
| Component | Confidence | Rationale |
|---|---|---|
| Aya for eBPF | HIGH | Undisputed leader in Rust eBPF. Active development (0.13.x released recently). No viable alternative. |
| Ratatui for TUI | HIGH | Community standard since tui-rs deprecation. 0.30.x is mature. |
| clap for CLI | HIGH | De facto standard, v4.6 actively maintained. |
| Tokio async runtime | HIGH | Standard async runtime, LTS releases, Aya integration proven. |
| csv crate | HIGH | BurntSushi's csv is the only real option. Mature and stable. |
| pcap + PKTAP for macOS | MEDIUM | PKTAP approach is proven (RustNet uses it), but the pcap crate's PKTAP-specific support is less documented. May need raw header parsing. Needs validation during implementation. |
| bpf-linker on macOS | MEDIUM | Cross-compilation works per docs, but LLVM version pinning can be fragile. CI may need Linux runners for eBPF compilation. |
| Overall macOS parity | MEDIUM-LOW | macOS backend will inherently provide less data than eBPF (no kernel-level TCP state machine hooks). Feature parity is not fully achievable -- must design the abstraction to handle this gracefully. |
Sources
- Aya GitHub repository -- versions, feature set, project structure
- Aya crates.io -- v0.13.x latest release
- Aya documentation -- async features, map types
- Aya book -- development environment setup, bpf-linker installation
- Ratatui official site -- v0.30.x features, no_std support
- Ratatui GitHub -- latest release info
- clap crates.io -- v4.6.0 latest
- Tokio -- LTS release schedule (1.43 until March 2026, 1.47 until Sept 2026)
- csv crate -- v1.4.0 latest
- pcap crate GitHub -- v2.3.x, libpcap bindings
- PKTAP vs eBPF article -- macOS PKTAP approach, process attribution
- RustNet GitHub -- cross-platform network monitoring reference implementation
- Bandix GitHub -- Rust eBPF network monitoring reference
- eBPF with Rust using Aya (blog) -- macOS cross-compilation workflow
- How to Write eBPF Programs in Rust with Aya -- build pipeline details
Stack research for: tcptop -- Rust eBPF network monitoring TUI Researched: 2026-03-21