How Cilium Uses eBPF: Identity, Policy, and Sockets
What actually happens in the kernel when a Pod starts, talks to another Pod, or gets a packet policy decision — and why it's fast.
Cilium’s defining characteristic isn’t any single feature, it’s that networking, security, and observability are all implemented as programs running directly in the Linux kernel, via eBPF, rather than bolted on through iptables rules or a sidecar proxy. This guide covers what that actually means in practice: what happens when a Pod starts, how a policy decision gets made, and why Cilium’s networking path is faster than the alternatives it replaces.
eBPF in one paragraph
eBPF lets you load small, purpose-built programs into the Linux kernel at runtime, without writing a kernel module or patching the kernel itself. Before any such program is allowed to load, an in-kernel verifier statically analyzes it: confirming it terminates (no unbounded loops), stays within safe memory bounds, and can’t crash or hang the kernel. A program failing that check is rejected outright, which is what makes it safe to let user-space tools load arbitrary logic into kernel space in the first place. Every eBPF program is compiled and loaded fresh, not shipped as a precompiled kernel binary.
What happens when a Pod starts
Kubernetes’ kubelet asks the configured CNI plugin to set up networking for a new Pod. With Cilium as that CNI:
- Cilium assigns the Pod a network namespace and the usual IP configuration, the same baseline job any CNI performs.
- Cilium assigns the Pod a security identity, derived from its Kubernetes labels, not its IP address. Every Pod sharing the same relevant labels (typically including things like its Deployment’s selector labels) shares the same identity. This matters because Pod IPs are short-lived and get reassigned constantly; an identity tied to labels stays stable across restarts and rescheduling in a way an IP address never could.
- Cilium attaches an eBPF program to the Pod’s network namespace. From this point on, that program sees and can act on every network event involving this Pod: a connection opening, a packet arriving, a request leaving for another service or the outside world.
Policy decisions happen per packet, not per session
Traditional firewalls commonly implement “allow established”: once a connection is permitted, every subsequent packet on it passes without being re-evaluated, only new connections are checked against policy. Cilium’s eBPF-based enforcement evaluates every individual packet against current policy, not just the connection’s initial setup.
The practical consequence: when you change a network policy, the change is immediately effective against all traffic, including on connections that were already open. There’s no window where an already-established session keeps flowing under stale rules until it happens to close and reopen.
Observability comes from the same event stream, for free
The same eBPF instrumentation that makes policy decisions also generates an event for every network interaction it observes: connection attempts, allowed and denied traffic, requests to external destinations. This is also how Cilium can attribute traffic to the actual process that generated it, not just “this Pod talked to that Pod,” but which specific process inside the Pod opened the connection, which is a level of detail that approaches like deep packet inspection at the edge of a sidecar typically can’t reconstruct after the fact. This event stream is what Cilium’s own observability tool, Hubble, is built on, covered in the core concepts of this technology’s landing page.
Socket-level load balancing: skipping the packet rewrite
Reaching a Kubernetes Service traditionally means a packet addressed to the Service’s virtual IP gets rewritten (NAT’d) to an actual backend Pod’s IP, a step historically implemented with iptables or IPVS rules that every packet has to pass through. Cilium instead performs this translation at the socket layer, at connection time, using eBPF hooks attached where a process calls connect() or sends data. The application’s connection is set up pointing directly at a chosen backend from the start, rather than every subsequent packet being individually rewritten in flight. This removes a meaningful amount of per-packet overhead, particularly noticeable for high-throughput or latency-sensitive service-to-service traffic.
Replacing kube-proxy entirely
kube-proxy, included in the standard Kubernetes binaries, is what implements Service routing (ClusterIP, NodePort, and so on) using iptables or IPVS rules by default. Cilium can replace kube-proxy outright, implementing that same Service-routing logic in eBPF instead. Beyond raw performance, this changes an operational characteristic worth knowing: a large iptables rule set is a single interdependent structure, and changing one rule can mean reloading the whole set. Cilium’s eBPF-based rules are closer to independent, atomic entries, so a change to one doesn’t require touching the rest.
Why this matters beyond “it’s fast”
Performance is the headline, but the deeper point is architectural: because Cilium operates at the kernel level rather than through a stack of iptables rules or a per-Pod sidecar, networking, security policy, load balancing, and observability all draw from the same underlying event stream and the same kernel-level enforcement point, instead of being four separate systems that each have to be configured, kept in sync, and trusted to agree with one another. The rest of this series builds on that foundation: cluster setup, Gateway API, network policy authoring, and BGP route advertisement.
Popular Guides
-
Set Up a Cluster for Cilium: Disable the Default CNI First Cilium replaces your cluster's networking entirely, which means the order of operations matters more than with most add-ons. -
Expose Services with Cilium's Gateway API Support GatewayClass, Gateway, and HTTPRoute — host-based routing, path matching, URL rewrites, and TLS, with no separate gateway Pods. -
Write Network Policies: From L3/L4 to L7 Rules Kubernetes starts with every Pod able to reach every other Pod — CiliumNetworkPolicy is how you narrow that down, down to the HTTP method if you need to.