ebpfdev / explorer

eBPF explorer is Web UI that lets you see all the maps and programs in eBPF subsystem

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

eBPF explorer

eBPF is a web UI that lets you explore eBPF subsystem of your Linux host.

Explorer consists of two parts: an agent with GraphQL API, Prometheus scrape endpoint, and a web interface. It is currently shipped as a single container. But you can also run them separately.

Features

  • view all maps and programs
  • view graph of interconnected maps and programs
  • view program's tracepoints/kprobe
  • map entries table (Hash, HashPerCPU, Array, ArrayPerCPU)
    • view and edit in number/hex/string formats
  • expose map entries as metrics for prometheus (also other useful metrics)

map editor demo gif

Usage

Run explorer as a container:

docker run -ti --rm -p 8070:80 \
  --cap-add CAP_SYS_ADMIN --pid=host \
  -e BPF_DIR=/sys/fs/bpf -v /sys/fs/bpf:/sys/fs/bpf \
  ghcr.io/ebpfdev/explorer:v0.0.7

Privileges breakdown:

  • --cap-add CAP_SYS_ADMIN (required)

    is needed for access BPF maps and programs (CAP_BPF is not yet enough)

  • --pid=host (optional)

    is needed to determine tracepoint/kprobe attachment

  • -e BPF_DIR=/sys/fs/bpf -v /sys/fs/bpf:/sys/fs/bpf (optional)

    is needed to determine paths of pinned maps, it is better to keep BPF_DIR (and target mount path) the same as your original eBPF FS, which can be determined with the following command:

    $ mount | grep bpf
    bpf on /sys/fs/bpf type bpf

Use --etm option to expose map (with name AT_) entries values to Prometheus endpoint:

docker run -ti --rm -p 8070:80 \
  --cap-add CAP_SYS_ADMIN --pid=host \
  -e BPF_DIR=/sys/fs/bpf -v /sys/fs/bpf:/sys/fs/bpf \
  ghcr.io/ebpfdev/explorer:v0.0.7 --etm -:AT_:string

If you only need GraphQL / Prometheus without web interface, you can run agent independently:

docker run -ti --rm -p 8080:8080 \
  --cap-add CAP_SYS_ADMIN --pid=host \
  -e BPF_DIR=/sys/fs/bpf -v /sys/fs/bpf:/sys/fs/bpf \
  ghcr.io/ebpfdev/dev-agent:v0.0.5 server

Links:

Demo

Run the explorer as described above and open http://localhost:8070 in your browser.

You should see a file tree view with a list of eBPF programs and maps:

List of maps

Let's use bpftrace to track amount of data read by each process:

$ sudo bpftrace -e 'tracepoint:syscalls:sys_exit_read /args->ret/ { @[comm] = sum(args->ret); }'
Attaching 1 probe...

Once you run it, list will be automatically updated:

A list of maps containing two new maps

...

A list of programs with the new sys_exit_read

Let's examine the sys_exit_read program:

sys_exit_read program page

We can see that this new program is using a new map called AT_. Which probably means that it contains state of @ variable of the program generated by bpftrace.

There is also printf map of type PerfEventArray. It is probably used by printf() invocation within bpftrace programs and created regardless of whatever you actually use it or not: out program doesnt use it therefore we also don't see that is used by the program in UI.

We can proceed to the AT_ map page:

Page of the AT map

On the Entries subpage we can examine current state of the map:

Entries table of the AT map state

Values are formatted as numbers by default if value size <= 8 bytes. Otherwise, they are displayed as hex strings.

We can also switch KEY representation to string:

Entries table of the AT map state with string keys

Prometheus scrape endpoint

There is a scrape endpoint for Prometheus available at /metrics path:

% curl http://localhost:8070/metrics
# HELP devagent_ebpf_map_count Number of eBPF maps
# TYPE devagent_ebpf_map_count gauge
devagent_ebpf_map_count{type="Hash"} 5
devagent_ebpf_map_count{type="PerCPUHash"} 1
devagent_ebpf_map_count{type="PerfEventArray"} 1
# 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="14",name="AT_",type="PerCPUHash"} 351
# 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="14",key="(xtract-3)",name="AT_",type="PerCPUHash"} 0
devagent_ebpf_map_entry_value{cpu="0",id="14",key="000resolvconf",name="AT_",type="PerCPUHash"} 0
# (...)
devagent_ebpf_map_entry_value{cpu="15",id="14",key="01-ifupdown",name="AT_",type="PerCPUHash"} 0
# (...)
# HELP devagent_ebpf_prog_count Number of eBPF programs
# TYPE devagent_ebpf_prog_count gauge
devagent_ebpf_prog_count{type="CGroupDevice"} 19
devagent_ebpf_prog_count{type="CGroupSKB"} 10
devagent_ebpf_prog_count{type="TracePoint"} 1
# HELP devagent_ebpf_prog_run_count Number of times an eBPF program has been run
# TYPE devagent_ebpf_prog_run_count gauge
devagent_ebpf_prog_run_count{id="112",name="",tag="03b4eaae2f14641a",type="CGroupDevice"} 0
devagent_ebpf_prog_run_count{id="113",name="",tag="03b4eaae2f14641a",type="CGroupDevice"} 0
devagent_ebpf_prog_run_count{id="114",name="",tag="03b4eaae2f14641a",type="CGroupDevice"} 54
devagent_ebpf_prog_run_count{id="118",name="sys_exit_read",tag="90964a143ba6aa2c",type="TracePoint"} 2.866732e+06
devagent_ebpf_prog_run_count{id="127",name="",tag="3918c82a5f4c0360",type="CGroupDevice"} 7
# (...)
# HELP devagent_ebpf_prog_run_time Total time spent running eBPF programs
# TYPE devagent_ebpf_prog_run_time gauge
devagent_ebpf_prog_run_time{id="112",name="",tag="03b4eaae2f14641a",type="CGroupDevice"} 0
devagent_ebpf_prog_run_time{id="113",name="",tag="03b4eaae2f14641a",type="CGroupDevice"} 0
devagent_ebpf_prog_run_time{id="114",name="",tag="03b4eaae2f14641a",type="CGroupDevice"} 6.857e-05
devagent_ebpf_prog_run_time{id="118",name="sys_exit_read",tag="90964a143ba6aa2c",type="TracePoint"} 1.405393686
devagent_ebpf_prog_run_time{id="127",name="",tag="3918c82a5f4c0360",type="CGroupDevice"} 2.314e-06
# (...)

By default, metrics devagent_ebpf_map_entry_count and devagent_ebpf_map_entry_value are disabled. To enable them for some of the maps (Array or Hash types), use --etm option, for the demo above:

docker run -ti --rm -p 8070:80 \
  --cap-add CAP_SYS_ADMIN --pid=host \
  -e BPF_DIR=/sys/fs/bpf -v /sys/fs/bpf:/sys/fs/bpf \
  ghcr.io/ebpfdev/explorer:v0.0.7 --etm -:AT_:string

Run with --help to see details of this option:

% docker run -ti --rm ghcr.io/ebpfdev/explorer:v0.0.7 --help               

  (edited)

   --entries-to-metrics value, --etm value [ --entries-to-metrics value, --etm value ]  (experimental, api may change)
    Configure which map entries should be exposed as metrics, in the format: id_start-id_end:metric_name_regexp:key_format.
    Example: '-:.+:string' to export any map with non-empty name while treating key as string.
    or '10-:.*:hex' to export any map after ID 10 with key represented in HEX format
    Available key formats: string, number, hex
    If a map matches multiple entries, the first one is used.

  (edited)

Some interesting visualization you could build with this data:

Programs run statistics: 07-grafana-ebpf.png

Amount of system calls per process: 08-grafana-syscallnum.png

Features

  • list of eBPF programs + details page

  • list of eBPF maps + details page

  • showing bounded maps of a programs (and vice versa)

  • showing map content

    • Hash (+ per CPU)
    • Array (+ per CPU)
    • others are planned
  • program introspection

    • eBPF bytecode
    • JIT disassembly
  • visualization of map's content

    Like plotting a chart of values of maps keys

  • program execution profiling

    I plan to keep track of duration/number of executions of a programs provided by kernel to draw nice charts

  • cluster support

    To traverse over a cluster of agents within a single interface

Feedback and suggestions are welcome in GitHub Issues or via alex@hsslb.ch

About

eBPF explorer is Web UI that lets you see all the maps and programs in eBPF subsystem


Languages

Language:Dockerfile 68.6%Language:Shell 31.4%