A NetworkPolicy only takes effect if the CNI implements it, a point already made elsewhere: what few articles detail is how that implementation actually happens, and why that detail becomes critical past a certain cluster size. kube-proxy, the historical component, translates every Kubernetes Service into iptables rules; Cilium, built on eBPF, replaces that entire mechanism with code running directly in the Linux kernel.
What kube-proxy actually does with iptables
kube-proxy, in its most common mode, translates every Service and every endpoint into a chain of iptables rules. Routing a packet to the right pod means evaluating those rules sequentially, one by one, until a match is found: a mechanism whose cost grows with the number of Services and endpoints in the cluster, not linearly but often worse.
# Every Service adds rules evaluated
# sequentially, cost grows with their count
iptables -t nat -L KUBE-SERVICES | wc -l
On a cluster with hundreds of Services and thousands of pods, that sequential evaluation becomes a measurable bottleneck: routing latency increases with cluster size, an effect that never shows up on a development cluster but becomes real in production at scale.
eBPF: code running in the kernel, no detour needed
eBPF (extended Berkeley Packet Filter) lets custom code run directly in the Linux kernel, at precise hook points along the network path, bypassing traditional iptables rules entirely. Cilium uses this mechanism to fully replace kube-proxy: routing to the right pod happens via an in-memory hash table, a near-constant-cost lookup, independent of the number of Services in the cluster.
# Cilium as a full kube-proxy replacement,
# routing goes through eBPF, not iptables rules
kubeProxyReplacement: true
That mechanism difference (hash lookup versus sequential evaluation) explains why Cilium advertises measurable performance gains precisely on high-Service-density clusters, exactly where kube-proxy starts showing its limits.
What it changes for network observability
eBPF isn’t limited to routing: the same mechanism lets Cilium observe network traffic at the kernel level with no extra agent or sidecar, with visibility down to packet and syscall level. Hubble, Cilium’s observability component, leverages this capability to provide visibility into network flows (who talks to whom, which flows a NetworkPolicy blocks) with no application instrumentation.
# Network flow visibility at the kernel level,
# no extra per-pod agent to deploy
hubble observe --namespace production
The price: a kernel dependency, not a cluster one
eBPF imposes a constraint kube-proxy and iptables never had: a sufficiently recent Linux kernel version on every node (generally 4.19 or newer depending on the features used). A cluster on an old operating system, or a managed environment that doesn’t allow controlling kernel version, can end up unable to fully leverage the newest eBPF features, a check to make before adopting Cilium as a full kube-proxy replacement, not after.
Takeaway
kube-proxy translates every Service into iptables rules evaluated sequentially, a mechanism whose cost grows with cluster size. Cilium, built on eBPF, replaces that mechanism with hash tables running directly in the kernel, at near-constant cost, with native network observability thrown in at no extra agent cost. The price is a dependency on a sufficiently recent kernel version, an infrastructure check to make before adopting Cilium, one of the network-layer choices that come up from the design stage of a Kubernetes migration at scale.