Skip to content

Make Cilium BGP control plane a first-class LoadBalancer path for Cilium clusters #2804

Open

Description

Summary

On Cilium-based clusters, advertising LoadBalancer / externalIP service IPs over BGP via Cilium's own BGP control plane is cleaner than MetalLB — advertisement and the BPF datapath live in one place, with no MetalLB↔Cilium handoff to misalign. Cozystack technically supports this (the vendored Cilium chart exposes bgpControlPlane), but it's entirely manual and undocumented, and MetalLB is the default LB. The Cilium-BGP path should be made first-class: documented, and ideally toggleable.

Current state

  • MetalLB ships as a default system package (cozystack.metallb, pulled into the common system bundle via package.default) and is the out-of-the-box LoadBalancer implementation.
  • The vendored Cilium chart supports bgpControlPlane (packages/system/cilium/charts/cilium/values.yaml, default false). Cilium's operator registers the CiliumBGP* CRDs at runtime when it's enabled.
  • Cozystack does not pin cilium.devices — Cilium auto-detects, so on multi-NIC nodes the BPF LB datapath may not attach to the interface that carries the BGP session, and north-south LB traffic loops back to the upstream router.

What an operator has to do today (manual, undocumented)

  1. Disable MetalLB: bundles.disabledPackages: [cozystack.metallb].
  2. Enable Cilium BGP via the Cilium Package: cilium.bgpControlPlane.enabled: true.
  3. Pin cilium.devices to include the BGP-facing NIC, otherwise the LB IP loops (Cilium does not add a host route by design — the BPF datapath must catch the packet on a managed device).
  4. Apply CiliumBGPClusterConfig / CiliumBGPPeerConfig / CiliumBGPAdvertisement CRs by hand.

Proposal

  • Document the Cilium-BGP LoadBalancer path in the networking docs: the MetalLB mutual-exclusion, the cilium.devices requirement, and a working set of CiliumBGP CRs.
  • Optionally expose it as a supported toggle (e.g. a publishing-level switch or a Cilium Package variant) so operators don't hand-assemble it and MetalLB is disabled automatically when it's selected.

Background

Surfaced from a user exposing tenant-root ingress-nginx over BGP: switching from MetalLB to the Cilium BGP control plane advertised the IP correctly, but traffic looped — Cilium doesn't add a host route (by design) and the BPF datapath wasn't attached to the BGP NIC because cilium.devices was unset.

Activity

  1. added
    kind/featureCategorizes issue or PR as related to a new feature
    area/networkingIssues or PRs related to networking (ingress, gateway, vpn, metallb, kube-ovn)
    on Jun 3, 2026
  2. lexfrei commented on Jun 3, 2026

    @lexfrei
    ContributorAuthor

    Independently corroborated from a separate field deployment (L3 + FRR): Cilium's external LoadBalancer datapath did not work until the ethernet interfaces were pinned explicitly (cilium.devices: 'eno5np0 eno6np1 dummy0 lo'). Same root cause as this issue — auto-detection misses the NIC carrying the LB traffic, so the BPF LB program isn't attached there. Reinforces pinning cilium.devices as part of the first-class BGP-LB path.

  3. lexfrei commented on Jun 4, 2026

    @lexfrei
    ContributorAuthor

    Follow-up from the same thread: once the Cilium-BGP path is working, a recurring source of confusion is that traceroute / ping / ICMP to the LoadBalancer VIP shows a routing loop even though the service is fully reachable. This is expected — Cilium's BPF LB only DNATs packets that match a service L4 backend (e.g. TCP :443), so ICMP and non-service ports fall through to the kernel's default route and bounce back to the upstream router. It has zero effect on real traffic. The networking docs this issue calls for should include that note explicitly, and recommend monitoring the service port (a TCP connect probe) rather than an ICMP ping of the VIP — it's a cosmetic symptom that reads as a misconfiguration and costs hours to chase down.

  4. added
    triage/acceptedIndicates an issue is ready to be actively worked on
    priority/important-longtermImportant over the long term, but may not be staffed and/or may need multiple releases to complete
    on Jul 1, 2026
  5. added
    area/ciliumIssues or PRs related to Cilium (agent, operator, Gateway API, network policy, LB-IPAM)
    on Aug 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/ciliumIssues or PRs related to Cilium (agent, operator, Gateway API, network policy, LB-IPAM)area/networkingIssues or PRs related to networking (ingress, gateway, vpn, metallb, kube-ovn)kind/featureCategorizes issue or PR as related to a new featurepriority/important-longtermImportant over the long term, but may not be staffed and/or may need multiple releases to completetriage/acceptedIndicates an issue is ready to be actively worked on

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions