Enable Cilium BGP Networking with Bird and FRR in a Vagrant Lab
This guide walks through setting up a simulated Kubernetes cluster with Cilium, configuring BGP using FRR on a router node and Bird on worker nodes, and enabling Cilium's built‑in BGP speaker to achieve cross‑node pod communication and LoadBalancer IP advertisement.
Background
The official Cilium documentation provides several ways to integrate BGP. This article validates the following approaches: using BIRD, using kube‑router, native BGP, and the Cilium BGP control plane.
A simple network topology is created with Vagrant VMs: one router node with multiple NICs and two worker nodes (node1, node2) each with a single NIC. The workers’ default routes point to the router (node1 → 10.0.1.2, node2 → 10.0.2.2). All nodes run Kubernetes and Cilium.
Router Node System Settings
net.ipv4.ip_forward = 1
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
net.ipv6.conf.all.forwarding = 1Deploying Cilium with BGP (Bird) Backend
Cilium supports two pod CIDR routing modes: encapsulation and native‑routing. Because the worker nodes are on different L2 subnets, autoDirectNodeRoutes cannot be used, so BGP is required.
1. Install and Configure FRR on the Router
Install FRR from the official repository and enable the BGP daemon:
FRRVER="frr-stable"
curl -O https://rpm.frrouting.org/repo/${FRRVER}-repo-1-0.el7.noarch.rpm
sudo yum install ./${FRRVER}*
sudo yum install frr frr-pythontoolsEdit /etc/frr/daemons to set bgpd=yes, then create /etc/frr/frr.conf:
frr version 8.4.1
frr defaults traditional
hostname router
log syslog informational
!
router bgp 65100 # router ASN
bgp router-id 192.168.121.16
no bgp ebgp-requires-policy
neighbor 10.0.1.10 remote-as 65010 # node1
neighbor 10.0.2.10 remote-as 65020 # node2
!Start the service:
systemctl restart frr2. Deploy Cilium on the Workers
Apply the following Cilium configuration (as a cilium-config.yaml ConfigMap):
k8sServiceHost: "10.0.1.10"
k8sServicePort: 6443
kubeProxyReplacement: strict
device: eth1
ipam:
operator:
clusterPoolIPv4PodCIDR: "172.31.254.0/23"
clusterPoolIPv4MaskSize: 26
loadBalancer:
mode: dsr
tunnel: disabled
autoDirectNodeRoutes: false
bpf:
masquerade: true
ipv4NativeRoutingCIDR: "172.31.254.0/23"
socketLB:
enabled: true
nodePort:
enabled: true
externalIPs:
enabled: true
hostPort:
enabled: trueAfter the Cilium pods are ready, pods obtain IPs but cross‑node pod traffic does not work.
3. Install and Configure Bird2 on the Workers
Install Bird2: yum -y install bird2 Check the allocated PodCIDR ranges:
kubectl -n kube-system exec -it ds/cilium -- cilium node listCreate /etc/bird.conf on each worker:
router id 10.0.1.10;
protocol device {
scan time 10;
}
protocol direct {
disabled;
}
protocol kernel {
ipv4 {
import none;
export none;
};
}
protocol static {
ipv4;
route 172.31.254.0/26 via "cilium_host";
}
protocol bgp uplink0 {
description "BGP uplink 0";
local 10.0.1.10 as 65010; # ASN of this node
neighbor 10.0.1.2 as 65100; # router ASN
ipv4 {
import filter { reject; };
export filter { accept; };
};
}Start Bird and verify BGP sessions from the router:
# On router
vtysh -c "show bgp summary"
vtysh -c "show bgp ipv4 all"After these steps, node1 and node2 can communicate, and any server using the router as its default gateway can reach pod IPs.
Built‑in BGP Speaker (Cilium 1.10+)
From Cilium 1.10 onward, a native BGP speaker is included, eliminating the need for external Bird2. To enable it, create a ConfigMap named bgp-config in kube-system:
apiVersion: v1
kind: ConfigMap
metadata:
name: bgp-config
namespace: kube-system
data:
config.yaml: |
peers:
- peer-address: 192.168.121.16
peer-asn: 65100
my-asn: 65000
address-pools:
- name: default
protocol: bgp
addresses:
- 192.0.2.0/24Then enable BGP in the Cilium configuration:
bgp:
enabled: true
announce:
loadbalancerIP: true
podCIDR: true
loadBalancer:
mode: snat # dsr mode may have issuesLoadBalancer Service Example
apiVersion: v1
kind: Service
metadata:
name: whoami-lb
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
selector:
app: whoamiCilium allocates an external IP from the 192.0.2.0/24 pool (e.g., 192.0.2.x) and announces it via BGP.
ECMP and Advanced BGP Configuration
For production scenarios, add ECMP‑related settings on the router and keep static neighbor definitions:
router bgp 65100
bgp bestpath as-path multipath-relax
bgp bestpath bandwidth skip-missing
bgp router-id 192.168.121.16
no bgp ebgp-requires-policy
neighbor 10.0.1.10 remote-as 65000
neighbor 10.0.2.10 remote-as 65000
!Verify ECMP path selection:
vtysh -c "show bgp ipv4 unicast 192.0.2.0/32"BGP Control Plane Controller
Cilium’s BGP control‑plane controller (available in newer releases) provides fine‑grained management of the built‑in BGP speaker, extending the ConfigMap shown earlier.
References
Using BIRD to run BGP – https://docs.cilium.io/en/stable/gettingstarted/bird/
Using kube‑router to run BGP – https://docs.cilium.io/en/stable/gettingstarted/kube-router/
BGP – https://docs.cilium.io/en/stable/gettingstarted/bgp/
Cilium BGP Control Plane – https://docs.cilium.io/en/stable/gettingstarted/bgp-control-plane/
LoadBalancer IP Address Management – https://docs.cilium.io/en/latest/network/lb-ipam/
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
