Replies from Cilium LoadBalancer VIPs now leave the node over ingress0, where the requests arrive as the BGP next hop. Before, they went out over mgmt0.
A VIP reply reaches the kernel's routing decision with the VIP as its source.
The pod-source rules 1000 (fd10:244::/48) and 1001 (10.244.0.0/16) therefore miss it.
Main's default then sends it out mgmt0 (10.2.40.1).
Seen on k8s-3, 2026-11-02: replies from 10.2.99.90 (shelly-manager-firmware) to an IoT device appear only on mgmt0, while the device's requests and ACKs arrive on ingress0.
The LoadBalancer pool as a site fact: inline manifest lb-pool-site (ConfigMap, flux-system) with LB_POOL_V4/LB_POOL_V6, next to the rules.
site-qemu.yaml, site-hcloud.yaml: the same lb-pool-site. Services pin their addresses from the production pool, so a test run carries the same pool.
infrastructure/post-crds/cilium-bgp.yaml: bgp-pool takes its blocks from ${LB_POOL_V4} and ${LB_POOL_V6} as CIDR blocks.
With Cilium 1.20 a CIDR block uses all its addresses (allowFirstLastIPs defaults to Yes), so the blocks cover exactly the former start/stop ranges.
clusters/homelab/infrastructure.yaml: infrastructure-crds substitutes from lb-pool-site as well as cluster-settings.
NETWORK-traffic-classes.md: the LoadBalancer reply rule.
Rollout
Talos creates inline manifests at bootstrap; on the running cluster lb-pool-site has to exist before this merges. Without it the substitution fails and infrastructure-crds stops reconciling. It is created once by hand with the same content, before the merge.
The routing rules reach the running nodes with talosctl patch machineconfig, k8s-3 first. Network config applies without a reboot.
Replies from Cilium LoadBalancer VIPs now leave the node over `ingress0`, where the requests arrive as the BGP next hop. Before, they went out over `mgmt0`.
Closes #1547.
**Why**
- A VIP reply reaches the kernel's routing decision with the VIP as its source.
- The pod-source rules 1000 (`fd10:244::/48`) and 1001 (`10.244.0.0/16`) therefore miss it.
- Main's default then sends it out `mgmt0` (`10.2.40.1`).
- Seen on k8s-3, 2026-11-02: replies from `10.2.99.90` (`shelly-manager-firmware`) to an IoT device appear only on `mgmt0`, while the device's requests and ACKs arrive on `ingress0`.
**Change**
- `talos/patches/site-homelab.yaml`:
- RoutingRuleConfig 1002 (`src fd99::/120`) and 1003 (`src 10.2.99.0/24`) → table 47.
- The LoadBalancer pool as a site fact: inline manifest `lb-pool-site` (ConfigMap, `flux-system`) with `LB_POOL_V4`/`LB_POOL_V6`, next to the rules.
- `site-qemu.yaml`, `site-hcloud.yaml`: the same `lb-pool-site`. Services pin their addresses from the production pool, so a test run carries the same pool.
- `infrastructure/post-crds/cilium-bgp.yaml`: `bgp-pool` takes its blocks from `${LB_POOL_V4}` and `${LB_POOL_V6}` as CIDR blocks.
- With Cilium 1.20 a CIDR block uses all its addresses (`allowFirstLastIPs` defaults to `Yes`), so the blocks cover exactly the former `start`/`stop` ranges.
- `clusters/homelab/infrastructure.yaml`: `infrastructure-crds` substitutes from `lb-pool-site` as well as `cluster-settings`.
- `NETWORK-traffic-classes.md`: the LoadBalancer reply rule.
**Rollout**
- Talos creates inline manifests at bootstrap; on the running cluster `lb-pool-site` has to exist before this merges. Without it the substitution fails and `infrastructure-crds` stops reconciling. It is created once by hand with the same content, before the merge.
- The routing rules reach the running nodes with `talosctl patch machineconfig`, k8s-3 first. Network config applies without a reboot.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_0185Qb5YG28FfnVi1ujMEV5C
A reply from a Cilium LoadBalancer VIP reaches the routing decision with
the VIP as its source, so the pod-source rules 1000/1001 missed it and
main sent it out mgmt0 while the request came in over ingress0, the BGP
next hop (k8s-3, 2026-11-02: replies from 10.2.99.90 to an IoT device
seen only on mgmt0). Rules 1002/1003 send the pool to table 47.
The pool becomes a site fact: each site patch carries lb-pool-site
(flux-system), and bgp-pool takes its blocks from it by Flux
substitution in infrastructure-crds. The CIDR blocks cover the same
addresses as the start/stop ranges did (allowFirstLastIPs defaults to
Yes). The qemu and hcloud sites carry the production pool, since
Services pin their addresses from it.
Refs #1547
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0185Qb5YG28FfnVi1ujMEV5C
claude-bot
requested review from review-bot 2026-11-02 07:43:05 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Replies from Cilium LoadBalancer VIPs now leave the node over
ingress0, where the requests arrive as the BGP next hop. Before, they went out overmgmt0.Closes #1547.
Why
fd10:244::/48) and 1001 (10.244.0.0/16) therefore miss it.mgmt0(10.2.40.1).10.2.99.90(shelly-manager-firmware) to an IoT device appear only onmgmt0, while the device's requests and ACKs arrive oningress0.Change
talos/patches/site-homelab.yaml:src fd99::/120) and 1003 (src 10.2.99.0/24) → table 47.lb-pool-site(ConfigMap,flux-system) withLB_POOL_V4/LB_POOL_V6, next to the rules.site-qemu.yaml,site-hcloud.yaml: the samelb-pool-site. Services pin their addresses from the production pool, so a test run carries the same pool.infrastructure/post-crds/cilium-bgp.yaml:bgp-pooltakes its blocks from${LB_POOL_V4}and${LB_POOL_V6}as CIDR blocks.allowFirstLastIPsdefaults toYes), so the blocks cover exactly the formerstart/stopranges.clusters/homelab/infrastructure.yaml:infrastructure-crdssubstitutes fromlb-pool-siteas well ascluster-settings.NETWORK-traffic-classes.md: the LoadBalancer reply rule.Rollout
lb-pool-sitehas to exist before this merges. Without it the substitution fails andinfrastructure-crdsstops reconciling. It is created once by hand with the same content, before the merge.talosctl patch machineconfig, k8s-3 first. Network config applies without a reboot.🤖 Generated with Claude Code
https://claude.ai/code/session_0185Qb5YG28FfnVi1ujMEV5C