|
|
|
@@ -0,0 +1,209 @@
|
|
|
|
|
apiVersion: v1
|
|
|
|
|
kind: ConfigMap
|
|
|
|
|
metadata:
|
|
|
|
|
name: bird-config
|
|
|
|
|
namespace: kube-system
|
|
|
|
|
data:
|
|
|
|
|
bird.conf: |
|
|
|
|
|
# Per-node addresses, written by the init container from bird-nodes.
|
|
|
|
|
include "/etc/bird/node.conf";
|
|
|
|
|
|
|
|
|
|
router id from "pod0";
|
|
|
|
|
log stderr all;
|
|
|
|
|
|
|
|
|
|
# Mirrors of the kernel main table, filtered down to this node's own pod
|
|
|
|
|
# CIDR. master4/master6 are implicit and hold what BGP exchanges.
|
|
|
|
|
ipv4 table kmain4;
|
|
|
|
|
ipv6 table kmain6;
|
|
|
|
|
|
|
|
|
|
protocol device { scan time 10; }
|
|
|
|
|
|
|
|
|
|
# Cilium's routes for the OTHER nodes' pod CIDRs are protocol kernel too,
|
|
|
|
|
# so the prefix alone does not identify the local one. The outgoing
|
|
|
|
|
# interface does: local is cilium_host, learned is mgmt0. ifname is set for
|
|
|
|
|
# the gatewayless IPv6 device route as well.
|
|
|
|
|
filter own_pod4 {
|
|
|
|
|
if ! (net ~ [ 10.244.0.0/16{17,32} ]) then reject;
|
|
|
|
|
if ifname !~ "cilium_host" then reject;
|
|
|
|
|
accept;
|
|
|
|
|
}
|
|
|
|
|
filter own_pod6 {
|
|
|
|
|
if ! (net ~ [ fd10:244::/48{49,128} ]) then reject;
|
|
|
|
|
if ifname !~ "cilium_host" then reject;
|
|
|
|
|
accept;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# learn all, not learn: plain learn skips routes marked proto kernel, which
|
|
|
|
|
# is what Cilium's are.
|
|
|
|
|
protocol kernel klearn4 {
|
|
|
|
|
learn all;
|
|
|
|
|
scan time 10;
|
|
|
|
|
ipv4 { table kmain4; import filter own_pod4; export none; };
|
|
|
|
|
}
|
|
|
|
|
protocol kernel klearn6 {
|
|
|
|
|
learn all;
|
|
|
|
|
scan time 10;
|
|
|
|
|
ipv6 { table kmain6; import filter own_pod6; export none; };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protocol pipe own4 { table kmain4; peer table master4; export all; import none; }
|
|
|
|
|
protocol pipe own6 { table kmain6; peer table master6; export all; import none; }
|
|
|
|
|
|
|
|
|
|
# Only BGP-learned routes reach table 48. The local CIDR stays out of it —
|
|
|
|
|
# it is already reachable via cilium_host in main.
|
|
|
|
|
filter to_t48 {
|
|
|
|
|
if source != RTS_BGP then reject;
|
|
|
|
|
accept;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protocol kernel k48v4 {
|
|
|
|
|
kernel table 48;
|
|
|
|
|
metric 0;
|
|
|
|
|
ipv4 { table master4; import none; export filter to_t48; };
|
|
|
|
|
}
|
|
|
|
|
protocol kernel k48v6 {
|
|
|
|
|
kernel table 48;
|
|
|
|
|
metric 0;
|
|
|
|
|
ipv6 { table master6; import none; export filter to_t48; };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# iBGP full mesh over pod0. 64514 keeps clear of Cilium's 64513, which
|
|
|
|
|
# peers with the UDM from ingress0 and is unrelated to this.
|
|
|
|
|
#
|
|
|
|
|
# direct is explicit because iBGP defaults to multihop, which makes the
|
|
|
|
|
# gateway recursive — BIRD would try to resolve the peer in the pod RIB.
|
|
|
|
|
# strict bind keeps the listener off mgmt0 and ingress0.
|
|
|
|
|
template bgp pod4 {
|
|
|
|
|
local as 64514;
|
|
|
|
|
source address MY4;
|
|
|
|
|
direct;
|
|
|
|
|
strict bind;
|
|
|
|
|
ipv4 {
|
|
|
|
|
next hop self;
|
|
|
|
|
import filter { if net ~ [ 10.244.0.0/16{17,32} ] then accept; reject; };
|
|
|
|
|
export filter { if net ~ [ 10.244.0.0/16{17,32} ] then accept; reject; };
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
template bgp pod6 {
|
|
|
|
|
local as 64514;
|
|
|
|
|
source address MY6;
|
|
|
|
|
direct;
|
|
|
|
|
strict bind;
|
|
|
|
|
ipv6 {
|
|
|
|
|
next hop self;
|
|
|
|
|
import filter { if net ~ [ fd10:244::/48{49,128} ] then accept; reject; };
|
|
|
|
|
export filter { if net ~ [ fd10:244::/48{49,128} ] then accept; reject; };
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protocol bgp p1v4 from pod4 { neighbor P1_4 as 64514; }
|
|
|
|
|
protocol bgp p2v4 from pod4 { neighbor P2_4 as 64514; }
|
|
|
|
|
protocol bgp p1v6 from pod6 { neighbor P1_6 as 64514; }
|
|
|
|
|
protocol bgp p2v6 from pod6 { neighbor P2_6 as 64514; }
|
|
|
|
|
---
|
|
|
|
|
apiVersion: v1
|
|
|
|
|
kind: ConfigMap
|
|
|
|
|
metadata:
|
|
|
|
|
name: bird-nodes
|
|
|
|
|
namespace: kube-system
|
|
|
|
|
data:
|
|
|
|
|
# One key per node, selected by name. The addresses are the pod0 statics from
|
|
|
|
|
# kubernetes/talos/patches/k8s-{1,2,3}.yaml; a node added there needs a key
|
|
|
|
|
# here and a peer line in the other two.
|
|
|
|
|
k8s-1: |
|
|
|
|
|
define MY4 = 10.2.48.11;
|
|
|
|
|
define MY6 = fd02:48::11;
|
|
|
|
|
define P1_4 = 10.2.48.12;
|
|
|
|
|
define P1_6 = fd02:48::12;
|
|
|
|
|
define P2_4 = 10.2.48.13;
|
|
|
|
|
define P2_6 = fd02:48::13;
|
|
|
|
|
k8s-2: |
|
|
|
|
|
define MY4 = 10.2.48.12;
|
|
|
|
|
define MY6 = fd02:48::12;
|
|
|
|
|
define P1_4 = 10.2.48.11;
|
|
|
|
|
define P1_6 = fd02:48::11;
|
|
|
|
|
define P2_4 = 10.2.48.13;
|
|
|
|
|
define P2_6 = fd02:48::13;
|
|
|
|
|
k8s-3: |
|
|
|
|
|
define MY4 = 10.2.48.13;
|
|
|
|
|
define MY6 = fd02:48::13;
|
|
|
|
|
define P1_4 = 10.2.48.11;
|
|
|
|
|
define P1_6 = fd02:48::11;
|
|
|
|
|
define P2_4 = 10.2.48.12;
|
|
|
|
|
define P2_6 = fd02:48::12;
|
|
|
|
|
---
|
|
|
|
|
apiVersion: apps/v1
|
|
|
|
|
kind: DaemonSet
|
|
|
|
|
metadata:
|
|
|
|
|
name: bird
|
|
|
|
|
namespace: kube-system
|
|
|
|
|
labels:
|
|
|
|
|
tier: node
|
|
|
|
|
app: bird
|
|
|
|
|
spec:
|
|
|
|
|
selector:
|
|
|
|
|
matchLabels:
|
|
|
|
|
app: bird
|
|
|
|
|
updateStrategy:
|
|
|
|
|
type: RollingUpdate
|
|
|
|
|
template:
|
|
|
|
|
metadata:
|
|
|
|
|
labels:
|
|
|
|
|
tier: node
|
|
|
|
|
app: bird
|
|
|
|
|
spec:
|
|
|
|
|
# Carries pod east-west once the routing rules land, so a node without it
|
|
|
|
|
# falls back to VLAN 40 rather than losing connectivity.
|
|
|
|
|
priorityClassName: system-node-critical
|
|
|
|
|
# Writes host routes and peers on host addresses.
|
|
|
|
|
hostNetwork: true
|
|
|
|
|
# Every node here is a control plane node, so this is not optional.
|
|
|
|
|
tolerations:
|
|
|
|
|
- operator: Exists
|
|
|
|
|
effect: NoSchedule
|
|
|
|
|
initContainers:
|
|
|
|
|
# bird.conf is identical everywhere; node.conf is this node's key.
|
|
|
|
|
- name: render-config
|
|
|
|
|
image: gitea.renner.uno/gitea_admin/bird:2026-09-16
|
|
|
|
|
command: ["/bin/sh", "-c"]
|
|
|
|
|
args:
|
|
|
|
|
- cp /config/bird.conf /etc/bird/bird.conf && cp /nodes/"$NODE_NAME" /etc/bird/node.conf
|
|
|
|
|
env:
|
|
|
|
|
- name: NODE_NAME
|
|
|
|
|
valueFrom:
|
|
|
|
|
fieldRef:
|
|
|
|
|
fieldPath: spec.nodeName
|
|
|
|
|
volumeMounts:
|
|
|
|
|
- name: config
|
|
|
|
|
mountPath: /config
|
|
|
|
|
- name: nodes
|
|
|
|
|
mountPath: /nodes
|
|
|
|
|
- name: etc-bird
|
|
|
|
|
mountPath: /etc/bird
|
|
|
|
|
containers:
|
|
|
|
|
- name: bird
|
|
|
|
|
image: gitea.renner.uno/gitea_admin/bird:2026-09-16
|
|
|
|
|
resources:
|
|
|
|
|
requests:
|
|
|
|
|
cpu: "50m"
|
|
|
|
|
memory: "32Mi"
|
|
|
|
|
limits:
|
|
|
|
|
cpu: "200m"
|
|
|
|
|
memory: "128Mi"
|
|
|
|
|
securityContext:
|
|
|
|
|
capabilities:
|
|
|
|
|
drop: ["ALL"]
|
|
|
|
|
# NET_ADMIN writes the routes; NET_BIND_SERVICE binds 179.
|
|
|
|
|
add: ["NET_ADMIN", "NET_BIND_SERVICE"]
|
|
|
|
|
volumeMounts:
|
|
|
|
|
- name: etc-bird
|
|
|
|
|
mountPath: /etc/bird
|
|
|
|
|
volumes:
|
|
|
|
|
- name: config
|
|
|
|
|
configMap:
|
|
|
|
|
name: bird-config
|
|
|
|
|
- name: nodes
|
|
|
|
|
configMap:
|
|
|
|
|
name: bird-nodes
|
|
|
|
|
- name: etc-bird
|
|
|
|
|
emptyDir: {}
|