Introduction to Calico Networking
Calico is one of the most widely adopted networking and network policy solutions for Kubernetes and other container orchestration platforms. It provides a pure Layer 3 approach to networking, using BGP (Border Gateway Protocol) to route packets between nodes without overlays, although it also supports VXLAN and IP-in-IP encapsulation modes. While Calico is robust and production-ready, operators frequently encounter issues related to pod-to-pod connectivity, policy enforcement, IP address management, and BGP peering. This tutorial walks through the most common Calico networking problems and provides actionable fixes.
Why Troubleshooting Calico Matters
Networking is the backbone of any Kubernetes cluster. When Calico misbehaves, workloads lose connectivity, DNS resolution fails, and applications degrade silently. Because Calico operates at multiple layers — kernel routing tables, iptables/eBPF dataplane, BGP control plane, and Kubernetes API — pinpointing the root cause requires a systematic approach. Mastering Calico troubleshooting reduces mean time to resolution (MTTR) and prevents cascading failures across your infrastructure.
Prerequisites and Tooling
Before diving into specific issues, ensure you have the right tools installed. You will need cluster-admin access to your Kubernetes cluster and the calicoctl command-line tool, which provides deep inspection capabilities beyond what kubectl offers.
# Install calicoctl
curl -L https://github.com/projectcalico/calico/releases/latest/download/calicoctl -o /usr/local/bin/calicoctl
chmod +x /usr/local/bin/calicoctl
# Verify installation
calicoctl version
Configure calicoctl to talk to your datastore. For Kubernetes-backed Calico installations, create a config file:
export KUBECONFIG=/path/to/kubeconfig
export DATASTORE_TYPE=kubernetes
calicoctl get nodes
Essential Diagnostic Commands
Keep these commands handy as they form the foundation of most troubleshooting workflows:
calicoctl node status— Shows BGP peer status on the local nodecalicoctl get pods -o wide— Lists Calico workload endpointscalicoctl get ipPool -o yaml— Displays configured IP poolskubectl get pods -n kube-system -l k8s-app=calico-node— Checks Calico node daemonset healthip route— Inspects kernel routing tables on a nodeiptables -L -n -v— Examines iptables rules (when using the iptables dataplane)
Issue 1: Calico Node Pod Stuck in Init State
One of the most frequent issues is the calico-node pod failing to become ready. This typically indicates a problem with the node's ability to initialize the Calico dataplane or register with the datastore.
Diagnosing the Problem
Start by inspecting the pod's status and logs:
kubectl get pods -n kube-system -l k8s-app=calico-node
kubectl describe pod <calico-node-pod-name> -n kube-system
kubectl logs <calico-node-pod-name> -n kube-system -c calico-node
Common log errors include:
Failed to get node: resource does not exist— The Calico node resource is missingAuthorization error— RBAC permissions are incorrectIP autodetection failed— Calico cannot determine the node's IP address
Fixing IP Autodetection Failures
When Calico cannot detect the correct node IP, you must explicitly configure the IP detection method. Edit the Calico daemonset or the Calico node manifest:
env:
- name: IP_AUTODETECTION_METHOD
value: "interface=eth0"
- name: IP6_AUTODETECTION_METHOD
value: "interface=eth0"
Alternatively, use a CIDR-based match to select the correct interface in multi-NIC environments:
env:
- name: IP_AUTODETECTION_METHOD
value: "cidr=10.0.0.0/8"
After updating the configuration, restart the Calico node pods:
kubectl delete pods -n kube-system -l k8s-app=calico-node
Fixing RBAC Issues
If logs show authorization errors, reapply the Calico RBAC manifests:
kubectl apply -f https://docs.projectcalico.org/manifests/rbac.yaml
Verify the Calico service account has the necessary cluster role bindings:
kubectl auth can-i get nodes --as=system:serviceaccount:kube-system:calico-node
Issue 2: Pod-to-Pod Communication Fails
When pods on different nodes cannot communicate, the problem usually lies in the routing plane, IP pool configuration, or encapsulation settings.
Step 1: Verify Calico Node Status
Log into a node and check the BGP peering status:
calicoctl node status
Expected output shows established peers:
Calico process is running.
IPv4 BGP status
+--------------+-------------------+-------+----------+-------------+
| PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO |
+--------------+-------------------+-------+----------+-------------+
| 10.0.1.5 | node-to-node mesh | up | 09:30:00 | Established |
| 10.0.1.6 | node-to-node mesh | up | 09:30:00 | Established |
+--------------+-------------------+-------+----------+-------------+
If peers show idle or active, BGP sessions are not establishing. Check firewall rules on port 179 (BGP) between nodes:
# On the target node, verify BGP port is listening
ss -tlnp | grep 179
# Test connectivity from source node
nc -zv 10.0.1.5 179
Step 2: Check IP Pool Configuration
Misconfigured IP pools are a common cause of cross-node connectivity failures. Verify the pool CIDR matches your pod network:
calicoctl get ipPool -o yaml
Ensure the following fields are correct:
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
name: default-ipv4-ippool
spec:
cidr: 192.168.0.0/16
ipipMode: Always
vxlanMode: Never
natOutgoing: true
disabled: false
If disabled is set to true, Calico will not allocate IPs from this pool. Fix it with:
calicoctl patch ipPool default-ipv4-ippool --patch '{"spec":{"disabled":false}}'
Step 3: Verify Encapsulation Mode
Calico supports multiple encapsulation modes. If nodes are on different subnets and no BGP peering with the underlying network is configured, you must use encapsulation (IPIP or VXLAN). Check the current mode:
calicoctl get ipPool default-ipv4-ippool -o yaml | grep -E "ipipMode|vxlanMode"
For VXLAN mode (recommended for most cloud environments):
cat <<EOF | calicoctl apply -f -
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
name: default-ipv4-ippool
spec:
cidr: 192.168.0.0/16
vxlanMode: Always
ipipMode: Never
natOutgoing: true
EOF
After changing encapsulation mode, verify the tunnel interface exists on each node:
# For VXLAN
ip link show vxlan.calico
# For IPIP
ip link show tunl0
Issue 3: Network Policies Not Being Enforced
Calico network policies provide fine-grained traffic control. When policies appear to be ignored, the issue often stems from policy ordering, selector mismatches, or dataplane mode conflicts.
Diagnosing Policy Enforcement
First, confirm the Calico dataplane mode. If you are using eBPF mode, some iptables-based debugging techniques will not apply:
kubectl get pods -n kube-system -l k8s-app=calico-node -o yaml | grep -A1 "FELIX_BPFENABLED"
Next, list all policies affecting a namespace:
calicoctl get networkPolicy -n <namespace> -o yaml
calicoctl get globalNetworkPolicy -o yaml
Common Policy Mistakes
A frequent mistake is creating a default-deny policy without any allow policies, which blocks all traffic including DNS. Always pair deny policies with explicit allow rules:
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
name: default-deny
namespace: production
spec:
selector: all()
types:
- Ingress
- Egress
---
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: production
spec:
selector: all()
egress:
- action: Allow
destination:
namespaceSelector: name == 'kube-system'
selector: k8s-app == 'kube-dns'
destinationPorts:
- 53
protocol: UDP
- action: Allow
destination:
namespaceSelector: name == 'kube-system'
selector: k8s-app == 'kube-dns'
destinationPorts:
- 53
protocol: TCP
Debugging Policy with Packet Capture
To verify whether traffic is being dropped by a policy, use Calico's built-in flow logging. Enable flow logs by configuring the Felix environment variables:
env:
- name: FELIX_FLOWLOGS_ENABLED
value: "true"
- name: FELIX_FLOWLOGS_FILEPATH
value: "/var/log/calico/flows"
Then inspect the flow logs on the node:
tail -f /var/log/calico/flows | grep <source-pod-ip>
For iptables dataplane mode, you can also trace packet drops:
# Watch Calico chain counters in real time
watch -n 1 'iptables -L -n -v -t filter | grep -i calico'
Look for incrementing counters in the cali-tw-cali (to-workload) or cali-fw-cali (from-workload) chains to identify where packets are being dropped.
Issue 4: IP Address Exhaustion
As clusters grow, IP pool exhaustion becomes a real concern. Pods stuck in ContainerCreating state with Failed to allocate address errors indicate this problem.
Detecting Exhaustion
Check the IP pool usage with calicoctl:
calicoctl ipam show --show-blocks
Sample output:
+----------+-------------------+------------+------------+-------------------+
| GROUPING | CIDR | IPS TOTAL | IPS IN USE | IPS FREE |
+----------+-------------------+------------+------------+-------------------+
| IP Pool | 192.168.0.0/16 | 65536 | 65400 | 136 |
| Block | 192.168.0.0/26 | 64 | 64 | 0 |
| Block | 192.168.0.64/26 | 64 | 64 | 0 |
+----------+-------------------+------------+------------+-------------------+
Fixing IP Exhaustion
Add a new IP pool and optionally disable the old one to prevent new allocations while existing pods continue running:
cat <<EOF | calicoctl apply -f -
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
name: extended-ipv4-ippool
spec:
cidr: 192.169.0.0/16
vxlanMode: Always
ipipMode: Never
natOutgoing: true
disabled: false
EOF
To reclaim IPs from deleted pods that were not properly released, use the ipam commands:
# Check for leaked IP allocations
calicoctl ipam check --show-orphans
# Release a specific IP
calicoctl ipam release --ip=192.168.1.50
# Release all orphaned IPs
calicoctl ipam release --orphans
Issue 5: BGP Route Reflection Not Working
In larger clusters, the default node-to-node mesh does not scale. Route reflectors reduce the BGP session count, but misconfiguration leads to incomplete route propagation.
Configuring Route Reflectors
Designate specific nodes as route reflectors by adding the appropriate label:
kubectl label node node-1 node-role.kubernetes.io/route-reflector=true
Create a BGPConfiguration to disable the full mesh and configure the route reflector cluster:
cat <<EOF | calicoctl apply -f -
apiVersion: projectcalico.org/v3
kind: BGPConfiguration
metadata:
name: default
spec:
nodeToNodeMeshEnabled: false
asNumber: 64512
---
apiVersion: projectcalico.org/v3
kind: BGPPeer
metadata:
name: rr-client-peer
spec:
nodeSelector: "!node-role.kubernetes.io/route-reflector"
peerSelector: "node-role.kubernetes.io/route-reflector"
---
apiVersion: projectcalico.org/v3
kind: BGPPeer
metadata:
name: rr-mesh-peer
spec:
nodeSelector: "node-role.kubernetes.io/route-reflector"
peerSelector: "node-role.kubernetes.io/route-reflector"
EOF
Verifying Route Propagation
On a non-route-reflector node, verify it has learned routes from all other nodes through the reflector:
calicoctl node status
# Check the routing table for learned BGP routes
ip route | grep proto bird
If routes are missing, verify the route reflector node has the correct AS number and that the routeReflectorClusterID is set on the node resource:
calicoctl patch node node-1 --patch='{"metadata":{"labels":{"i-am-a-route-reflector":"true"}},"spec":{"bgp":{"routeReflectorClusterID":"10.0.0.1"}}}'
Issue 6: Calico and eBPF Dataplane Issues
Calico's eBPF dataplane offers superior performance and eliminates kube-proxy, but it introduces its own set of troubleshooting challenges.
Verifying eBPF Mode
Confirm eBPF mode is active and kube-proxy is disabled:
# Check Felix configuration
calicoctl get felixConfiguration default -o yaml | grep bpf
# Verify kube-proxy is not running (if using eBPF mode)
kubectl get pods -n kube-system -l k8s-app=kube-proxy
Common eBPF Problems
If pods cannot reach ClusterIP services after enabling eBPF, the issue is often a stale kube-proxy iptables configuration. Flush the iptables rules and restart Calico:
# Remove kube-proxy iptables rules
iptables-save | grep -v KUBE | iptables-restore
# Restart calico-node to reload eBPF programs
kubectl delete pods -n kube-system -l k8s-app=calico-node
Verify eBPF programs are loaded:
# Check loaded Calico BPF programs
tc filter show dev eth0 ingress
tc filter show dev eth0 egress
# Use bpftool for detailed inspection
bpftool prog show | grep calico
Best Practices for Calico Operations
- Monitor Calico metrics: Calico exposes Prometheus metrics on port 9091. Scrape these to detect BGP session drops, IP pool exhaustion, and policy violations proactively.
- Use named selectors: Define reusable label selectors in Calico
GlobalNetworkPolicyresources to simplify policy management and reduce selector mismatch errors. - Pin Calico versions: Avoid auto-upgrading in production. Test new versions in staging, especially when switching dataplane modes.
- Document IP pool topology: Maintain a record of all IP pools, their CIDRs, and intended usage to prevent overlap and exhaustion surprises.
- Regularly run ipam checks: Schedule periodic
calicoctl ipam checkruns to catch orphaned allocations before they cause exhaustion. - Use Typha for large clusters: Deploy the Typha daemon to reduce Kubernetes API server load when running more than 50 nodes. Typha fans out Calico policy updates to node agents efficiently.
- Test BGP failover: In BGP-based deployments, regularly test node failure scenarios to ensure routes converge within your expected SLA.
- Keep calicoctl version aligned: Always use a
calicoctlversion that matches your Calico cluster version to avoid API compatibility issues.
Conclusion
Troubleshooting Calico networking requires a methodical approach that spans the Kubernetes API, the Calico control plane, BGP routing, and the underlying Linux dataplane. By understanding the common failure modes — from node initialization and IP autodetection to BGP peering, policy enforcement, and IP exhaustion — you can quickly narrow down the root cause and apply the appropriate fix. The key is to build a consistent diagnostic workflow: start with calicoctl node status and pod health, then drill into IP pools, policies, and kernel-level routing. Combined with proactive monitoring and adherence to best practices, this approach will keep your Calico-powered clusters healthy and resilient at any scale.