Skip to main content

Bpf userspace program example with wasm_bpf plug-in

There is a WasmEdge plug-in called wasm_bpf, which provided APIs to perform operations on eBPF program, such as loading, attaching and polling.

The detailed description can be found at

Here we will provide several examples to demonstrate the wasm_bpf plug-in.


For simplicity, we will reuse the Makefile of wasm-bpf, since wasmEdge_bpfPlugin has the precisely same API as wasm-bpf

  1. Clone the wasm-bpf repo.
  2. Run make install-deps and make /opt/wasi-sdk at the project's root. This will install the build prerequisites.
  3. Install WasmEdge
  4. Build and install the wasm_bpf plug-in. Currently, we have to build wasm_bpf plug-in manually. The building instructions could be found at

The bootstrap example

bootstrap is a simple eBPF program to track the entry and exit of all processes. It will print a line of message when there is an entry of an exiting event of a process.

Run make in wasm-bpf/examples/bootstrap, and you will find the bootstrap.wasm, which can be executed by WasmEdge.

WASMEDGE_PLUGIN_PATH=./build/plugins/wasm_bpf/ wasmedge bootstrap.wasm

WASMEDGE_PLUGIN_PATH should be changed due to your build directory of the plug-in.

Example output:

13:38:00 EXEC bash 121487 40189 /usr/bin/bash
13:38:00 EXEC groups 121489 121487 /usr/bin/groups
13:38:00 EXIT groups 121489 121487 [0] (3ms)
13:38:00 EXEC lesspipe 121490 121487 /usr/bin/lesspipe
13:38:00 EXEC basename 121491 121490 /usr/bin/basename
13:38:00 EXIT basename 121491 121490 [0] (8ms)
13:38:00 EXEC dirname 121493 121492 /usr/bin/dirname
13:38:00 EXIT dirname 121493 121492 [0] (1ms)
13:38:00 EXIT lesspipe 121492 121490 [0]

Details of bootstrap

bootstrap was created in a similar spirit as libbpf-tools from BCC package but is designed to be more stand-alone and with a simpler Makefile to simplify adoption to users' particular needs. It demonstrates the use of typical BPF features:

Cooperating BPF programs (tracepoint handlers for process exec and exit events, in this particular case); BPF map for maintaining the state; BPF ring buffer for sending data to userspace; global variables for application behavior parameterization. It utilizes BPF CO-RE and vmlinux.h to read extra process information from kernel's struct task_struct.

Some code snippets

A bpf program from bootstrap.bpf.c. It tracks the execution of processes, wraps the event in a struct, and sends the struct to the userspace program through ringbuf.

int handle_exec(struct trace_event_raw_sched_process_exec* ctx) {
struct task_struct* task;
unsigned fname_off;
struct event* e;
pid_t pid;
u64 ts;

/* remember time exec() was executed for this PID */
pid = bpf_get_current_pid_tgid() >> 32;
ts = bpf_ktime_get_ns();
bpf_map_update_elem(&exec_start, &pid, &ts, BPF_ANY);

/* don't emit exec events when minimum duration is specified */
if (min_duration_ns)
return 0;

/* reserve sample from BPF ringbuf */
e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0);
if (!e)
return 0;

/* fill out the sample with data */
task = (struct task_struct*)bpf_get_current_task();

e->exit_event = false;
e->pid = pid;
e->ppid = BPF_CORE_READ(task, real_parent, tgid);
bpf_get_current_comm(&e->comm, sizeof(e->comm));

fname_off = ctx->__data_loc_filename & 0xFFFF;
bpf_probe_read_str(&e->filename, sizeof(e->filename),
(void*)ctx + fname_off);

/* successfully submit it to user-space for post-processing */
bpf_ringbuf_submit(e, 0);
return 0;

The userspace program's core process (compiled to Wasm). It invokes APIs from wasm_bpf to open, load, attach the bpf program, and poll data from the ringbuf.

/* Load and verify BPF application */
skel = bootstrap_bpf__open();
if (!skel) {
fprintf(stderr, "Failed to open and load BPF skeleton\n");
return 1;

/* Parameterize BPF code with minimum duration parameter */
skel->rodata->min_duration_ns = env.min_duration_ms * 1000000ULL;

/* Load & verify BPF programs */
err = bootstrap_bpf__load(skel);
if (err) {
fprintf(stderr, "Failed to load and verify BPF skeleton\n");
goto cleanup;

/* Attach tracepoints */
err = bootstrap_bpf__attach(skel);
if (err) {
fprintf(stderr, "Failed to attach BPF skeleton\n");
goto cleanup;

/* Set up ring buffer polling */
rb = bpf_buffer__open(skel->maps.rb, handle_event, NULL);
if (!rb) {
err = -1;
fprintf(stderr, "Failed to create ring buffer\n");
goto cleanup;
/* Process events */
printf("%-8s %-5s %-16s %-7s %-7s %s\n", "TIME", "EVENT", "COMM", "PID",
while (!exiting) {
// poll buffer
err = bpf_buffer__poll(rb, 100 /* timeout, ms */);
/* Ctrl-C will cause -EINTR */
if (err == -EINTR) {
err = 0;
if (err < 0) {
printf("Error polling perf buffer: %d\n", err);

Other examples

Each directory under wasm-bpf/examples represents an example able to be run using WasmEdge. You can run make in their directory and run the corresponding WASM with WasmEdge.