Back openDesk Edu for a sovereign, open-source education â every vote counts.
Vote nowSave products you love by clicking the heart icon.
A deep technical comparison of NetworkPolicy enforcement between eBPF-based CNIs (Cilium) and iptables-based CNIs (Calico). Covers implementation internals, real performance benchmarks at scale, L7 policy trade-offs, migration strategies, and production debugging patterns.
The 2026 disruption question: Is your service mesh too slow for modern microservices? A recent study by Rizky Ramadhana Putra, Osama Bajaber and Saimon Amanuel Tsegai (2026) shows: traditional service meshes (Istio, Linkerd) fail on complex multi-hop requests â while eBPF (Extended Berkeley Packet Filter) provides the kernel-level solution â with 10x less latency and no performance overhead.
đ„ Fact: In a multi-hop scenario (e.g.
Service A â Service B â Service C â Database), a service mesh can incur up to 50% overhead from sidecar proxies. eBPF solves the problem â with near-zero overhead.
A service mesh (e.g. Istio, Linkerd, Consul) adds sidecar proxies to every pod in Kubernetes. Each request traverses multiple hops:
Client â [Sidecar Proxy] â Service A â [Sidecar Proxy] â Service B â [Sidecar Proxy] â Service C â [Sidecar Proxy] â Database
Problems:
| Drawback | Impact | Example |
|---|---|---|
| Sidecar overhead | Every pod runs an additional proxy container | +50â100ms latency per hop |
| Network hops | Each request traverses multiple proxies | 3â5Ă more network calls |
| Resource consumption | Proxies consume CPU & memory | 10â20% more resources |
| Complexity | Configuration becomes opaque fast | YAML hell |
| Cold starts | Sidecars must start with the pod | +1â2s startup time |
đ Benchmark: Latency comparison (3-hop request)
| Method | Latency (p99) | CPU overhead | Memory overhead |
|---|---|---|---|
| No service mesh | 12ms | 0% | 0% |
| Linkerd | 45ms | +15% | +20% |
| Istio | 68ms | +25% | +30% |
| eBPF (Cilium) | 15ms | +2% | +5% |
đ Source: arXiv:2608.05300v1 â eMicro: Real-Time Multi-Hop Access Control for Microservices with eBPF
eBPF (Extended Berkeley Packet Filter) is a Linux kernel technology that lets you run safe code in the kernel â without modifying the kernel.
Benefits of eBPF: â Zero overhead: Runs directly in the kernel â no extra proxies â Real-time: Reacts to every network call in microseconds â Safe: Sandboxed execution â cannot crash the kernel â Flexible: Can intercept arbitrary kernel events (network, syscalls, etc.) â Observable: Visibility into everything (network traffic, process calls, etc.)
Instead of sidecar proxies, eBPF uses the kernel directly to:
Example: Cilium's eBPF-based Network Policy
# Kubernetes NetworkPolicy (translated by Cilium into eBPF rules)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
spec:
podSelector:
matchLabels:
app: frontend
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
app: backend
ports:
- protocol: TCP
port: 8080
đ§ What happens behind the scenes?
NetworkPolicy into eBPF bytecode| Criterion | Service Mesh (Istio/Linkerd) | eBPF (Cilium) | Winner |
|---|---|---|---|
| Latency | High (40â70ms for multi-hop) | Low (12â15ms) | â eBPF |
| Overhead | High (+15â30% CPU/memory) | Low (+2â5%) | â eBPF |
| Scalability | Limited (sidecars per pod) | High (kernel-based) | â eBPF |
| Complexity | High (YAML configuration) | Medium (eBPF programming) | â Service Mesh |
| Visibility | Good (metrics, logs) | Better (kernel-level) | â eBPF |
| Security | Good (mTLS, RBAC) | Better (kernel enforcement) | â eBPF |
| Debugging | Easy (sidecar logs) | Hard (kernel debugging) | â Service Mesh |
| Cost | High (more resources) | Low | â eBPF |
| Maturity | High (production-ready) | Medium (growing fast) | â Service Mesh |
| Ecosystem | Large (Istio, Linkerd, Consul) | Growing (Cilium, Pixie, Falco) | âïž Even |
| Tool | Focus | Language | Kubernetes Integration | Highlights | GitHub Stars |
|---|---|---|---|---|---|
| Cilium | Networking & Security | Go | â Native | eBPF-based CNI, Network Policies, Hubble (observability) | â 45k |
| Pixie | Observability | Go/Python | â Plug-in | Auto-instrumentation, distributed tracing, service maps | â 12k |
| Falco | Runtime Security | C++ | â DaemonSet | Behavioural monitoring, anomaly detection, SIEM integration | â 7k |
| bpfman | eBPF Management | Rust | â ïž Experimental | eBPF program management, kernel modules | â 1.5k |
| Parca | Profiling | Go | â DaemonSet | Continuous profiling, CPU/memory analysis | â 8k |
Cilium replaces kube-proxy and uses eBPF for networking & security.
Install with Helm:
# Add the Cilium Helm repo
helm repo add cilium https://helm.cilium.io/
# Install Cilium (with eBPF enabled)
helm install cilium cilium/cilium \
--namespace kube-system \
--set kubeProxyReplacement=strict \
--set bpf.masquerade=true \
--set securityContext.capabilities.add=CHOWN,NET_ADMIN
Verify:
# Check whether eBPF is enabled
kubectl -n kube-system exec -it cilium-xxx -- cilium status | grep "eBPF"
Example: Multi-hop access control
# 1. Frontend may only access backend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: frontend-to-backend
spec:
podSelector:
matchLabels:
app: frontend
egress:
- to:
- podSelector:
matchLabels:
app: backend
ports:
- protocol: TCP
port: 8080
# 2. Backend may only access database
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-to-database
spec:
podSelector:
matchLabels:
app: backend
egress:
- to:
- podSelector:
matchLabels:
app: database
ports:
- protocol: TCP
port: 5432
# 3. Database must NOT be reachable from the internet
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database-deny-ingress
spec:
podSelector:
matchLabels:
app: database
policyTypes:
- Ingress
ingress: [] # No ingress allowed
Hubble uses eBPF to analyse network traffic between pods â without sidecars!
Install:
helm install hubble cilium/hubble \
--namespace kube-system \
--set metrics.enabled=true
Example: Show traffic between pods
# Install the Hubble CLI
curl -L https://github.com/cilium/hubble/releases/latest/download/hubble-linux-amd64.tar.gz | tar -xvz
sudo mv hubble /usr/local/bin
# Show traffic between pods
kubectl hubble observe --from-namespace default --to-namespace default
Sample output:
Aug 24 14:30:45.123 frontend-abc â backend-xyz TCP 8080 (HTTP) L7