Prabal Tripathi

eBPF, Explained to Me by Me

Running your code inside the kernel, safely — written down until I understood it.

I kept nodding along to eBPF without really having it. So I wrote the explanation I needed, which is the only technique I know that reliably works.

The problem it solves

You want to observe or modify something the kernel does — every network packet, every file open, every system call.

Two bad options historically:

Do it in userspace. Safe, but the kernel has to copy data out to you and switch context constantly. For anything high-frequency, the overhead eats you.

Write a kernel module. Fast, and a bug panics the machine. You're shipping code with no seatbelt into the most privileged place on the system.

eBPF is a third door: run your code inside the kernel, but prove it's safe first.

How "prove" works

You write a small program. Before it loads, a verifier examines it and rejects anything it can't prove terminates and stays in bounds.

Which means real restrictions. No unbounded loops. Limited stack. You can only touch memory you've been handed. The verifier is famously difficult to satisfy and the errors are opaque.

But the trade is extraordinary: kernel-speed code with a static guarantee it can't take the box down. The restrictions are the feature.

The bit that unlocked it for me

eBPF programs don't run on their own. They're attached to events.

A packet arrives — your program runs. A syscall is entered — your program runs. It's an event handler, installed at a point in the kernel's own execution.

And it talks to userspace through maps — shared key/value structures both sides can read and write. That's the whole architecture. Tiny verified handlers at kernel events, writing into maps, with a normal program reading them.

Once I had "event handlers plus shared memory," most of what I'd read stopped being mysterious.

Why it matters for what I work on

Capturing an application's network traffic without modifying the application.

The alternatives all cost something. A proxy means reconfiguring the app to point at it, and it adds a hop. A library means changing the code. eBPF attaches to the kernel's own networking path — the app is unmodified, unaware, and unslowed.

For capturing what a service actually does in order to replay it later, that property is the whole ballgame. The moment observation changes the thing being observed, you're recording a fiction.

What I still find hard

The verifier. I have written loops that obviously terminate and been told otherwise, and the gap between "I can see this is fine" and "I can express this such that a machine agrees" is where all the time goes.