eBPF: See Everything, Instrument Nothing
Run sandboxed programs inside the Linux kernel and get L3/L4/L7 telemetry, runtime security and inline enforcement, without touching a single line of application code.
For two decades, getting visibility into a running system meant a choice between two bad options: recompile the kernel, or bolt instrumentation onto every application. eBPF makes a third option real, run your own safe, verified programs directly inside the kernel, at the exact points where packets, syscalls and functions actually happen.
The result is the thing every observability vendor has promised and almost none delivered, deep, structured telemetry with no code changes, no sidecars per workload, and overhead measured in nanoseconds per event. The same machinery that watches your traffic can also drop a malicious packet before it reaches userspace. Observability and security stop being two stacks and become one.
What eBPF actually is
eBPF (extended Berkeley Packet Filter) lets you load small programs into the Linux kernel and attach them to events, the moment a syscall fires, a packet arrives on a NIC, a function is entered. Your program runs in kernel context with access to that event's data, then returns. It is not a module you compile against kernel headers and pray; it is bytecode the kernel itself agrees to run.
Two pieces make that safe enough to trust in production:
- The verifier. Before any program is loaded, the kernel statically analyses every possible execution path. It rejects unbounded loops, out-of-bounds memory access, uninitialised reads and anything that could panic the kernel. If it cannot prove the program terminates and stays in bounds, it does not load. Period.
- The JIT compiler. Once verified, the bytecode is just-in-time compiled to native machine code for the host architecture. You are not paying an interpreter tax, the hook runs at close to the speed of hand-written kernel code.
Programs talk to userspace through maps, shared key/value structures the kernel writes and your agent reads. That is how a kprobe counting TCP retransmits surfaces as a Prometheus metric without ever copying a packet into userspace. The data path stays in the kernel; only aggregates cross the boundary.
Where you hook in
eBPF is only as useful as the events it can attach to, and the menu is large. The hook type decides what you can see and whether you can act on it.
- kprobes / kretprobes. Attach to (almost) any kernel function entry or return,
tcp_connect,do_unlinkat,vfs_write. Powerful but tied to internal symbols that can shift between kernel versions. - uprobes. The same idea in userspace, attach to a function in a binary or library,
SSL_writein OpenSSL to capture plaintext before encryption, or a Go runtime symbol for L7 visibility. - tracepoints. Stable, kernel-maintained instrumentation points (
syscalls:sys_enter_openat). Less flexible than kprobes but far more durable across upgrades, the right default for portable tooling. - XDP and TC. The networking hooks. XDP runs at the earliest possible point, in the NIC driver, before an
sk_buffis even allocated, so it can drop or redirect at line rate. TC (traffic control) sits slightly higher and sees both ingress and egress. This is where eBPF stops observing and starts enforcing.
The demo below makes the difference concrete. With probes off, traffic flows but you are blind. Turn them on and the same packets light up every hook they cross, while a malicious one is dropped at XDP before it ever reaches the pod.
What eBPF powers in 2026
eBPF is plumbing, not a product. What makes it matter is the layer of tools built on top, most of them now defaults in production Kubernetes clusters rather than experiments.
- Cilium replaces kube-proxy and iptables with eBPF for service routing and load balancing, and enforces network policy in the kernel, including identity-aware L7 policy (allow
GET /health, deny everything else) without a per-pod proxy. - Hubble sits on Cilium and gives you a live service map and flow logs, every L3/L4/L7 connection in the cluster, who talked to whom, what was allowed or dropped, with zero app changes.
- Tetragon handles runtime security, kernel-level observation and enforcement of process execution, file access and network activity, with policies that can kill a process the instant it does something it should not.
- Pixie and Parca deliver auto-instrumented L7 traces and continuous, whole-fleet CPU profiling, flame graphs of production with no profiler linked into your binary and overhead low enough to leave on permanently.
One agent, not one per workload
A sidecar mesh runs a proxy in every pod, doubling your process count and adding a hop to every request. An eBPF agent runs once per node and sees every pod's traffic from the kernel. Same L7 visibility, a fraction of the footprint and latency.
The trade-offs that still bite
eBPF is genuinely transformative, but it is not magic, and treating it as free leads to surprises in production.
- Kernel version matters. Features like BTF, CO-RE (compile once, run everywhere) and ringbuf landed across different releases. A program that runs on 5.15 may not load on 4.x. You are coupling part of your platform to the kernels your distro ships.
- The verifier has limits. It rejects programs it cannot prove safe, which sometimes means perfectly correct code that exceeds the instruction or complexity budget. Engineers spend real time restructuring loops to satisfy it.
- kprobes are not a stable ABI. Hooking internal kernel functions means an upgrade can rename the symbol under you. Tracepoints and CO-RE mitigate this, but probe-heavy tooling needs testing per kernel.
- It is not a mesh replacement for everything. eBPF excels at observability, policy and L4 plus much of L7. For complex traffic management, mTLS termination and rich retries you may still want a service mesh, increasingly one whose data plane is itself eBPF-accelerated.
# Tetragon: kill any process that opens /etc/shadow in a pod
apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
spec:
kprobes:
- call: "security_file_open" # LSM hook, stable
syscall: false
args:
- index: 0
type: "file"
selectors:
- matchArgs:
- index: 0
operator: "Equal"
values: ["/etc/shadow"]
matchActions:
- action: Sigkill # enforce in-kernel, not just observe
Takeaways
- eBPF runs verified, JIT-compiled programs in the kernel, deep visibility with no app instrumentation and near-zero overhead.
- The hook type sets the power: tracepoints for portable tracing, kprobes/uprobes for depth, XDP/TC for inline networking and enforcement.
- Cilium, Hubble, Tetragon, Pixie and Parca turn raw hooks into network policy, flow maps, runtime security and continuous profiling.
- Mind the edges, kernel version support, verifier limits and unstable kprobe symbols, and know where a mesh still earns its place.
Want kernel-level visibility without the sidecar tax?
We roll out Cilium, Hubble and Tetragon on your clusters, so you get L3/L4/L7 telemetry, network policy and runtime security from one agent per node, not one proxy per pod.
Deploy eBPF observability