Cilium and Calico are the two most deployed Kubernetes CNI plugins. Both handle pod networking and network policy. The fundamental difference: Cilium uses eBPF in the kernel, Calico uses iptables (with an eBPF option). This affects performance, observability, and what else the CNI can do beyond basic networking.
Architecture
Cilium
Cilium programs the Linux kernel via eBPF β small programs that run in kernel space without modifying kernel source or loading modules:
- Datapath: eBPF programs attached to network interfaces
- kube-proxy replacement: Cilium replaces kube-proxy entirely
- Identity-based: Pods get numeric identities, policies are enforced by identity, not IP
- Hubble: Built-in observability layer (flows, metrics, service map)
Calico
Calico uses iptables (or eBPF in newer versions) with BGP routing:
- Datapath: iptables rules (default) or eBPF (opt-in)
- Routing: BGP peering for flat L3 networking (no overlay needed)
- Policy engine: Calico-specific policies extend Kubernetes NetworkPolicy
- BIRD: BGP daemon for route distribution
Feature comparison
| Feature | Cilium | Calico |
|---|---|---|
| Datapath | eBPF (always) | iptables (default) or eBPF (opt-in) |
| kube-proxy replacement | Yes (recommended) | Yes (eBPF mode) |
| Network policy | Kubernetes + CiliumNetworkPolicy | Kubernetes + Calico NetworkPolicy |
| L7 policy | Yes (HTTP, gRPC, Kafka, DNS) | No (L3/L4 only) |
| Encryption | WireGuard or IPsec | WireGuard or IPsec |
| Observability | Hubble (flows, metrics, UI) | Flow logs (basic) |
| Service mesh | Built-in (eBPF-based) | No built-in mesh |
| BGP | Yes (native) | Yes (BIRD daemon) |
| Multi-cluster | ClusterMesh | Federation |
| Windows nodes | No | Yes |
| CNCF status | Graduated | Not CNCF (Tigera) |
| Bandwidth management | EDT-based rate limiting | No |
| Load balancing | Maglev, DSR, XDP | IPVS or iptables |
| Used by default | GKE Dataplane V2, EKS (option) | AKS (option), K3s, RKE2 |
Performance
The eBPF vs iptables difference is measurable at scale:
Throughput (iperf3, same node)
| Metric | Cilium (eBPF) | Calico (iptables) | Calico (eBPF) |
|---|---|---|---|
| TCP throughput | 9.4 Gbps | 8.1 Gbps | 9.2 Gbps |
| UDP throughput | 9.1 Gbps | 7.8 Gbps | 8.9 Gbps |
| p99 latency | 0.12 ms | 0.28 ms | 0.15 ms |
Policy enforcement at scale
| Number of policies | Cilium | Calico (iptables) |
|---|---|---|
| 10 | No measurable impact | No measurable impact |
| 100 | No measurable impact | ~3% throughput drop |
| 1,000 | No measurable impact | ~15% throughput drop |
| 10,000 | ~2% throughput drop | ~40% throughput drop |
iptables scales linearly β each packet traverses every rule. eBPF scales logarithmically β policies are compiled into efficient maps. At 1,000+ network policies, the difference is dramatic.
Connection tracking
| Metric | Cilium | Calico (iptables) |
|---|---|---|
| Conntrack table | eBPF maps (per-CPU) | nf_conntrack (global, contended) |
| New connections/sec | 250K+ | ~100K (contention at scale) |
| Memory per entry | 64 bytes | 376 bytes |
Network policy
Kubernetes NetworkPolicy (both support)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend
spec:
podSelector:
matchLabels:
app: api
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- port: 8080Cilium L7 policy (Cilium only)
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: api-l7
spec:
endpointSelector:
matchLabels:
app: api
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: "8080"
rules:
http:
- method: GET
path: "/api/v1/products"
- method: POST
path: "/api/v1/orders"Cilium can enforce policies at the HTTP method/path level without a service mesh. Calico is L3/L4 only.
Calico GlobalNetworkPolicy (Calico only)
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
name: deny-external
spec:
selector: environment == "production"
ingress:
- action: Deny
source:
nets:
- 0.0.0.0/0
destination:
ports:
- 443
egress:
- action: AllowCalicoβs GlobalNetworkPolicy applies cluster-wide without namespace scoping, which is useful for platform teams.
Observability
Cilium Hubble
Hubble provides deep network observability built into the CNI:
# Install Hubble
cilium hubble enable --ui
# Watch real-time flows
hubble observe --namespace production
# Filter by verdict
hubble observe --verdict DROPPED
# Service dependency map
hubble observe --to-service api-service -o jsonHubble gives you:
- Real-time flow logs (source, destination, verdict, L7 info)
- Service dependency maps
- Prometheus metrics (latency, throughput per service)
- DNS query visibility
- HTTP request/response visibility
Calico observability
Calico provides basic flow logs via Calico Enterprise (paid). Open-source Calico has limited observability β you need external tools like Prometheus + Grafana for network metrics.
Encryption
Both support node-to-node encryption:
# Cilium with WireGuard
cilium install --set encryption.enabled=true --set encryption.type=wireguard
# Calico with WireGuard
calicoctl patch felixconfiguration default --type='merge' \
-p '{"spec":{"wireguardEnabled":true}}'Performance impact is similar (~5-10% throughput reduction with WireGuard).
Installation
Cilium
cilium install --set kubeProxyReplacement=true
cilium hubble enable
cilium status --waitCalico
# Operator-based install
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.28/manifests/tigera-operator.yaml
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.28/manifests/custom-resources.yamlDecision guide
Choose Cilium when:
- Performance at scale matters β eBPF handles 1,000+ policies without degradation
- You want built-in observability (Hubble) without extra tools
- You need L7 network policy (HTTP path/method enforcement)
- You want a service mesh alternative without sidecars
- You are building AI/GPU clusters where every millisecond of network latency counts
- You want to replace kube-proxy for better load balancing (Maglev, DSR)
Choose Calico when:
- You need BGP peering with physical network infrastructure (data centers)
- Windows node support is required
- You are on OpenShift or an older cluster where Calico is already deployed
- You need GlobalNetworkPolicy for cluster-wide rules
- Your team is more familiar with iptables-based networking
- You have under 100 network policies and do not need L7 enforcement
Migration path
Many teams start with Calico (it is the default on many platforms) and migrate to Cilium as they scale. The migration requires a maintenance window to swap the CNI, but network policies can be converted.