labsim: add IPv6 BGP config layer for the Gateway-API public-v6 rehearsal
Some checks failed
Some checks failed
The sim's eBGP was IPv4-only; extend it to the v6 family so labsim can rehearse
Cilium BGP advertising a public-style v6 LoadBalancer /64 to the VyOS pair before
it touches production (approved plan: public IPv6 via Cilium BGP + Gateway API).
- sim-net-config.py: bgp6 inside bgp() -- ipv6-unicast peer-group K8S6 over
fd00:2::11/12/13, prefix-list6 (le 128, /128 host routes), K8S-IN6/OUT6 route-maps
(export deny -- never hand the cluster a default). ULA fd61:1e00::/64 as the sim
LB range so nothing leaks into the real HE /48. All v6 lines pass the
sim-net-apply.sh whitelist.
- sim-ha-config.py: VLANS6 = {2: fd00:2/64} -> routers hold fd00:2::252/253 on
bond0.2 so they can peer the nodes over v6 (no v6 VRRP VIP; BGP peers the per-box
address, as production).
- k8s-up.sh: nodes get fd00:2::11/12/13 + dual-stack k3s (dual node-ip, dual
cluster/service CIDR). Peers line up with sim-net-config K8S_NODES_V6.
Config-gen verified for all three. Live chunk (Cilium v6+BGP+Gateway install,
bring-up, datapath/#26847 proof) is next.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DMVzWZgiKW2wquf5z8S1yH
This commit is contained in:
@@ -38,6 +38,14 @@ K8S_VLAN="${K8S_VLAN:-2}"
|
||||
K8S_PREFIX="${K8S_PREFIX:-172.31.2}"
|
||||
K8S_NODES="${K8S_NODES:-3}"
|
||||
K8S_FIRST_OCTET="${K8S_FIRST_OCTET:-11}"
|
||||
# Dual-stack, mirroring production's shape (not its addresses). VLAN 2 v6 is a
|
||||
# ULA so nothing here can leak into the real HE /48; node fd00:2::1x matches the
|
||||
# BGP peers in sim-net-config.py (K8S_NODES_V6). cluster/service v6 are ULAs too;
|
||||
# the LB pool fd61:1e00::/64 is what Cilium advertises (SERVICE_CIDR_V6 there).
|
||||
K8S_PREFIX_V6="${K8S_PREFIX_V6:-fd00:2}" # nodes fd00:2::11/12/13, router ::252/::253
|
||||
K8S_ROUTER_V6="${K8S_ROUTER_V6:-fd00:2::252}" # v6 next-hop (primary router bond0.2)
|
||||
CLUSTER_CIDR_V6="${CLUSTER_CIDR_V6:-fd00:42::/56}"
|
||||
SERVICE_CIDR_V6="${SERVICE_CIDR_V6:-fd00:43::/112}"
|
||||
K8S_MEM="${K8S_MEM:-4096}" # MB — k3s + cilium + a workload
|
||||
K8S_CPUS="${K8S_CPUS:-2}"
|
||||
K8S_DISK_GB="${K8S_DISK_GB:-12}"
|
||||
@@ -53,6 +61,7 @@ CILIUM_VERSION="${CILIUM_VERSION:-1.19.1}"
|
||||
|
||||
node_name() { echo "labsim-k8s$1"; }
|
||||
node_ip() { echo "${K8S_PREFIX}.$((K8S_FIRST_OCTET + $1 - 1))"; }
|
||||
node_ip6() { echo "${K8S_PREFIX_V6}::$((K8S_FIRST_OCTET + $1 - 1))"; }
|
||||
|
||||
# --- base image -----------------------------------------------------------
|
||||
ensure_base_image() {
|
||||
@@ -75,7 +84,7 @@ ensure_base_image() {
|
||||
# before joining, because cloud-init ordering across VMs is not guaranteed and
|
||||
# a failed join leaves an agent that never retries.
|
||||
build_k8s_seed() {
|
||||
local iso="$1" vm="$2" ip="$3" role="$4" server_ip="$5" pubkey="$6"
|
||||
local iso="$1" vm="$2" ip="$3" role="$4" server_ip="$5" pubkey="$6" ip6="$7" server_ip6="$8"
|
||||
local tmp; tmp="$(mktemp -d)"
|
||||
|
||||
cat > "$tmp/meta-data" <<EOF
|
||||
@@ -89,7 +98,7 @@ ethernets:
|
||||
enp1s0:
|
||||
match:
|
||||
name: "en*"
|
||||
addresses: [$ip/24]
|
||||
addresses: [$ip/24, $ip6/64]
|
||||
routes:
|
||||
- to: default
|
||||
via: ${K8S_PREFIX}.1
|
||||
@@ -100,10 +109,13 @@ EOF
|
||||
local k3s_exec
|
||||
if [ "$role" = "server" ]; then
|
||||
# flannel/servicelb/traefik off: Cilium is the CNI under test, and k3s's
|
||||
# own ServiceLB would fight Cilium for LoadBalancer addresses.
|
||||
k3s_exec="server --flannel-backend=none --disable-network-policy --disable=servicelb --disable=traefik --node-ip=$ip --tls-san=$ip --cluster-init"
|
||||
# own ServiceLB would fight Cilium for LoadBalancer addresses. Dual-stack:
|
||||
# both families in cluster-cidr/service-cidr and a dual node-ip, mirroring
|
||||
# production. Pod IPs come from Cilium cluster-pool (node.spec.podCIDRs is
|
||||
# immutable), so cluster-cidr v6 just marks the cluster dual-stack.
|
||||
k3s_exec="server --flannel-backend=none --disable-network-policy --disable=servicelb --disable=traefik --node-ip=$ip,$ip6 --tls-san=$ip --cluster-cidr=10.42.0.0/16,${CLUSTER_CIDR_V6} --service-cidr=10.43.0.0/16,${SERVICE_CIDR_V6} --cluster-init"
|
||||
else
|
||||
k3s_exec="agent --server https://${server_ip}:6443 --node-ip=$ip"
|
||||
k3s_exec="agent --server https://${server_ip}:6443 --node-ip=$ip,$ip6"
|
||||
fi
|
||||
|
||||
cat > "$tmp/user-data" <<EOF
|
||||
@@ -170,8 +182,10 @@ create_node() {
|
||||
local n="$1" pubkey="$2"
|
||||
local vm; vm="$(node_name "$n")"
|
||||
local ip; ip="$(node_ip "$n")"
|
||||
local ip6; ip6="$(node_ip6 "$n")"
|
||||
local role="agent"; [ "$n" -eq 1 ] && role="server"
|
||||
local server_ip; server_ip="$(node_ip 1)"
|
||||
local server_ip6; server_ip6="$(node_ip6 1)"
|
||||
|
||||
if virsh_q dominfo "$vm" >/dev/null 2>&1; then
|
||||
local state; state="$(virsh_q domstate "$vm" 2>/dev/null | head -1 | tr -d '\n')"
|
||||
@@ -189,7 +203,7 @@ create_node() {
|
||||
|
||||
log "creating $vm ($ip, $role, ${K8S_MEM}MB/${K8S_CPUS}cpu)"
|
||||
sudo qemu-img create -q -f qcow2 -F qcow2 -b "$DEB_BASE" "$disk" "${K8S_DISK_GB}G" >/dev/null
|
||||
build_k8s_seed "$seed" "$vm" "$ip" "$role" "$server_ip" "$pubkey"
|
||||
build_k8s_seed "$seed" "$vm" "$ip" "$role" "$server_ip" "$pubkey" "$ip6" "$server_ip6"
|
||||
|
||||
# Access port on the k8s VLAN — same broadcast domain as the routers'
|
||||
# bond0.2 leg, so BGP peering is directly connected exactly as in production.
|
||||
|
||||
Reference in New Issue
Block a user