Why architecture matters here

eBPF matters because it makes the kernel programmable safely, unlocking capabilities that previously required kernel modules, dedicated hardware, or weren't possible at all. The kernel sits at the heart of everything — every packet, every syscall, every network decision passes through it — so being able to run custom logic there, at native speed, is enormously powerful: you can implement a load balancer that processes packets at line rate without dedicated hardware (Katran), network policy and security for Kubernetes enforced in-kernel (Cilium), deep observability into what the kernel is doing (tracing every syscall, every network flow) without instrumentation overhead, and DDoS mitigation that drops attack packets at the earliest possible point (XDP, before they consume stack resources). The previous ways to do these — kernel modules (dangerous, gatekept), dedicated hardware (expensive, inflexible), or userspace processing (slow, copies) — are all worse. eBPF's combination of safety, speed, and runtime-loadability makes kernel-level custom logic accessible, and it's reshaping networking, observability, and security.

The verifier is the architectural key that makes this safe, and understanding it is understanding eBPF's constraints. Running arbitrary code in the kernel would be catastrophic (a bug crashes everything, an infinite loop hangs the kernel, invalid memory access corrupts state). The verifier prevents this by proving each program safe before loading: it checks the program terminates (no unbounded loops — historically no loops at all, now bounded loops), accesses only valid memory (bounds-checked), doesn't leak kernel data, and stays within complexity limits (a bounded number of instructions the verifier can analyze). This makes eBPF programs safe but constrained — you can't write arbitrary code; you write code the verifier can prove safe, which means working within its constraints (bounded loops, limited complexity, specific memory access patterns). The verifier is simultaneously eBPF's safety guarantee and its main limitation, and eBPF programming is largely about expressing your logic in a form the verifier accepts — a real skill and a real constraint.

And XDP's position is what enables eBPF's networking performance. Packets normally traverse the kernel's full network stack (allocation, parsing, routing) before your code sees them — expensive per packet. XDP hooks at the earliest point: in the NIC driver, on the raw packet, before the stack allocates structures for it. This means XDP can process (drop, redirect, load-balance) packets at line rate (millions per second) with minimal per-packet cost — dropping a DDoS packet at XDP costs almost nothing (it never entered the stack), versus dropping it later after the stack processed it. XDP's earliness is why it enables line-rate DDoS mitigation and load balancing — the packet is handled before it consumes resources — and understanding the hook hierarchy (XDP earliest/fastest, then tc, then socket layer) is key to choosing where to run eBPF for a given task (earliest for raw performance, later for more context).

Advertisement

The architecture: every piece explained

Top row: the eBPF machinery. An eBPF program is bytecode (compiled from restricted C or other frontends) that runs in the kernel at a hook. The verifier analyzes it before loading, proving safety: termination (bounded), valid memory access (bounds-checked), no kernel-data leaks, within complexity limits — rejecting unsafe programs. The JIT compiles verified bytecode to native machine code, so it runs at native speed (not interpreted). Hooks are the attachment points: XDP (earliest network), tc (traffic control, later network with more context), socket hooks, and beyond networking — tracing hooks (kprobes, tracepoints), security hooks (LSM) — eBPF spans networking, observability, and security.

Middle row: the components. XDP is the earliest, fastest network hook — in the NIC driver, on the raw packet before the stack — enabling line-rate processing. Maps are the state mechanism: key-value structures (hash maps, arrays, and specialized types) shared between the eBPF program (in-kernel) and userspace — so the program maintains state (connection tracking, counters, configuration) and userspace reads/writes it (configuring the program, reading its results) — the kernel-userspace communication channel. Helpers are the controlled kernel-function access: eBPF programs can't call arbitrary kernel functions (safety), but a defined set of helper functions gives them needed capabilities (map access, packet manipulation, time, randomness) — the sanctioned interface to kernel functionality. Actions for network programs: XDP returns an action per packet — PASS (continue to the stack), DROP (discard — DDoS mitigation), TX (send back out — reflection), REDIRECT (send to another interface/CPU — load balancing) — the packet's fate decided by the program.

Bottom rows: applications and systems. Use cases: load balancing (XDP redirecting packets across backends at line rate — Katran), DDoS mitigation (XDP dropping attack packets at the earliest point), observability (tracing kernel/network activity with minimal overhead — the whole eBPF observability ecosystem), and network security/policy (enforcing rules in-kernel — Cilium). Cilium / Katran are flagship production systems: Cilium (eBPF-based Kubernetes networking, security, and observability, replacing iptables-based approaches), Katran (Facebook's eBPF/XDP load balancer). The ops strip: verifier limits (working within the verifier's constraints — bounded loops, complexity limits — the main eBPF programming challenge), map sizing (maps have fixed sizes; sizing them for the workload — connection tables, counters), and kernel version dependencies (eBPF capabilities and hooks vary by kernel version; programs depend on kernel features, requiring version awareness).

eBPF and XDP — programmable packet processing in the kernelrun sandboxed code at the network fast patheBPF programsandboxed kernel bytecodeVerifiersafety before loadJIT compilenative speedHooksXDP, tc, sockets, tracingXDPearliest packet hookMapskernel-user shared stateHelperskernel functionsActionspass, drop, redirect, txUse casesload balancing, DDoS, observabilityCilium / Katranproduction systemsOps — verifier limits + map sizing + kernel versionshooksharecallactdeployuseoperateoperateoperate
eBPF/XDP: verified, JIT-compiled programs run at kernel hooks (XDP earliest), using maps for state and helpers for kernel access, acting on packets at line rate.
Advertisement

End-to-end flow

Trace an XDP load balancer (Katran-style) processing packets. A packet arrives at the NIC; the XDP program runs in the driver, on the raw packet, before the kernel stack. It parses the packet headers, looks up the destination service in a map (the service-to-backends mapping, configured from userspace), selects a backend (consistent hashing on the connection, tracked in a connection map for consistency), rewrites the packet to the backend, and returns REDIRECT (sending it to the backend) — all at line rate, before the stack allocated any structures for the packet. Millions of packets per second load-balanced by an eBPF program in the NIC driver, no dedicated hardware, configured and monitored via maps from userspace. The performance comes from XDP's earliness (raw packet, pre-stack) and the JIT (native speed), and the configurability comes from maps (userspace updates the backend set, the program reads it).

The DDoS and observability vignettes show the range. A DDoS mitigation case: an XDP program checks each packet against a map of blocked sources / attack signatures and returns DROP for attack packets — dropping them at the earliest point (in the driver, before the stack), so the attack consumes almost no resources (the dropped packets never entered the stack). This is why XDP is the premier DDoS mitigation point: dropping at XDP is nearly free, versus dropping later after the stack processed the packet. An observability case: an eBPF program on tracing hooks monitors network flows (or syscalls, or any kernel activity), maintaining statistics in maps that userspace reads — deep visibility into kernel behavior with minimal overhead (the eBPF program runs at native speed at the hook, no instrumentation or context-switching), enabling the eBPF observability tools (network flow monitoring, performance analysis, security monitoring) that see what the kernel is doing.

The verifier and operational vignettes complete it. A developer writes an eBPF program with an unbounded loop (processing a variable-length structure) — the verifier rejects it (can't prove termination). They restructure with a bounded loop (a fixed max iterations the verifier accepts), and it loads — the verifier constraint shaping the code. A complexity limit: a program too complex for the verifier to analyze (too many instruction paths) is rejected; they simplify (split logic, reduce branches) to fit — the verifier's complexity budget as a real constraint. A kernel-version issue: a program uses a helper available in newer kernels but runs on an older one; it fails to load — the version dependency requiring awareness of what the target kernel supports. The team's operational practice: work within verifier constraints (bounded loops, manageable complexity — the main eBPF programming discipline), size maps for the workload (connection tables, counters large enough), test on the target kernel versions (capabilities vary), and use established frameworks (Cilium, libbpf, BCC) that handle much of the complexity. The consolidated discipline: leverage eBPF/XDP for line-rate in-kernel processing (load balancing, DDoS, observability, security), work within the verifier's safety constraints (the code must be provably safe), size maps appropriately, and manage kernel version dependencies — because eBPF makes the kernel safely programmable at native speed, unlocking capabilities that reshape networking and observability, with the verifier's constraints as the price of the safety that makes running code in the kernel viable.