M6: anycast — pod lo + Ready-gated /128/32 + BIRD export
Build flock Image / build (push) Has been cancelled

CNI ADD now adds anycast IPs to the pod's lo interface (NOT eth0 — design
doc rationale: avoid NDP/ARP DAD conflicts when N replicas share an IP).
Allocation persists the anycast list.

AnycastReconciler:
  desired = { ip → flock<8hex> } from
            committed allocations × pod.Status.PodReady=True
  diff against advertised, install/remove host /128 (v6) or /32 (v4)
  re-render bird.conf with the active set

Triggers: 2s tick, AfterCommit (per ADD/DEL), Pod informer Ready
transitions (PodCache.OnReadyChange callback).

The bird template already supported Anycast6/Anycast4 via the export
filter — this turn finally drives those slices from runtime.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Donavan Fritz
2026-04-25 07:36:47 -05:00
parent c7fb159632
commit 89a3502446
7 changed files with 352 additions and 15 deletions
+29
View File
@@ -21,6 +21,10 @@ type SetupRequest struct {
HostIface string // host-side veth name from HostIfaceName
IP6 net.IP // /128 inside pod
IP4 net.IP // /32 inside pod (may be nil)
// Anycast IPs to add to pod's lo (NOT eth0). Mix of IPv6 and IPv4.
// Host /128 and /32 routes are NOT installed here — that happens once
// the pod becomes Ready, see AnycastReconciler.
Anycast []net.IP
}
// LinkLocalGW is the deterministic IPv6 LL gateway placed on every host
@@ -237,6 +241,31 @@ func configurePodSide(req SetupRequest) error {
}
}
// Anycast: assign each IP to pod lo. NOT on eth0 (avoids NDP/ARP
// DAD conflicts when multiple replicas share the same IP).
if len(req.Anycast) > 0 {
lo, err := netlink.LinkByName("lo")
if err != nil {
return fmt.Errorf("lookup pod lo: %w", err)
}
if err := netlink.LinkSetUp(lo); err != nil {
return fmt.Errorf("set up pod lo: %w", err)
}
for _, ip := range req.Anycast {
var mask net.IPMask
if ip.To4() != nil {
mask = net.CIDRMask(32, 32)
ip = ip.To4()
} else {
mask = net.CIDRMask(128, 128)
}
a := &netlink.Addr{IPNet: &net.IPNet{IP: ip, Mask: mask}, Scope: int(netlink.SCOPE_UNIVERSE)}
if err := netlink.AddrAdd(lo, a); err != nil && !errors.Is(err, os.ErrExist) {
return fmt.Errorf("pod lo anycast %s: %w", ip, err)
}
}
}
return nil
})
}