Cilium doesn’t just use eBPF to replace iptables in Kubernetes; it fundamentally rethinks networking by treating network packets as events that can be processed directly in the kernel.

Let’s see this in action. Imagine a simple Kubernetes Service of type LoadBalancer pointing to two Pods. Normally, iptables rules would be generated to intercept traffic destined for the Service’s ClusterIP, DNAT it to one of the Pod IPs, and then potentially apply further rules for NetworkPolicies.

Here’s what a simplified Cilium flow looks like, abstracting away the raw eBPF, but showing the logic you’d find in the kernel:

  1. Ingress Packet: A packet arrives at the Kubernetes node, destined for 10.96.0.10 (a Service ClusterIP).
  2. eBPF Hook: The packet hits an eBPF program attached to the network interface (e.g., eth0) at the XDP (eXpress Data Path) or TC (Traffic Control) ingress hook.
  3. Lookup: The eBPF program consults a shared eBPF map (think of it as a kernel-level hash table). This map contains the Service definition: 10.96.0.10:80 maps to a list of backend Pod IPs and ports.
  4. Load Balancing: The eBPF program performs load balancing (e.g., round-robin) and selects a backend Pod IP, say 10.42.0.5:8080.
  5. DNAT (in-kernel): The eBPF program modifies the packet’s destination IP and port in memory to 10.42.0.5:8080.
  6. Network Policy Enforcement: Before the packet leaves the kernel’s network stack for the Pod’s veth pair, another eBPF program intercepts it. This program checks if the source Pod is allowed to communicate with 10.42.0.5:8080 based on defined NetworkPolicies. If allowed, the packet proceeds.
  7. Packet Forwarding: The packet is then forwarded to the Pod’s network namespace.

This entire process happens within the kernel, avoiding the overhead of user-space context switches that iptables incurs.

The Problem Cilium Solves

Kubernetes networking, especially at scale, is complex. iptables has been the de facto standard for years, but it struggles with:

  • Performance: Each packet might traverse dozens or hundreds of iptables rules. Adding more Services, Pods, or NetworkPolicies means more rules, slowing everything down.
  • Scalability: The sheer number of iptables rules can become unmanageable, leading to slow rule updates and high CPU usage.
  • Visibility: Debugging iptables rules across a large cluster is notoriously difficult.
  • Feature Gaps: Advanced networking features like service mesh integration, direct Pod-to-Pod encryption, and fine-grained L7 policy enforcement are cumbersome or impossible with iptables alone.

Cilium’s core innovation is leveraging eBPF to move this logic from user-space iptables into highly optimized, kernel-resident eBPF programs.

How it Works Internally

Cilium builds a data plane using eBPF programs that are attached to various points in the Linux kernel’s network stack. These programs are compiled from a high-level language (like Go, which Cilium uses extensively) into eBPF bytecode.

  1. eBPF Programs: These are small, event-driven pieces of code that run in the kernel. They can be attached to network interface ingress/egress, socket operations, tracepoints, and more.
  2. eBPF Maps: These are kernel-resident data structures (hash tables, arrays, LRU-lists) that eBPF programs can read from and write to. Cilium uses maps extensively to store Service information, endpoint state, NetworkPolicy rules, and routing tables.
  3. Cilium Agent: A user-space daemonset running on each node. It’s responsible for:
    • Discovering Kubernetes API objects (Services, Endpoints, Pods, NetworkPolicies).
    • Translating these objects into eBPF map updates and configurations.
    • Loading and managing eBPF programs.
    • Providing observability and metrics.
  4. Cilium CNI Plugin: When a Pod is created, the Cilium CNI plugin is invoked. It configures the Pod’s network namespace and attaches the necessary eBPF programs to its veth pair and the node’s network interface.

When a packet arrives, it might trigger an eBPF program at the XDP hook (for very early packet processing) or the TC ingress hook. This program performs lookups in eBPF maps to determine the packet’s ultimate destination (e.g., a Service or another Pod) and applies transformations (like DNAT) or policy decisions. If the packet is destined for a Pod, it’s then passed through the Pod’s network namespace. If it’s egressing from a Pod, an eBPF program attached to the Pod’s veth pair intercepts it, performs lookups and policy checks, and then forwards it onto the node’s network interface.

The Levers You Control

  • NetworkPolicies: Cilium implements the standard Kubernetes NetworkPolicy API, but with significantly more power. You define ingress and egress rules based on Pod labels, namespaces, and even IP blocks. Cilium translates these into efficient eBPF bytecode for enforcement.
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: allow-frontend
    spec:
      podSelector:
        matchLabels:
          app: backend
      policyTypes:
      - Ingress
      ingress:
      - from:
        - podSelector:
            matchLabels:
              app: frontend
        ports:
        - protocol: TCP
          port: 80
    
  • Services: Cilium provides high-performance, eBPF-accelerated Service load balancing. It bypasses kube-proxy entirely.
  • Identity-Based Security: Cilium introduces a concept of "identity" for Pods and Services. Instead of relying on IP addresses for policy enforcement, it uses these identities. This makes policies more resilient to IP address changes and allows for richer L7 policy definition.
  • Observability: Cilium offers deep visibility into network traffic, including L3/L4 flow data and L7 request/response metrics, all derived from eBPF observations.
  • Encryption: Cilium can enforce automatic, transparent IPsec or WireGuard encryption between Pods, even across different nodes, without application changes.

The most surprising thing about Cilium’s eBPF implementation is how it treats network packets not as simple IP datagrams, but as discrete events flowing through a directed acyclic graph (DAG) of eBPF programs. Each program in the chain can inspect, modify, drop, or redirect the packet based on context derived from eBPF maps, which are themselves dynamically updated by the Cilium agent based on Kubernetes state. This event-driven, programmable kernel networking stack is what enables its performance and flexibility.

Once you’ve mastered the fundamentals of Cilium and eBPF networking, the next logical step is to explore its advanced features like L7 protocol awareness and service mesh integration.

Want structured learning?

Take the full Cilium course →