172 lines
14 KiB
Markdown
172 lines
14 KiB
Markdown
<!-- GSD:project-start source:PROJECT.md -->
|
|
## Project
|
|
|
|
**tcptop**
|
|
|
|
A polished command-line utility that provides a real-time, `top`-like TUI for layer 4 (TCP/UDP) network statistics. It shows per-connection data — bytes, packets, latency, and state — in a sortable table with an aggregate summary header. It also supports CSV logging for offline analysis. Built in Rust using eBPF for kernel-level connection tracing, targeting both macOS and Linux.
|
|
|
|
**Core Value:** Live, accurate, per-connection network visibility from the terminal — the network equivalent of `top`.
|
|
|
|
### Constraints
|
|
|
|
- **Privileges**: Requires root/elevated permissions for kernel tracing — must handle gracefully when not root
|
|
- **Platform divergence**: macOS and Linux have different kernel tracing APIs — architecture must abstract this
|
|
- **Language**: Rust (preferred for performance, safety, and eBPF ecosystem)
|
|
- **Overhead**: Must be low-impact on the system being observed — no heavy polling
|
|
<!-- GSD:project-end -->
|
|
|
|
<!-- GSD:stack-start source:research/STACK.md -->
|
|
## Technology Stack
|
|
|
|
## 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)
|
|
| 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)
|
|
## Installation
|
|
# Prerequisites (Linux)
|
|
# Prerequisites (macOS -- for cross-compiling eBPF or developing userspace)
|
|
# Project dependencies (in workspace Cargo.toml for userspace crate)
|
|
# 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
|
|
- Skip the pcap dependency entirely
|
|
- Skip the platform abstraction trait (simplifies architecture)
|
|
- Use Aya directly in the main collector module
|
|
- This significantly reduces complexity
|
|
- Must implement the `NetworkCollector` trait 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"
|
|
- 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
|
|
## 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](https://github.com/aya-rs/aya) -- versions, feature set, project structure
|
|
- [Aya crates.io](https://crates.io/crates/aya) -- v0.13.x latest release
|
|
- [Aya documentation](https://docs.rs/aya/latest/aya/) -- async features, map types
|
|
- [Aya book](https://aya-rs.dev/book/) -- development environment setup, bpf-linker installation
|
|
- [Ratatui official site](https://ratatui.rs/) -- v0.30.x features, no_std support
|
|
- [Ratatui GitHub](https://github.com/ratatui/ratatui) -- latest release info
|
|
- [clap crates.io](https://crates.io/crates/clap) -- v4.6.0 latest
|
|
- [Tokio](https://tokio.rs/) -- LTS release schedule (1.43 until March 2026, 1.47 until Sept 2026)
|
|
- [csv crate](https://crates.io/crates/csv) -- v1.4.0 latest
|
|
- [pcap crate GitHub](https://github.com/rust-pcap/pcap) -- v2.3.x, libpcap bindings
|
|
- [PKTAP vs eBPF article](https://domcyrus.github.io/systems-programming/networking/ebpf/macos/linux/2025/01/18/pktap-vs-ebpf-network-process-identification.html) -- macOS PKTAP approach, process attribution
|
|
- [RustNet GitHub](https://github.com/domcyrus/rustnet) -- cross-platform network monitoring reference implementation
|
|
- [Bandix GitHub](https://github.com/beijixi/bandix) -- Rust eBPF network monitoring reference
|
|
- [eBPF with Rust using Aya (blog)](https://www.galiglobal.com/blog/2025/20251119-ebpf-rust-aya.html) -- macOS cross-compilation workflow
|
|
- [How to Write eBPF Programs in Rust with Aya](https://oneuptime.com/blog/post/2026-01-07-ebpf-rust-aya/view) -- build pipeline details
|
|
<!-- GSD:stack-end -->
|
|
|
|
<!-- GSD:conventions-start source:CONVENTIONS.md -->
|
|
## Conventions
|
|
|
|
Conventions not yet established. Will populate as patterns emerge during development.
|
|
<!-- GSD:conventions-end -->
|
|
|
|
<!-- GSD:architecture-start source:ARCHITECTURE.md -->
|
|
## Architecture
|
|
|
|
Architecture not yet mapped. Follow existing patterns found in the codebase.
|
|
<!-- GSD:architecture-end -->
|
|
|
|
<!-- GSD:workflow-start source:GSD defaults -->
|
|
## GSD Workflow Enforcement
|
|
|
|
Before using Edit, Write, or other file-changing tools, start work through a GSD command so planning artifacts and execution context stay in sync.
|
|
|
|
Use these entry points:
|
|
- `/gsd:quick` for small fixes, doc updates, and ad-hoc tasks
|
|
- `/gsd:debug` for investigation and bug fixing
|
|
- `/gsd:execute-phase` for planned phase work
|
|
|
|
Do not make direct repo edits outside a GSD workflow unless the user explicitly asks to bypass it.
|
|
<!-- GSD:workflow-end -->
|
|
|
|
|
|
|
|
<!-- GSD:profile-start -->
|
|
## Developer Profile
|
|
|
|
> Profile not yet configured. Run `/gsd:profile-user` to generate your developer profile.
|
|
> This section is managed by `generate-claude-profile` -- do not edit manually.
|
|
<!-- GSD:profile-end -->
|