What if I could program eBPF in pure Go? I want to use eBPF and lots of current tooling exist, but I like Go. I don’t want to use clang to create the ELF binary that then gets loaded into the Linux kernel. I want to use Go to create that ELF file. The heavy lifting of loading and inspecting can be done via bpftool (although I’m aware that Go programs exist that do this), but bpftool looks like the standard way of interacting with the kernel’s eBPF subsystem.

Show how would the Go source look like?

An eBPF hello world, looks like this:

/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
#define BPF_NO_GLOBAL_DATA
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>

typedef unsigned int u32;
typedef int pid_t;
const pid_t pid_filter = 0;

char LICENSE[] SEC("license") = "Dual BSD/GPL";

SEC("tp/syscalls/sys_enter_write")
int handle_tp(void *ctx)
{
 pid_t pid = bpf_get_current_pid_tgid() >> 32;
 if (pid_filter && pid != pid_filter)
  return 0;
 bpf_printk("BPF triggered sys_enter_write from PID %d.\n", pid);
 return 0;
}

I envision that would be something like this in Go:

import "github.com/miekg/ebpf"

func Syscalls_SysEnterWrite(ctx ebpf.Context) int {
    pid := ebpf.GetCurrentPidTgid() >> 32
    if pid != 0 {
        epbf.Printk("BPF triggered sys_enter_write from PID %d.\n", pid)
    }
    return 0
}

How?

After much reading and pondering I have some sort of a plan. Never done a compiler, but this “just” needs a compiler to take the Go code and create an eBPF ELF file. However I read things like relocating “stuff” and I have no idea if that is something I also need to do, or that just outputting the correct bits in the ELF file is enough?

I plan to take the above Go code and try to hack that into a ELF file that can be loaded in kernel by eBPF. And see how that goes. Note that the above bpf_get_current_pid_tgid() is a eBPF helper function; I need to figure out how I create Go (stub?) code for those too.

As the eBPF byte is really simple (thankfully) this should all be doable. But doing the fancy optimizations and having intermidiate code, etc., etc. is probably above my pay grade (but we can learn! :) ).

So, in the near future I’m going to see how I (manually?) can turn the above into the correct stream of bytes and then figure out how to do the rest.