Welcome to this issue of Activation Function. Every other week, I introduce you to a new and interesting open-source backend technology (that you’ve probably only kind of heard about… ) and explain it to you in 5 minutes or less so you can make better technical decisions moving forward.
In this issue, we’ll explore eBPF (Extended Berkeley Packet Filter), an exciting new technology that makes programming the kernel flexible, safe, and accessible to developers.
[IMPORTANT NOTE] eBPF is now a standalone term that doesn’t stand for anything. You'll see the term BPF in Linux source code, and you'll see BPF and eBPF used interchangeably in tooling and documentation. The original BPF is sometimes called cBPF (classic BPF) to distinguish it from eBPF.
The kernel can oversee and control the entire system, which, on the one hand, makes it the ideal place to implement networking, security, and observability capabilities and, on the other hand, makes it very risky to fiddle with.
As a result, innovation at the kernel level has been super slow! After all, as the saying goes,
With great power comes great responsibility.
Up until recently, if you wanted to add functionality to the kernel, you had two options:
eBPF is a mechanism that makes the kernel dynamically programmable, kind of like how JavaScript lets you dynamically change the behavior of a webpage. Here is a great high-level explanation by Brendan Gregg:
eBPF does to Linux what JavaScript does to HTML. (Sort of.) So, instead of a static HTML website, JavaScript lets you define mini-programs that run on events like mouse clicks, which are run in a safe virtual machine in the browser. And with eBPF, instead of a fixed kernel, you can now write mini-programs that run on events like disk I/O, which are run in a safe virtual machine in the kernel. In reality, eBPF is more like the v8 virtual machine that runs JavaScript rather than JavaScript itself. eBPF is part of the Linux kernel.
Although eBPF is far from completely replacing LKMs, it sets itself apart by bringing great flexibility while mitigating risk by putting solid safety and controls in place.
1992 – Van Jacobson wanted to troubleshoot network issues, but existing network filters were too slow. He and his team developed BPF (Berkeley Packet Filter) to be fast, efficient, and easily verifiable to run in the kernel safely.
BPF was a great technology, but it had a few limitations that became apparent over the years as networking technology evolved. Among other things:
2014 – Alexei Starovoitov introduced the extended BPF (eBPF) design that took things to a whole new level by:
Today, eBPF is a general-purpose compute engine within the Linux kernel that allows you to hook into, observe, and act upon anything happening in the kernel.
Check out by Alexei Starovoitov for an in-depth history of eBPF.
Before we delve into this, it’s essential to understand the difference between the kernel and user space in Linux.
Here is a quick rundown:
Alright, back to eBPF. Without going the rabbit hole, here is how it works on a high level:
Step #1 | Program Development
You can write your own eBPF program using a tool like bpftrace that provides an easy-to-learn high-level language or the BPF Compiler Collection (BCC) Python framework. The program is then compiled into bytecode.
[Note] As a beginner, you don’t need to write eBPF code from scratch, as BCC comes with over 70 tools you can use out of the box. Here is a glimpse of what you have at your disposal:
Source — https://www.brendangregg.com/
Step #2 | Program Verification
The bytecode runs through the eBPF verifier inside a VM to ensure it will not harm the system before being loaded into the kernel.
[Note] The verification process is quite complex. You can read more about it here. Although much work has gone into improving and simplifying it, you can still run into strange errors when developing your program. If you need help, check out the eBPF Slack community channel.
Step #3 | Program Attachment
The verified program is loaded into the kernel and attached to predefined hook points before being further JIT compiled at runtime into native machine instructions to ensure maximum performance.
Step #4 | Program Execution
The program is triggered on predefined events, and helper functions are called.
Maps are then used to pass data between the kernel and user space or other eBPF functions and to maintain the state.
[Note] eBPF program becomes active when loaded into the kernel. You don’t need to reboot the machine, restart existing processes, or change anything about other applications.
Since its inception in 2014, eBPF capabilities have continued to grow, supported by 300+ kernel developers and major tech players, including Netflix, Meta, Google, Cloudflare, DoorDash, and many others, running eBPF-based tools in production for over half a decade 24/7 at internet scale on millions of servers. Let’s look at some examples:
And the list goes on.
No technology is perfect, and eBPF isn’t an exception. Let’s discuss a few current limitations you should be aware of:
Despite a lot of effort put in by the community to make eBPF more accessible, the reality is that it’s still a pretty complex technology to work with for the majority of developers.
The good news is that if you want to leverage the power of eBPF, there are a growing number of projects that can help you do that without writing eBPF programs:
And the list goes on.
If eBPF sounds like your cup of tea, and you’re interested in exploring further, you’re in luck, as many great free resources are available. Here are a few:
That’s it for today. I hope this gave you a good idea of what eBPF is and how you can use it for your next project. There is still SO MUCH to unpack when it comes to eBPF, so I encourage you to go out and explore!
Until next time!
Also published here.