A real-time web dashboard for visualizing eBPF programs running on a Linux kernel. The visualizer polls bpftool every 5 seconds and renders kernel attachment zones, network interfaces with OSI layers, cgroup hierarchies, a network-namespace topology graph, an interactive OS Map canvas, snapshot diffing, and a Code Inspector with BPF bytecode and control-flow graphs.
No database. No authentication. No external services required.
The visualizer provides nine distinct views, each designed to answer a different question about the BPF programs running on a system.
| View | Description |
|---|---|
| Dashboard | Summary statistics, program type breakdown, orphaned program alerts, recently loaded programs, and runtime activity charts |
| Kernel | Attachment points organized by hook type — XDP, TC, Netfilter, Socket Filter, kprobe/fentry, Tracepoint, Perf Event, Cgroup Hooks, and more |
| Network | Physical and virtual NICs with BPF programs grouped by OSI layer (L2–L7), including TC chain order and sockmap interfaces |
| Topology | Network-namespace connectivity graph — host, container, and pod namespaces wired by veth/netkit pairs, with BPF programs attributed per interface |
| Cgroups | Full cgroup hierarchy tree showing which BPF programs are attached at each node, with shared-bytecode color coding |
| Programs | Sortable, filterable table of all loaded programs with live calls/sec sparklines, avg latency, CPU%, flags (JIT/GPL/BTF), relative load time, and a time scrubber to rewind stats across the recent history ring |
| Maps | BPF map inventory with key/value sizes, live entry counts, locked memory, and an interactive entry dump viewer with JSON/CSV export |
| Diff | Side-by-side comparison of two captured snapshots — programs, maps, and map entries added, removed, or changed between them |
| OS Map | Interactive ReactFlow canvas showing the entire kernel topology — kernel zones, cgroup tree, network interfaces, and BPF maps — in a single scrollable diagram |
| Mode | How it works | When to use |
|---|---|---|
| Live | Polls bpftool every 5 s via Server-Sent Events |
Running directly on the target Linux host |
| Demo | Synthetic mock data with 28 realistic programs | Exploring the UI without a Linux host |
| Snapshot | Uploaded JSON file captured by scripts/capture-snapshot.sh |
Inspecting production data on a local machine |
The main dashboard provides a high-level summary of the BPF subsystem. The orphaned program banner alerts you when a program has no owning process — a common indicator of a leaked program whose loader exited unexpectedly. The Recently Loaded sidebar shows programs sorted by load time with relative timestamps.
The Kernel view organizes programs by hook type within a stylized Linux kernel diagram. The Packet Processing Path shows the canonical XDP → TC Ingress → Netfilter → Socket Filter → TC Egress pipeline. Each zone card displays a live sparkline of call rate activity, and zones glow with color intensity proportional to CPU heat.
The Network view groups programs by interface and OSI layer. TC classifiers are shown in chain order with a warning when a short-circuit action can prevent downstream programs from running. Sockmap interfaces (sk_msg, sk_skb, sock_ops, sk_lookup) appear in a separate section below the NIC list.
The Topology view shows how network namespaces are wired together by veth/netkit device pairs — host, containers, and pods. Solid boxes were scanned directly; dashed boxes are peers inferred from a device pair. BPF programs are attributed to the interface they are attached to, and ambiguous attributions are marked with (?).
The Cgroups view renders the full /sys/fs/cgroup tree. Programs with identical compiled bytecode (same BPF tag) share a color dot — hovering reveals the tag hash and the list of cgroups that share it. Attach types are shown as labeled chips, and each cgroup node can be expanded or collapsed.
The Programs table lists every loaded BPF program with live runtime statistics. The type filter chips let you narrow to a specific program type. The Orphaned only chip (shown in red when orphaned programs exist) filters to programs whose owning process has exited. Each row includes a sparkline of calls/sec, average execution latency, CPU utilization percentage, and the relative time since the program was loaded.
The Maps view shows every BPF map with its type, key/value sizes, live entry count, and locked memory. Maps are categorized as Data, Event, or Socket. Dump Entries opens a modal with the full map contents, interpreted key/value pairs, and JSON/CSV export. Maps that cannot be iterated (ringbuf, perf_event_array) show a "Not dumpable" indicator.
The Diff view compares two captured snapshot files side by side. Programs are matched by name + bytecode and maps by name + type; added, removed, and changed entries are color-coded. Attaching a map-dump file to each side also diffs map contents key-by-key.
The OS Map is a zoomable, pannable canvas that renders the entire kernel topology in one view. The Cgroup depth slider in the toolbar controls how many levels of the cgroup tree are rendered — nodes at the depth limit show a dashed badge indicating how many descendants are collapsed. The Download button exports the current topology as a re-uploadable snapshot JSON.
After loading a snapshot file, the toolbar switches to SNAPSHOT mode. The filename, capture timestamp, and a Load Map Dumps button appear in the top bar. The sidebar shows the snapshot hostname and kernel version. All views render the snapshot data identically to live mode. Click the × next to the filename to return to Live or Demo mode.
The standalone tarball bundles the compiled frontend and Express server into a single archive. The target machine needs only Node.js ≥ 16.5 — no npm, no Docker, no internet access.
1. Download the latest release:
# Download from the GitHub Releases page
curl -LO https://github.com/mykola-lysenko/ebpf-viz/releases/download/latest/ebpf-viz-standalone.tar.gz2. Extract and start:
tar -xzf ebpf-viz-standalone.tar.gz
cd standalone
sudo ./start.sh # sudo required for bpftool accessOpen http://localhost:3000 in your browser.
Demo mode (no bpftool required):
DEMO_MODE=1 ./start.shSee DEPLOY.md for systemd service configuration, nginx reverse proxy setup, and environment variable reference.
git clone https://github.com/mykola-lysenko/ebpf-viz.git
cd ebpf-viz
pnpm install
# Live mode (requires bpftool + root)
sudo pnpm dev
# Demo mode (no kernel required)
DEMO_MODE=true pnpm dev| Dependency | Version | Notes |
|---|---|---|
| Linux kernel | ≥ 5.1 | For run_time_ns/run_cnt stats; ≥ 4.15 for basic operation |
| Node.js | ≥ 16.5 standalone runtime; ≥ 22 development/build | Corp devservers can run the standalone bundle on Node 16 |
| pnpm | ≥ 10 | npm install -g pnpm |
| bpftool | ≥ 7.x | See INSTALL.md for build instructions |
| sudo | any | The server calls sudo bpftool; configure sudoers accordingly |
See INSTALL.md for full installation instructions including bpftool build from source, sudoers configuration, and distribution-specific notes.
To see calls/sec, avg latency, and CPU% per program, enable BPF stats on the host:
# Immediate (lost on reboot)
sudo sysctl -w kernel.bpf_stats_enabled=1
# Persistent across reboots
echo 'kernel.bpf_stats_enabled=1' | sudo tee /etc/sysctl.d/90-bpf-stats.conf
sudo sysctl -p /etc/sysctl.d/90-bpf-stats.confThe visualizer attempts to enable this sysctl automatically at startup when it has the necessary permissions. Stats only accumulate after the sysctl is set — programs loaded before that point will show zero until they are reloaded.
The snapshot workflow lets you capture a point-in-time view of BPF programs from a production server and visualize it on your local machine — without installing the full eBPF Viz on the production host.
Use the dev VM relay to run scripts/capture-snapshot.sh on the production server and stream the result back locally. The target-side script requires only bash and bpftool — no jq, Python, or Node.js.
# Basic snapshot (programs, maps, network, cgroups)
scripts/devvm-collect-prod-bpf.sh <devvm> <prod-host> --snapshot
# With map contents (larger file, requires bpftool map dump)
scripts/devvm-collect-prod-bpf.sh <devvm> <prod-host> --snapshot --dump-mapsThe relay writes files under captures/ by default:
<target>-snapshot-<YYYYMMDD-HHMMSS>.json— topology snapshot (~0.3 MB typical)<target>-snapshot-<YYYYMMDD-HHMMSS>-mapdumps.json— map entry contents (size varies; only with--dump-maps)
Map dump files preserve raw map entries when feasible; unsupported map types are skipped, and the UI displays up to 1000 entries per map while preserving total entry counts.
ls captures/*snapshot*.json
# Optional map dumps are written next to the snapshot as *-mapdumps.json.- Open eBPF Viz in your browser.
- Click Load Snapshot (folder icon) in the top-right toolbar.
- Select the
*snapshot*.jsonfile. - The UI switches to Snapshot mode — a
SNAPSHOTbadge appears with the capture timestamp and hostname. - Optionally, click Load Map Dumps to load the companion
*-mapdumps.jsonfile, which enables the Dump Entries button on each map card.
{
"_ebpfVizSnapshot": true,
"capturedAt": "2026-03-12T15:11:00Z",
"hostname": "myserver",
"kernelVersion": "6.8.0-51-generic",
"bpftoolVersion": "7.4.0",
"raw": {
"progs": [ ... ],
"maps": [ ... ],
"net": [ ... ],
"cgroups": [ ... ]
}
}Snapshots exported via the Download Topology JSON button in the OS Map toolbar carry the same _ebpfVizSnapshot: true marker and can be re-uploaded directly, but store the pre-parsed snapshot model rather than raw bpftool output.
All settings are provided as environment variables (or in a .env file). No database URL, auth tokens, or API keys are required.
| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
HTTP listen port |
HOST |
127.0.0.1 |
Interface to bind on. Loopback-only by default; set 0.0.0.0 or :: to allow remote access |
BPFTOOL_PATH |
auto-detected | Absolute path to the bpftool binary |
DEMO_MODE |
false |
Use synthetic mock data instead of live bpftool |
POLL_INTERVAL_MS |
5000 |
Polling interval in milliseconds (1000–60000) |
BPF_STATS_ENABLED |
auto | Set to 0 to skip enabling BPF runtime stats at startup |
ADMIN_TOKEN |
unset | Optional token for remote access to config changes and bpftool-heavy endpoints; loopback requests are always allowed |
EBPF_VIZ_ALLOWED_HOSTS |
unset | Extra hostnames accepted by the Host-header guard (comma-separated) — required when serving behind a reverse proxy or a non-localhost hostname |
Remote access: the server binds to loopback by default so an accidental run never exposes kernel BPF state to the network. To reach the dashboard from another machine, set
HOST=0.0.0.0(or::) and add the hostname you browse to viaEBPF_VIZ_ALLOWED_HOSTS.
# Install dependencies
pnpm install
# Start dev server (with hot reload)
DEMO_MODE=true pnpm dev
# Run tests
pnpm test
# Type check and lint
pnpm check
pnpm lint
# Build standalone tarball
bash build-standalone.sh
# Build, deploy to a dev VM, restart the app, and open an SSH tunnel.
# Use bash directly because pnpm 10 requires Node >= 18 to start.
bash scripts/devvm-standalone.sh user@devvm.example.comclient/
src/
pages/ <- Page-level components (Dashboard, KernelView, etc.)
components/ <- Reusable UI components (OsMapCanvas, MapEntriesModal, etc.)
contexts/ <- EbpfContext (snapshot state, demo/live/snapshot mode)
lib/ <- Utilities (time formatting, tRPC client)
server/
ebpf-poller.ts <- bpftool polling and SSE stream
ebpf-parser.ts <- Raw bpftool output -> EbpfSnapshot model
ebpf-mock.ts <- Synthetic demo data generator
routers.ts <- tRPC procedures (snapshot, maps, programs, etc.)
shared/
ebpf-types.ts <- Shared TypeScript types
scripts/
capture-snapshot.sh <- Production snapshot capture script
build-standalone.sh <- Standalone tarball builder
The test suite uses Vitest for unit tests:
pnpm test # run all tests
pnpm test --watch # watch modeGitHub Actions runs ci.yml on pull requests and pushes to main. It validates Node 22 audit/typecheck/lint/test/build and builds the standalone package, then smoke-tests it on Node 16. The release.yml workflow publishes a rolling latest standalone tarball from main only after the same standalone runtime audit and smoke test pass.
Demo mode shows instead of live data
bpftool was not accessible when the server started, so it fell back to demo mode. Check the server log for the reason. Common causes: bpftool not found at BPFTOOL_PATH, sudo permission denied, or kernel too old (< 4.15). Poll errors after startup do not switch to demo mode — the server keeps serving the last good snapshot and reports the error in the poller status.
bpftool: command not found
Install bpftool for your distribution:
| Distribution | Install command |
|---|---|
| Fedora / RHEL 9+ | sudo dnf install bpftool |
| Debian / Ubuntu | sudo apt install linux-tools-common linux-tools-$(uname -r) |
| Arch Linux | sudo pacman -S bpf |
Or build from source — see INSTALL.md.
Permission denied reading BPF maps
The server must run as root or with CAP_BPF + CAP_SYS_ADMIN. Use sudo ./start.sh or configure a sudoers entry — see INSTALL.md for details.
"Not a valid eBPF Viz snapshot file" error
The uploaded file must have "_ebpfVizSnapshot": true at the top level. Use scripts/capture-snapshot.sh to generate the file, or export a topology from the OS Map's Download button.









