Writing, Compiling, and Loading eBPF Program

Gika Megawan Pramudita
2 min readMay 12, 2023

--

Photo by Yannick Pulver on Unsplash

In our previous article, we introduced BPF and eBPF, their history, architecture, and use cases. Now, it’s time to dive deeper into eBPF programming, where we’ll explore its restricted C-like language, the process of writing, compiling, and loading eBPF programs, and working with eBPF bytecode and maps. By the end of this article, you’ll be ready to create and deploy your own eBPF programs to tackle real-world challenges.

eBPF’s Restricted C-like Language

eBPF programs are written in a restricted subset of the C programming language. The restrictions are designed to ensure that eBPF programs are safe to run in the kernel and don’t cause issues like infinite loops or illegal memory accesses. Here are some key aspects of eBPF’s C-like language:

  1. Limited loops: Loops are allowed in eBPF programs, but they must have a known, fixed upper-bound to prevent infinite loops.
  2. No global variables: eBPF programs cannot use global variables; instead, they rely on eBPF maps for data storage and sharing.
  3. No floating-point arithmetic: eBPF programs do not support floating-point arithmetic, as they can introduce non-deterministic behaviour.
  4. Limited function calls: eBPF programs can only call a specific set of kernel functions, known as “helper functions.”

Writing Your First eBPF Program

Let’s create a simple eBPF program that counts the number of packets received on a network interface. This program will use an eBPF map to store the packet counters.

The code below defines a map named pkt_counter and a function named count_packets. The function increments the counter in the map every time a packet is received.

#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

struct bpf_map_def SEC("maps") pkt_counter = {
.type = BPF_MAP_TYPE_PERCPU_ARRAY,
.key_size = sizeof(u32),
.value_size = sizeof(u64),
.max_entries = 1,
};

SEC("prog")
int count_packets(struct __sk_buff *skb) {
u32 key = 0;
u64 *counter;

counter = bpf_map_lookup_elem(&pkt_counter, &key);
if (counter) {
(*counter)++;
}

return 0;
}

char _license[] SEC("license") = "GPL";

Compiling and Loading Your eBPF Program

You can compile the eBPF program using Clang and LLVM, and then load it into the kernel using the bpftool utility. Here's how to do it:

  1. Compile the eBPF program:
clang -O2 -target bpf -c my_ebpf_program.c -o my_ebpf_program.o

2. Load the eBPF program into the kernel:

sudo bpftool prog load my_ebpf_program.o /sys/fs/bpf/my_ebpf_program

Conclusion

In this article, we’ve created and loaded our first eBPF program. It’s a simple one, but it lays the foundation for creating more complex and powerful programs in the future. In the next article, we’ll dive deeper into eBPF maps, which are essential for sharing data between eBPF programs and userspace.

--

--

Gika Megawan Pramudita

SRE and DevOps practitioner who enjoys writing about tech and occasionally sharing bits of my life.