Skip to content

TC, XDP, KProbe and CGroup eBPF based simple Ethernet interface traffic monitor and reporting tool

License

Notifications You must be signed in to change notification settings

dkorunic/pktstat-bpf

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

128 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pktstat-bpf

GitHub license GitHub release

About

pktstat-bpf is a lightweight replacement for the ncurses/libpcap-based pktstat, powered by a Linux eBPF (extended Berkeley Packet Filter) program. It is capable of gathering packet statistics even under very high traffic volumes — typically several million packets per second on an average server. In high-volume scenarios such as DoS attacks, traditional packet capture solutions often become unreliable due to increasing packet loss, making eBPF-based capture a more robust alternative.

At the end of execution, the program displays per-IP and per-protocol statistics sorted by per-connection bps, packet counts, and (source-IP:port, destination-IP:port) tuples.

The program consists of eBPF code written in C and a pure-Go userland component that parses and outputs final IP/port/protocol/bitrate statistics. The Go component uses the cilium/ebpf library to load and run the eBPF program and to interface with the eBPF map.

By default, the eBPF component uses TC (Traffic Control) eBPF hooks with TCX attaching, requiring at minimum Linux kernel v6.6, and collects both ingress and egress traffic statistics for TCP, UDP, ICMPv4, and ICMPv6. It can also switch to the faster XDP (eXpress Data Path) hook, at the cost of losing egress statistics since XDP operates only in the ingress path. XDP mode requires at minimum Linux kernel v5.9 due to its program-to-interface attachment calls. Some distributions (notably Red Hat Enterprise Linux) have backported XDP/TC patches, so the eBPF program may work on older kernels as well (see Requirements for details).

Alternatively, the tool can use KProbes to monitor TCP, UDP, ICMPv4, and ICMPv6 traffic across all containers, Kubernetes pods, NAT translations, and forwarded flows. In this mode, it also displays the process ID, process name, and cgroup path for traffic sent or delivered to a userspace application. KProbes operate closest to userspace and therefore have the highest overhead, but they provide uniquely useful process-level visibility. KProbes support older Linux kernels as well, with the hard dependency being a BTF-enabled kernel. The program resolves kernel-level cgroup IDs to cgroup paths (under /sys/fs/cgroup) by scanning the cgroup filesystem and consuming kernel cgroup mkdir events via dedicated eBPF code.

It is also possible to monitor a specific cgroup directly, with full support for both ingress and egress traffic. You can monitor all traffic by attaching to the root cgroup (e.g. /sys/fs/cgroup). Process tracking is available in cgroup mode, but only for traffic whose socket creation was observed by pktstat-bpf. Demo

Talks

The author has given several eBPF talks, available below along with the accompanying slides:

  • A shorter overview of eBPF features, capabilities, and implementation (35 minutes):

DORS/CLUC 2025: eBPF

  • A longer deep dive into eBPF features, capabilities, implementation, and security (~45 minutes, in Croatian):

DEEP 2024: eBPF: Features, capabilities and implementation

Requirements

The hard requirement for the eBPF program is Linux kernel 4.10 with BTF enabled; on such older kernels, KProbes will likely be the only supported mode (e.g. RHEL/CentOS 8, Debian 10). From kernel 5.9 onwards (RHEL/CentOS 9, Debian 11, Ubuntu 20.04), XDP mode is supported. TC may work as early as 5.14 (RHEL/CentOS 9) if the distribution has backported TC eBPF patches. On all recent distributions (RHEL/CentOS 9, Debian 12, Ubuntu 24.04), all eBPF modes are fully supported.

Loading eBPF programs typically requires root privileges. Additionally, pointer arithmetic in the eBPF code causes the eBPF verifier to reject non-root use explicitly. The kernel must have BTF enabled, and certain features require more recent kernels, as shown in the table below.

BPF JIT (Just-In-Time compilation) should be enabled for best performance (most Linux distributions enable this by default):

sysctl -w net.core.bpf_jit_enable=1

In XDP mode, not all NIC drivers support Native XDP (where the XDP program is loaded by the NIC driver as part of the initial receive path; most common 10G drivers already support this) or Offloaded XDP (where the XDP program runs directly on the NIC hardware without using the CPU). If native or offloaded XDP is unavailable, the kernel falls back to Generic XDP, which offers reduced performance. Generic XDP requires no special NIC driver support, but operates much later in the networking stack, making its performance roughly equivalent to TC hooks.

The following table maps capture modes to their requirements and expected performance:

Capture type Ingress Egress Performance Process tracking Kernel required SmartNIC required
Generic PCAP Yes Yes Low No Any No
AF_PACKET Yes Yes Medium No v2.2 No
KProbes Yes Yes Medium+ Yes (command, process ID, cgroup path) v4.10 No
Cgroup (SKB) Yes Yes Medium+ Partial (command, process ID) v4.10 No
TC (SchedACT) Yes Yes High No v6.6 No
XDP Generic Yes No High No v5.9 No
XDP Native Yes No Very high No v5.9 No
XDP Offloaded Yes No Wire speed No v5.9 Yes

Lists of XDP-compatible drivers:

Usage

NAME
  pktstat-bpf

FLAGS
  -?, --help               display help
  -j, --json               if true, output in JSON format
  -c, --cgroup STRING      the path to a CGroup V2 to measure statistics on
  -x, --xdp                if true, use XDP instead of TC (this disables egress statistics)
  -k, --kprobes            if true, use KProbes for per-process TCP/UDP statistics
  -g, --tui                if true, enable TUI
      --version            display program version
  -i, --iface STRING       interface to read from (default: anpi4)
      --xdp_mode STRING    XDP attach mode (auto, generic, native or offload; native and offload require NIC driver support) (default: auto)
  -r, --refresh DURATION   refresh interval in TUI (default: 1s)
  -t, --timeout DURATION   timeout for packet capture in CLI (default: 10m0s)

Use --iface to specify the network interface to capture on.

--timeout stops the program after the specified duration. You can also interrupt it at any time with Ctrl-C, SIGTERM, or SIGINT.

--tui switches to a simple interactive TUI designed for continuous monitoring. Use the arrow keys to navigate the statistics table, and press q or x to exit.

--json outputs traffic statistics in JSON format.

--xdp switches from TC eBPF mode to XDP eBPF mode for higher performance, at the cost of disabling egress statistics. Note that the program may reset the interface on exit, so it is recommended to run it inside screen or tmux.

--xdp_mode overrides the XDP attach mode from the default auto (best-effort between native and generic) to native or offload, for NIC drivers or hardware that support those modes.

--kprobes switches to KProbe mode to track TCP and UDP traffic per process. Performance is lower compared to TC and XDP modes, but all per-process traffic is visible across all cgroups, containers, and Kubernetes pods. Additional details such as process command name, process ID, and control group are displayed.

--cgroup <path> measures ingress and egress traffic for the specified control group. Process command name and process ID are displayed when available.

Star History

Star History Chart

Packages

 
 
 

Contributors 2

  •  
  •