This agent provides access to system's eBPF-programs and maps to perform remote debugging.
Features:
- GraphQL model for maps and programs
- Prometheus metrics exporter (including values of maps entries)
See also CHANGELOG.
sudo ./phydev server [--help]GraphQL interface: http://localhost:8080/
Prometheus endpoint: http://localhost:8080/metrics
Schema: pkg/graph/schema.graphqls
Metrics scrape endpoint for Prometheus: http://localhost:8080/metrics
- program metrics:
devagent_ebpf_prog_count- number of eBPF programs bytype- runtime metrics only available with
sysctl -w kernel.bpf_stats_enabled=1:devagent_ebpf_prog_run_count- number of times an eBPF program has been run (byid,name,tag,type)devagent_ebpf_prog_run_time- total time spent running eBPF programs (byid,name,tag,type)
- map metrics:
devagent_ebpf_map_count- number of eBPF maps bytype- if map export is configured (see below):
devagent_ebpf_map_entry_count- number of entries in an eBPF map (byid,name,type)devagent_ebpf_map_entry_value- value of an eBPF map entry (bykey,cpu,id,name,type)
You can find example of Grafana dashboard in grafana-ebpf-dashboard.json:

As an example, I'm running this bpftrace program:
sudo bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @SYSCALLNUM[comm] = count(); }'You could see the name of created map - AT_SYSCALLNUM, and the map content in ebpf-explorer:

By default, dev-agent doesn't export map entries to Prometheus, as it may introduce some performance issues.
Instead, you could set an option --etm -:AT_SYSCALLNUM:string when running server, which will suggest agent which map entries to expose in /metrics.
For this HASH_PER_CPU map, it will export 2 metrics:
# HELP devagent_ebpf_map_entry_count Number of entries in an eBPF map
# TYPE devagent_ebpf_map_entry_count gauge
devagent_ebpf_map_entry_count{id="25",name="AT_SYSCALLNUM",type="PerCPUHash"} 764
# HELP devagent_ebpf_map_entry_value Value of an eBPF map entry
# TYPE devagent_ebpf_map_entry_value gauge
devagent_ebpf_map_entry_value{cpu="0",id="25",key="(anacron)",name="AT_SYSCALLNUM",type="PerCPUHash"} 0
devagent_ebpf_map_entry_value{cpu="0",id="25",key="(fprintd)",name="AT_SYSCALLNUM",type="PerCPUHash"} 0
This is how it may look in Grafana (top 10 processes doing most of syscalls):

Full demo in terminal:
sudo bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @SYSCALLNUM[comm] = count(); }' &
docker run -ti --rm --cap-add CAP_SYS_ADMIN --pid=host -v /sys/fs/bpf:/sys/fs/bpf --pid=host -p 8080:8080 ghcr.io/ebpfdev/dev-agent:v0.0.4 server --etm -:AT_SYSCALLNUM:string
curl http://localhost:8080/metrics | grep devagent_ebpf_map_entry_countRun ./phydev server --help for more details on this flag.
These are just for debugging purpose, use bpftool instead
List loaded eBPF programs:
sudo ./phydev inspect progs list
> ID Type Tag RunCount RunTime AvgRunTime
> 3 CGroupDevice e3dbd137be8d6168 0 0s 0s
> 4 CGroupSKB 6deef7357e7b4530 0 0s 0s
> 125 uprobe__BIO_new Kprobe 0d9ea14e5516f975 0 0s 0s
> 126 socket__http_fi SocketFilter 6b7ab673cb23d3f0 0 0s 0s
> 127 kretprobe__do_s Kprobe 154f35d6575c73f9 0 0s 0s
> 128 uretprobe__SSL_ Kprobe 8737d2e349595de3 0 0s 0sList loaded eBPF maps:
% sudo ./phydev inspect maps list
ID Name FD Type Flags IsPinned KeySize ValueSize MaxEntries
1 3 Hash 0 false 9 1 500
2 4 Hash 0 false 9 1 500
44 do_sendfile_arg 10 Hash 0 false 8 8 1024
61 http_in_flight 27 Hash 0 false 48 112 10000
62 http_notificati 28 PerfEventArray 0 false 4 4 16
63 open_at_args 29 Hash 0 false 8 128 1024Instead of ./phydev server, use docker command:
docker run -ti --rm --cap-add CAP_SYS_ADMIN --pid=host -e BPF_DIR=/sys/fs/bpf -v /sys/fs/bpf:/sys/fs/bpf -p 8080:8080 ghcr.io/ebpfdev/dev-agent:v0.0.4 serverRequired:
--cap-add CAP_SYS_ADMINis needed for access BPF maps and programs (CAP_BPF is not yet enough to list existing maps and programs)
Optional:
-
--pid=hostis needed to determine tracepoint/kprobe attachment, if you skip it, you won't see what tracepoint/kprobe a program is attached to:
-
-e BPF_DIR=/sys/fs/bpf -v /sys/fs/bpf:/sys/fs/bpfis needed to determine pinned maps (they will be resolved relative toBPF_DIRtough, so it's better to mount it to the same path) if you skip it, you won't see maps pinned path, and it won't be possible to pin new maps:
go build -o phydev cmd/dev-agent/main.goThis will update GraphQL code and some other constants:
go install golang.org/x/tools/cmd/stringer@latest
go generate ./...