eBPF
Learn how eBPF executes sandboxed code inside the OS kernel, enabling low-overhead observability, custom network routing, and system monitoring.
Sandboxed Kernel Execution
The operating system kernel has absolute control over the hardware, CPU schedules, memory maps, and network routing. Traditionally, modifying kernel behavior required writing a kernel module.
However, kernel modules are highly risky: a single memory error or null-pointer dereference will crash the entire operating system (triggering a kernel panic). Furthermore, kernel modules are tightly coupled to specific kernel versions, requiring constant maintenance and recompilation.
Traditional Kernel Module:
[Code] ---> [Loaded directly into Kernel Space] === (Crash in Code = Kernel Panic!)
eBPF Sandboxed Code:
[Code] ---> [Verifier Checks Safety] ---> [JIT compiler] ---> [Executed in Sandbox]
eBPF (Extended Berkeley Packet Filter) solves this problem by providing a secure, sandboxed virtual machine inside the kernel. It allows developers to run custom bytecode at helper hook points in the kernel without restarting the server or loading unstable modules.
The eBPF runtime ensures that programs cannot crash the system, read invalid memory, or execute infinite loops, providing a safe bridge between user space applications and kernel-level performance.
The eBPF Virtual Machine
The eBPF VM runs as a software-defined execution engine directly within the operating system kernel:
- Registers: Features eleven 64-bit registers:
R0(return value register),R1toR5(argument registers),R6toR9(callee-saved registers), andR10(a read-only frame pointer to access the stack). - Stack Space: Provides a small 512-byte stack frame. For larger storage allocations, programs must utilize external structures called eBPF Maps.
- Helper Functions: eBPF bytecode is restricted from calling arbitrary kernel routines. Instead, it interacts with the OS via restricted helper functions (e.g., retrieving the current PID via
bpf_get_current_pid_tgid()).
The Kernel Verification Engine
Before an eBPF program can be loaded, it must pass through the Verifier. The verifier performs static analysis to ensure execution safety before the code is compiled to native instructions:
- Control Flow Analysis: The verifier constructs a Directed Acyclic Graph (DAG) of all possible execution branches. It rejects any programs containing infinite loops or unreachable states.
- Memory Safety: Checks every read and write instruction to ensure the program only accesses memory on the stack or within validated maps. Pointers must be checked for NULL before dereferencing.
- Complexity Bounds: Limits the number of instructions checked (historically 1 million instructions) to ensure verification terminates quickly.
Once verified, the JIT (Just-In-Time) Compiler translates the generic eBPF bytecode into native x86-64 or ARM assembly instructions, allowing the program to execute at native kernel speeds.
Attachment Points and Hooks
eBPF programs are event-driven. They compile, register with the kernel, and wait for specific events to trigger execution at designated attachment points:
- Kprobes & Kretprobes: Dynamic probes attached to the entry (
kprobe) or return (kretprobe) of any kernel function. - Uprobes & Uretprobes: User-space equivalent of kprobes. They hook functions within user-space applications (e.g. tracking when a Go HTTP server calls a database driver).
- Tracepoints: Static trace structures compiled directly into the kernel source by kernel developers. They are more stable than kprobes, which can change between kernel versions.
- XDP (eXpress Data Path): A high-performance hook located directly in the network driver layer, immediately after packet reception. XDP allows eBPF programs to inspect, modify, or drop packets before they are parsed by the kernel's TCP/IP stack.
eBPF Maps: Sharing Data
Because eBPF programs run in sandboxed kernel memory, they cannot write directly to user-space memory. To share state, they use eBPF Maps:
Maps are key-value structures initialized in kernel space. They can be read or written by both eBPF kernel programs and user-space controllers. Common map formats include:
- Hash Tables: Dynamic key-value pairs, ideal for matching processes to state tags.
- Ring Buffers: High-throughput queues designed to stream structured event sequences from the kernel to user space.
- Arrays: Fixed-size tables, useful for accumulating counters and metrics.
Observability and High-Performance Networking
eBPF has revolutionized backend systems engineering by changing how observability and networking are implemented:
Low-Overhead Observability
Traditional monitoring agents poll log files or intercept system calls by wrapping user commands. This introduces significant CPU overhead. eBPF hooks directly into kernel tracepoints, aggregating system statistics (such as execution times or disk latency distributions) inside local kernel maps. The user-space metrics collector only reads from these maps periodically, minimizing context-switching overhead.
High-Performance Networking (XDP)
In traditional networking, every packet travels up the network driver, through the IP routing tables, through firewalls (like iptables), and up to the TCP socket buffer.
Using eBPF with XDP, you can drop DDoS packets or route incoming queries at the network card driver level. This bypasses the TCP/IP stack entirely, enabling servers to process millions of packets per second with minimal CPU load.
Further Reading
- eBPF Document Portal — Foundational resources, code directories, and community projects using eBPF
- Learning eBPF — Liz Rice's textbook explaining raw eBPF assembly, BCC, and Go-BPF loaders
- Linux Kernel BPF Documentation — Official specifications of the eBPF VM, register rules, and verifier safety structures
Prerequisites
Code Examples
Core Literature References
Learning eBPF: Programming the Linux Kernel for Observability and Networking
by Liz Rice — Chapter 1 & 3, pp. 1-54
View sourceContinue learning
ACID & Isolation Levels
Deep dive into database transaction guarantees, isolation levels, concurrency anomalies like write skew, and control mechanisms such as MVCC, 2PL, and SSI.
API Gateways
Understand the API Gateway pattern as the central ingress point for microservices, handling routing, auth, rate limiting, and protocol translation.
API Security & OAuth 2.0
Understand API authentication and authorization mechanisms, JWT security, and the OAuth 2.0 framework including Authorization Code Flow with PKCE.