Skip to content

OPNET-783: network: Add BGP VIP management support#3047

Open
mkowalski wants to merge 4 commits into
openshift:masterfrom
mkowalski:bgp-vip-management
Open

OPNET-783: network: Add BGP VIP management support#3047
mkowalski wants to merge 4 commits into
openshift:masterfrom
mkowalski:bgp-vip-management

Conversation

@mkowalski

@mkowalski mkowalski commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

What

CNO side of BGP-based VIP management (enhancement openshift/enhancements#1982, epic OPNET-595). Four commits:

  1. FRRConfiguration rendering: when BGP VIP management is active, CNO reads the installer-generated bgp-vip-config ConfigMap and renders a cluster-wide bgp-vip FRRConfiguration (no node selector: the masters' static-pod controller and the workers' DaemonSet consume the same object) carrying the BGP sessions (neighbors, passwords, BFD). Advertisement deliberately stays out of the CRD surface (CRD prefixes render as unconditional network statements, defeating kube-vip's health gating — validated failure mode) and is carried in rawConfig: per-family health-gated redistribute table-direct 198 behind route-map/prefix-list filters, plus high-sequence permits appended to frr-k8s's generated per-neighbor -out route-maps (frr-k8s renders deny-any egress without toAdvertise; prefix-list deny = route-map no-match = fall-through, so egress opens exactly for the VIP prefixes). No ip import-table is needed: table-direct reads the kernel table directly (lab-verified; a first upstreaming step to express this natively in the frr-k8s CRD is design: redistribute support metallb/frr-k8s#470).
  2. DaemonSet placement: under BGP VIP management the frr-k8s DaemonSet gets required node-affinity excluding control plane nodes by role — masters run the MCO-deployed frr-k8s static pod, workers the DaemonSet. Label-based approaches were validated broken (NodeRestriction denies node-credential label writes; DaemonSet scheduling races labeling).
  3. Static pod RBAC: the static pod authenticates with the node kubeconfig, whose identity is the openshift-machine-config-operator/node-bootstrapper ServiceAccount (verified live) — grants for FRRConfiguration/FRRK8sConfiguration reads, node state CR writes, and namespace-scoped secrets/pods reads. Per-node write scoping is a documented pre-GA follow-up (needs admission-level enforcement).
  4. Static pod metrics: static pods cannot mount Secrets, so the FRR metrics exporter runs in a masters-only companion DaemonSet reading the static pod's FRR through the hostPath sockets MCO exposes under /run/frr-k8s, serving TLS with a serving certificate via its own Service/ServiceMonitor. Workers keep the regular in-DaemonSet exporter — together this gives full per-node BGP metric coverage.

Why

On-prem VIP failover today relies on keepalived (VRRP), which requires L2 adjacency between nodes. BGP-based VIP management (enhancement 1982, feature gate BGPBasedVIPManagement) advertises the API and Ingress VIPs as /32 (/128) BGP routes instead: health-gated per node, ECMP across healthy nodes, no L2 requirement — enabling routed (L3/spine-leaf) datacenter topologies. CNO's part is rendering the frr-k8s session/advertisement config and keeping the frr-k8s DaemonSet off nodes that run the MCO-rendered static pods.

Merge safety — no openshift/api dependency

openshift/api#2923 (OPNET-780) is not merged yet, so this PR deliberately avoids the new vendored types:

  • The BGPBasedVIPManagement gate name is a local configv1.FeatureGateName constant; a KnownFeatures guard makes every new path a no-op on any cluster whose FeatureGate status does not know the gate — i.e. this code is inert everywhere until OPNET-780: Add BGPBasedVIPManagement feature gate and BGP VIP management fields api#2923 and its cluster-config plumbing ship.
  • Infrastructure.status.platformStatus.baremetal.vipManagement is read unstructured (the CRD field is equally gated api-side).

A small follow-up will switch both to typed access once the api merges and re-vendors. No vendor/, go.mod or default-behavior changes; featureSet: Default/TechPreview clusters are untouched.

Testing

Unit (run in ci/prow/unit): per-commit coverage — schema round-trip incl. full installer-shaped payloads and dual-stack, rawConfig content, input validation (IP/injection), render-var/affinity/RBAC-gating branches, bindata object counts; go test ./pkg/... fully green.

CI lanes on this PR: the standard CNO presubmits (e2e-aws-ovn, e2e-metal-ipi-ovn-ipv6, e2e-gcp-ovn, etc.) exercise the inert path — the gate is DevPreviewNoUpgrade and no CI platform sets vipManagement: BGP, so these lanes prove zero behavior change for existing FRR/MetalLB users (the render tests additionally pin the inactive path explicitly).

Feature e2e: this repository has no in-repo e2e suite (there is no test/e2e/ directory — CNO is covered by the openshift/origin e2e framework via the prow lanes above). Feature-specific e2e is additionally not yet automatable in openshift/release — it requires a BGP ToR peer next to the cluster. A containerized ToR pattern for CI exists (validated in the reference implementation, dev-scripts PR openshift-metal3/dev-scripts#1929) and dedicated [OCPFeatureGate:BGPBasedVIPManagement] e2e lanes are tracked as OPNET-621/622/623 per the enhancement's graduation criteria.

Live validation: end to end in the enhancement reference implementation across 21 dev-scripts baremetal installs (3-master compact and 3+2 with routers on workers) — install over a BGP-advertised API VIP, health-gated ECMP for API+Ingress VIPs, router-kill failover (withdraw ~50s, restore ≤20s), CRD handover, and Prometheus scraping frrk8s_* metrics from all five nodes (masters via the companion DaemonSet, workers via the regular one) with zero dead targets: https://github.com/mkowalski/bgp-vip-demo.

Related: #3046 (statusmanager fix this feature exposed), openshift/api#2923, openshift/baremetal-runtimecfg#395, openshift-metal3/dev-scripts#1929, kube-vip/kube-vip#1627.

CNO subtask: OPNET-783.

@openshift-ci-robot

openshift-ci-robot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

@mkowalski: This pull request references OPNET-783 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "5.0.0" version, but no target version was set.

Details

In response to this:

What

CNO side of BGP-based VIP management (enhancement openshift/enhancements#1982, epic OPNET-595). Three commits:

  1. FRRConfiguration rendering: when BGP VIP management is active, CNO reads the installer-generated bgp-vip-config ConfigMap and renders a bgp-vip-master FRRConfiguration carrying the BGP sessions (neighbors, passwords, BFD). Advertisement deliberately stays out of the CRD surface (CRD prefixes render as unconditional network statements, defeating kube-vip's health gating — validated failure mode) and is carried in rawConfig: ip import-table 198, per-family health-gated redistribute table-direct 198 behind route-map/prefix-list filters, plus high-sequence permits appended to frr-k8s's generated per-neighbor -out route-maps (frr-k8s renders deny-any egress without toAdvertise; prefix-list deny = route-map no-match = fall-through, so egress opens exactly for the VIP prefixes).
  2. DaemonSet placement: under BGP VIP management the frr-k8s DaemonSet gets required node-affinity excluding control plane nodes by role — masters run the MCO-deployed frr-k8s static pod, workers the DaemonSet. Label-based approaches were validated broken (NodeRestriction denies node-credential label writes; DaemonSet scheduling races labeling).
  3. Static pod RBAC: the static pod authenticates with the node kubeconfig, whose identity is the openshift-machine-config-operator/node-bootstrapper ServiceAccount (verified live) — grants for FRRConfiguration/FRRK8sConfiguration reads, node state CR writes, and namespace-scoped secrets/pods reads. Per-node write scoping is a documented pre-GA follow-up (needs admission-level enforcement).

Merge safety — no openshift/api dependency

openshift/api#2923 (OPNET-780) is not merged yet, so this PR deliberately avoids the new vendored types:

  • The BGPBasedVIPManagement gate name is a local configv1.FeatureGateName constant; a KnownFeatures guard makes every new path a no-op on any cluster whose FeatureGate status does not know the gate — i.e. this code is inert everywhere until OPNET-780: Add BGPBasedVIPManagement feature gate and BGP VIP management fields api#2923 and its cluster-config plumbing ship.
  • Infrastructure.status.platformStatus.baremetal.vipManagement is read unstructured (the CRD field is equally gated api-side).

A small follow-up will switch both to typed access once the api merges and re-vendors. No vendor/, go.mod or default-behavior changes; featureSet: Default/TechPreview clusters are untouched.

Testing

Unit tests per commit (schema round-trip incl. full installer-shaped payloads and dual-stack, rawConfig content, render-var/affinity branches, bindata object counts); go test ./pkg/... fully green. Validated end to end in the enhancement reference implementation across 14 dev-scripts baremetal installs — install over a BGP-advertised API VIP, health-gated ECMP for API+Ingress VIPs, CRD handover: https://github.com/mkowalski/bgp-vip-demo.

Related: #3046 (statusmanager fix this feature exposed), openshift/api#2923, openshift/baremetal-runtimecfg#395, openshift-metal3/dev-scripts#1929, kube-vip/kube-vip#1627.

CNO subtask: OPNET-783.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 10, 2026
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • ✅ Review completed - (🔄 Check again to review again)

Summary by CodeRabbit

  • New Features
    • Added BGP-based VIP management for supported BareMetal environments.
    • Generates FRR configuration to advertise IPv4 and IPv6 VIPs through configured BGP peers.
    • Added control-plane monitoring and Prometheus metrics collection for FRR.
    • Added required access controls and scheduling behavior for BGP VIP operation.
  • Documentation
    • Added documentation covering configuration, prerequisites, routing behavior, monitoring, and limitations.
  • Bug Fixes
    • Rendering now validates required FRR capabilities and reports configuration errors early.

Walkthrough

Adds feature-gated BGP VIP management for BareMetal clusters, rendering validated FRR configuration from a ConfigMap and conditionally changing FRR-K8s placement, monitoring, and static-pod RBAC.

Changes

BGP VIP management

Layer / File(s) Summary
BGP configuration and FRR generation
pkg/network/bgp_vip.go, pkg/network/bgp_vip_test.go
Validates VIP, peer, timing, and boolean settings, then generates single- or dual-stack FRRConfiguration resources with optional BFD, timing, password, and multihop fields.
Rendering integration
pkg/network/render.go, pkg/network/render_test.go
Determines BGP VIP mode from feature-gate, platform, and infrastructure state; passes it to routing-capability rendering and appends generated FRR resources.
FRR-K8s placement, monitoring, and RBAC
bindata/network/frr-k8s/frr-k8s.yaml, bindata/network/frr-k8s/master-monitor.yaml, bindata/network/frr-k8s/003-static-pod-rbac.yaml
Excludes master-labeled nodes from the FRR-K8s DaemonSet, adds a control-plane metrics exporter with HTTPS monitoring, and adds conditional static-pod permissions and bindings.
Feature documentation
docs/bgp_vip_management.md
Documents activation conditions, FRR rendering, VIP advertisement, placement, monitoring, and RBAC.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Render
  participant Infrastructure
  participant ConfigMap
  participant FRRK8sManifests
  participant FRRConfiguration
  Render->>Infrastructure: check BareMetal BGP VIP mode
  Render->>FRRK8sManifests: render enabled FRR-K8s resources
  Render->>ConfigMap: read bgp-vip-config
  ConfigMap-->>Render: return config.json
  Render->>FRRConfiguration: validate and generate bgp-vip
Loading

Suggested labels: jira/valid-bug, jira/valid-reference

Suggested reviewers: fedepaol, arkadeepsen, bpickard22


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (1 error, 4 warnings, 1 inconclusive)

Check name Status Explanation Resolution
E2e Tests For Feature Changes ❌ Error New user-facing Go behavior was added, but the PR has no test/e2e/ changes; the custom check requires both E2E coverage and testing context. Add/modify E2E tests under test/e2e/ or justify why they’re infeasible in the PR description, then reference the CI lanes/jobs and pass state.
Docstring Coverage ⚠️ Warning Docstring coverage is 64.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Go And Test Code Quality ⚠️ Warning render.go in this PR still uses log.Printf, and registerNetworkingConsolePlugin returns a bare err, violating the code-quality rules. Replace log.Printf with klog and add context or %w when returning the console update error.
Test Structure And Quality ⚠️ Warning The new tests rely on many bare Gomega assertions, and Test_renderAdditionalRoutingCapabilitiesBGPVIPManagement mixes active/inactive/error paths. Add descriptive messages to key expectations and split the BGPVIP management test into separate cases for active, inactive, and missing-FRR-provider paths.
Topology-Aware Scheduling Compatibility ⚠️ Warning frr-k8s now excludes master-labeled nodes via required affinity, with no ControlPlaneTopology check, so SNO/TNF baremetal clusters without workers won’t schedule it. Make the worker placement topology-aware: detect SingleReplica/DualReplica/TNA/External and avoid worker-only affinity there, or allow control-plane-labeled nodes when no dedicated workers exist.
Container-Privileges ❓ Inconclusive pending need evidence
✅ Passed checks (18 passed)
Check name Status Explanation
Title check ✅ Passed The title is imperative, under 72 characters, and scoped with the network component.
Description check ✅ Passed The description clearly matches the PR's BGP VIP management changes and related testing.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Pr Quality ✅ Passed Description has Why/What/Testing sections, cites CI presubmits and platforms, includes issue links, and the PR is small (~930 net lines).
Commit Message Quality ✅ Passed All 4 PR commits are linear, scoped as network:, have why-focused bodies, and no merge or vague/changelog-style messages.
Unit Tests For Go Changes ✅ Passed The bindata template change is accompanied by new render tests in pkg/network/render_test.go.
Rbac Least Privilege ✅ Passed Changed RBAC uses specific verbs/resources only; write verbs target FRRNodeState/BGPSessionState, and docs explain the need plus future admission scoping.
Docs For Feature And Behavior Changes ✅ Passed A new docs/bgp_vip_management.md file is present and documents the feature gate, behavior, placement, and RBAC for BGP VIP management.
Stale Project Docs And Config ✅ Passed Added docs/bgp_vip_management.md covers the new BGP VIP/static-pod behavior, and .coderabbit.yaml path instructions still match the repo; no stale refs found.
Ai-Generated Code Smell ✅ Passed Reviewed the new BGP VIP code, manifests, and tests; no AI/tool references, no obvious comment slop, and tests are focused on the feature.
Stable And Deterministic Test Names ✅ Passed Touched tests use static Go test function/table names; no Ginkgo titles or dynamic identifiers were found.
Microshift Test Compatibility ✅ Passed The PR adds only Go unit tests and manifests; no new Ginkgo e2e tests are introduced, so there’s nothing MicroShift-specific to flag.
Single Node Openshift (Sno) Test Compatibility ✅ Passed PASS: The PR adds only unit tests and manifests; no new Ginkgo e2e tests or SNO-sensitive multi-node assumptions were added.
Ote Binary Stdout Contract ✅ Passed No added stdout writes in main/init/TestMain/suite setup or top-level initializers; logging is only inside ordinary render helpers.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the touched tests are standard Go unit tests, so the IPv6/disconnected compatibility check is not applicable.
No-Weak-Crypto ✅ Passed No MD5/SHA1/DES/RC4/3DES/Blowfish/ECB, no crypto imports, and no secret/token comparisons were added in the changed files.
No-Sensitive-Data-In-Logs ✅ Passed New logs are generic; no added logging of passwords, tokens, PII, or host/customer data was found in the PR changes.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="Running error: context loading failed: failed to load packages: failed to load packages: failed to load with go/packages: err: exit status 1: stderr: go: inconsistent vendoring in :\n\tgithub.com/Masterminds/semver@v1.5.0: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\tgithub.com/Masterminds/sprig/v3@v3.2.3: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\tgithub.com/containernetworking/cni@v1.3.0: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\tgithub.com/ghodss/yaml@v1.0.1-0.20190212211648-25d852aebe32: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\tgithub.com/go-bindata/go-bindata@v3.1.2+incompatible: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\tgithub.com/onsi/gomega@v1.39.1: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\tgithub.com/ope

... [truncated 17377 characters] ...

red in go.mod, but not marked as explicit in vendor/modules.txt\n\tk8s.io/gengo/v2@v2.0.0-20251215205346-5ee0d033ba5b: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\tk8s.io/kms@v0.35.2: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\tk8s.io/kube-aggregator@v0.35.1: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\tsigs.k8s.io/randfill@v1.0.0: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\tsigs.k8s.io/structured-merge-diff/v6@v6.3.2: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\n\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo mod vendor\n"


Comment @coderabbitai help to get the list of available commands.

@openshift-ci
openshift-ci Bot requested review from arkadeepsen and bpickard22 July 10, 2026 09:27
@openshift-ci

openshift-ci Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: mkowalski
Once this PR has been reviewed and has the lgtm label, please assign abhat for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/network/render.go (1)

132-143: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Gate BGP VIP FRRConfiguration rendering in pkg/network/render.go:138-143.
renderBGPVIPFRRConfiguration still runs whenever BGP VIP management is active, even if RoutingCapabilitiesProviderFRR isn't enabled. That can emit FRRConfiguration objects before the frr-k8s CRD/manifests exist, so this should be gated on the FRR provider too.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/network/render.go` around lines 132 - 143, Gate the
renderBGPVIPFRRConfiguration call in the rendering flow so it executes only when
BGP VIP management is active and RoutingCapabilitiesProviderFRR is enabled.
Preserve the existing error handling and object appending within that
conditional block.
🧹 Nitpick comments (1)
pkg/network/render.go (1)

859-868: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Duplicate isBGPVIPManagement check causes a redundant Infrastructure CR fetch per render.

isBGPVIPManagement is called here and again inside renderBGPVIPFRRConfiguration (bgp_vip.go), each independently issuing a dynamic-client Get on the Infrastructure CR every Render() invocation. Compute it once in Render() and pass the boolean into both functions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/network/render.go` around lines 859 - 868, Compute the BGP VIP management
state once in Render() and pass the resulting boolean through the rendering call
chain, including renderAdditionalRoutingCapabilities and
renderBGPVIPFRRConfiguration. Remove the repeated isBGPVIPManagement call from
renderAdditionalRoutingCapabilities and renderBGPVIPFRRConfiguration, updating
their signatures and callers to use the shared value.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@bindata/network/frr-k8s/003-static-pod-rbac.yaml`:
- Around line 10-53: Restrict the FRR static-pod RBAC in the ClusterRole named
frr-k8s-static-pod: render this ClusterRole and its associated
ClusterRoleBinding only when BGP VIP management/bootstrap is active, not merely
when AdditionalRoutingCapabilities is enabled, and reduce node-state permissions
to the minimum required by the static pod, removing unnecessary destructive
verbs such as delete. Update render tests, including the bootstrapResult == nil
case, to verify the resources are omitted when BGP VIP management is inactive.

In `@pkg/network/bgp_vip.go`:
- Line 77: Replace context.TODO() in Render(), renderBGPVIPFRRConfiguration, and
the other affected client calls with a real bounded context.Context propagated
through the call chain; derive it from the reconcile/request context and apply
an appropriate timeout or cancellation before each Kubernetes API call.
- Around line 307-311: Handle the error returned by uns.NestedString in the
session status check within the BGP status function, rather than discarding it.
If extracting status or encountering a type mismatch fails, return the error to
the caller; otherwise continue checking whether status equals "Established".
- Around line 44-53: Update buildFRRConfigurationObjects and
buildBGPVIPRawConfig to propagate bgpVIPConfigData.Communities and HostOverrides
into the rendered FRRConfiguration, applying host-specific peers from
HostOverrides instead of only DefaultPeers and preserving configured route
communities. Ensure buildBGPVIPRawConfig includes both fields in its generated
raw configuration so installer and administrator settings are not discarded.

---

Outside diff comments:
In `@pkg/network/render.go`:
- Around line 132-143: Gate the renderBGPVIPFRRConfiguration call in the
rendering flow so it executes only when BGP VIP management is active and
RoutingCapabilitiesProviderFRR is enabled. Preserve the existing error handling
and object appending within that conditional block.

---

Nitpick comments:
In `@pkg/network/render.go`:
- Around line 859-868: Compute the BGP VIP management state once in Render() and
pass the resulting boolean through the rendering call chain, including
renderAdditionalRoutingCapabilities and renderBGPVIPFRRConfiguration. Remove the
repeated isBGPVIPManagement call from renderAdditionalRoutingCapabilities and
renderBGPVIPFRRConfiguration, updating their signatures and callers to use the
shared value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: af2a1a47-ab87-42a3-9874-a6d81393a5e8

📥 Commits

Reviewing files that changed from the base of the PR and between 0a9965a and f9ce13a.

📒 Files selected for processing (6)
  • bindata/network/frr-k8s/003-static-pod-rbac.yaml
  • bindata/network/frr-k8s/frr-k8s.yaml
  • pkg/network/bgp_vip.go
  • pkg/network/bgp_vip_test.go
  • pkg/network/render.go
  • pkg/network/render_test.go

Comment thread bindata/network/frr-k8s/003-static-pod-rbac.yaml
Comment thread pkg/network/bgp_vip.go Outdated
Comment thread pkg/network/bgp_vip.go Outdated
Comment thread pkg/network/bgp_vip.go Outdated
@mkowalski
mkowalski marked this pull request as draft July 10, 2026 10:10
@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 10, 2026
@mkowalski
mkowalski force-pushed the bgp-vip-management branch 2 times, most recently from 70cd187 to 445a366 Compare July 15, 2026 08:44
@mkowalski

Copy link
Copy Markdown
Contributor Author

@CodeRabbit help

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

CodeRabbit commands

These commands are invoked using PR/Issue comments.

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai rate limit to show your current review rate limit status.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai evaluate custom pre-merge check --instructions <custom-checks-instructions> --name <custom-checks-title> [--mode <error|warning>] to validate the custom pre-merge checks instructions. Defaults to error when --mode is omitted.
  • @coderabbitai ignore pre-merge checks to override pre-merge checks and get an approval on PR.
  • @coderabbitai run pre-merge checks to run pre-merge checks on the pull request.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai emit path instructions to emit generated path-specific review instructions for this repository.
  • @coderabbitai resolve merge conflict to automatically resolve merge conflicts.
  • @coderabbitai autofix to automatically fix issues identified in unresolved review comments.
  • @coderabbitai resolve to resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai generate configuration to create a PR that adds the current resolved configuration as .coderabbit.yaml (or show it if already present).
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, support, documentation and community

  • Visit our status page to check the current availability of CodeRabbit.
  • Create a ticket on our support page for assistance with any issues or questions.
  • Visit our documentation site for detailed information on how to use CodeRabbit.
  • Join our Discord community to connect with other users and get help from the community.
  • Follow us on X/Twitter for updates and announcements.

@mkowalski

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@mkowalski mkowalski changed the title OPNET-783: BGP-based VIP management: FRRConfiguration rendering, DaemonSet placement and static pod RBAC OPNET-783: network: Add BGP VIP management support Jul 15, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
bindata/network/frr-k8s/003-static-pod-rbac.yaml (1)

24-45: ⚠️ Potential issue | 🟠 Major

Keep node-bootstrapper from receiving cluster-wide state and Secret access.

This binding gives the shared MCO ServiceAccount cluster-wide mutation of all FRR/BGP node-state objects, including deletion and status writes. It also permits list/watch on every Secret in openshift-frr-k8s, although the stated need is only BGP session passwords. A compromised node bootstrap credential could modify other nodes’ state or read unrelated Secret data. Use node-scoped ownership or identities, narrow the verbs and Secret access to the static pod’s actual needs, and verify the renderer emits this RBAC only when BGP VIP bootstrap is active. This remains the previous review finding; the current manifest still contains it.

As per path instructions, RBAC must follow least privilege.

Also applies to: 55-66, 77-84, 94-106

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bindata/network/frr-k8s/003-static-pod-rbac.yaml` around lines 24 - 45,
Restrict the RBAC emitted by the static-pod renderer so node-bootstrapper cannot
access cluster-wide FRR/BGP state or broadly read Secrets. Update the bindings
covering the referenced FRR state and Secret rules to use node-scoped ownership
or identities, grant only the verbs and BGP session-password Secret access
required by the static pod, and ensure the renderer emits these rules only when
BGP VIP bootstrap is enabled.

Source: Path instructions

🧹 Nitpick comments (1)
pkg/network/render.go (1)

859-868: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

isBGPVIPManagement runs even when FRR isn't a configured provider.

The check (and its Infrastructure CR GET) executes unconditionally for any non-nil AdditionalRoutingCapabilities, but its result is only used inside the RoutingCapabilitiesProviderFRR case (Line 878). Move the call inside that case to avoid an unnecessary API call on every render pass when FRR isn't configured.

♻️ Proposed refactor
-	// Under BGP VIP management the static FRR pods own the control plane
-	// nodes, so the frr-k8s DaemonSet must avoid masters by role.
-	bgpVIP, err := isBGPVIPManagement(client, bootstrapResult, featureGates)
-	if err != nil {
-		return nil, fmt.Errorf("failed to check VIPManagement mode: %v", err)
-	}
 	var out []*uns.Unstructured
 	for _, provider := range conf.AdditionalRoutingCapabilities.Providers {
 		switch provider {
 		case operv1.RoutingCapabilitiesProviderFRR:
+			// Under BGP VIP management the static FRR pods own the control
+			// plane nodes, so the frr-k8s DaemonSet must avoid masters by role.
+			bgpVIP, err := isBGPVIPManagement(client, bootstrapResult, featureGates)
+			if err != nil {
+				return nil, fmt.Errorf("failed to check VIPManagement mode: %v", err)
+			}
 			data := render.MakeRenderData()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/network/render.go` around lines 859 - 868, Move the isBGPVIPManagement
call and its error handling from the start of
renderAdditionalRoutingCapabilities into the RoutingCapabilitiesProviderFRR
case, immediately before its result is needed. Keep the existing behavior and
error message for FRR, while avoiding the API call for other providers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@bindata/network/frr-k8s/frr-k8s.yaml`:
- Around line 297-305: Update the BGP VIP management scheduling logic around
isBGPVIPManagement and the shown frr-k8s affinity so single-node and compact
BareMetal topologies retain a schedulable node. If the feature is HA-only,
disable it through isBGPVIPManagement for those topologies; otherwise replace
the unconditional master-excluding affinity with topology-aware placement while
preserving the existing HA behavior.

In `@pkg/network/bgp_vip.go`:
- Around line 225-291: The buildBGPVIPRawConfig function must validate all
values before interpolating them into raw FRR configuration. Parse each VIP as a
valid IP or CIDR and each DefaultPeers PeerAddress as a valid IP, and ensure
LocalASN is validated as an acceptable ASN before rendering; reject or safely
handle invalid inputs rather than emitting configuration. Only splice the
validated canonical values into the generated config.
- Around line 34-42: Update the BGP VIP peer configuration flow centered on
bgpVIPPeer to accept the installer-provided kubernetes.io/basic-auth Secret and
reference it through FRRConfiguration neighbor.passwordSecret instead of reading
bgp-vip-config from a ConfigMap or populating neighbor.password. Remove
plaintext password propagation while preserving the existing peer authentication
behavior.

---

Duplicate comments:
In `@bindata/network/frr-k8s/003-static-pod-rbac.yaml`:
- Around line 24-45: Restrict the RBAC emitted by the static-pod renderer so
node-bootstrapper cannot access cluster-wide FRR/BGP state or broadly read
Secrets. Update the bindings covering the referenced FRR state and Secret rules
to use node-scoped ownership or identities, grant only the verbs and BGP
session-password Secret access required by the static pod, and ensure the
renderer emits these rules only when BGP VIP bootstrap is enabled.

---

Nitpick comments:
In `@pkg/network/render.go`:
- Around line 859-868: Move the isBGPVIPManagement call and its error handling
from the start of renderAdditionalRoutingCapabilities into the
RoutingCapabilitiesProviderFRR case, immediately before its result is needed.
Keep the existing behavior and error message for FRR, while avoiding the API
call for other providers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 257523d9-b259-40c4-b682-29a43a397d67

📥 Commits

Reviewing files that changed from the base of the PR and between 76e94f2 and 445a366.

📒 Files selected for processing (6)
  • bindata/network/frr-k8s/003-static-pod-rbac.yaml
  • bindata/network/frr-k8s/frr-k8s.yaml
  • pkg/network/bgp_vip.go
  • pkg/network/bgp_vip_test.go
  • pkg/network/render.go
  • pkg/network/render_test.go

Comment thread bindata/network/frr-k8s/frr-k8s.yaml
Comment thread pkg/network/bgp_vip.go
Comment thread pkg/network/bgp_vip.go
@mkowalski
mkowalski force-pushed the bgp-vip-management branch 2 times, most recently from 266cf7d to 37ff2cc Compare July 15, 2026 19:34
@mkowalski

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@mkowalski
mkowalski force-pushed the bgp-vip-management branch from 37ff2cc to 6917c46 Compare July 15, 2026 20:02

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/network/render.go (1)

138-142: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Gate BGP VIP FRRConfiguration on FRR enablement.
BGPBasedVIPManagement is independent of AdditionalRoutingCapabilities.Providers, but FRRConfiguration only exists in the frr-k8s bundle. This path can render a CR before its CRD is installed; guard it on the FRR provider or install the CRD unconditionally.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/network/render.go` around lines 138 - 142, Gate the
renderBGPVIPFRRConfiguration call on whether the FRR provider is enabled, using
the existing FRR enablement/provider configuration symbol. Keep
BGPBasedVIPManagement independent, and avoid appending or rendering the
FRRConfiguration unless its CRD is available; preserve the existing error
handling for enabled FRR rendering.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@bindata/network/frr-k8s/003-static-pod-rbac.yaml`:
- Around line 70-77: Restrict the Secret RBAC rule for node-bootstrapper to the
mounted frr-k8s-certs-secret by adding resourceNames, and reduce the verbs to
get only if the pod does not require collection operations. Preserve access to
that specific certificate Secret while removing namespace-wide Secret
permissions.

---

Outside diff comments:
In `@pkg/network/render.go`:
- Around line 138-142: Gate the renderBGPVIPFRRConfiguration call on whether the
FRR provider is enabled, using the existing FRR enablement/provider
configuration symbol. Keep BGPBasedVIPManagement independent, and avoid
appending or rendering the FRRConfiguration unless its CRD is available;
preserve the existing error handling for enabled FRR rendering.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 45e0fdea-5e7c-499e-89c5-0f1c9280a6e1

📥 Commits

Reviewing files that changed from the base of the PR and between 76e94f2 and 37ff2cc.

📒 Files selected for processing (6)
  • bindata/network/frr-k8s/003-static-pod-rbac.yaml
  • bindata/network/frr-k8s/frr-k8s.yaml
  • pkg/network/bgp_vip.go
  • pkg/network/bgp_vip_test.go
  • pkg/network/render.go
  • pkg/network/render_test.go

Comment thread bindata/network/frr-k8s/003-static-pod-rbac.yaml
@mkowalski
mkowalski force-pushed the bgp-vip-management branch 2 times, most recently from 2d3fd17 to f0979ba Compare July 16, 2026 08:57
@mkowalski

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (1)
bindata/network/frr-k8s/003-static-pod-rbac.yaml (1)

20-31: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Do not grant cluster-wide write access to the shared bootstrap identity.

This binding allows node-bootstrapper to create, update, and patch every FRRNodeState and BGPSessionState in the cluster. Any holder of that identity could alter another node’s BGP state. Use a per-node identity or another authorization mechanism that scopes writes to the local node, and verify this trust model before merging.

As per path instructions, RBAC must follow least privilege.

Also applies to: 50-61

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bindata/network/frr-k8s/003-static-pod-rbac.yaml` around lines 20 - 31,
Restrict the RBAC rule for node-bootstrapper in the ClusterRole to read-only
verbs, removing create, update, and patch access for frrnodestates and
bgpsessionstates. If writes are required, move them to a per-node identity or
authorization mechanism scoped to the local node rather than granting
cluster-wide write access.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/bgp_vip_management.md`:
- Around line 3-6: Update the prerequisites in the BGP VIP management
documentation to state that
Infrastructure.status.platformStatus.baremetal.additionalRoutingCapabilities.providers
must include the FRR provider. Clarify that renderBGPVIPFRRConfiguration
requires this capability in addition to the existing feature gate, BareMetal
platform, and BGP vipManagement conditions.

In `@pkg/network/bgp_vip.go`:
- Around line 101-104: Update the vipManagement lookup in the BGP mode logic to
handle the error from uns.NestedString separately: propagate or return the error
when it is non-nil, and only treat found == false as an absent field selecting
the existing non-BGP path. Do not discard malformed-value errors.
- Around line 162-204: Update buildFRRConfigurationObjects so each neighbor
includes the configured holdTime and keepaliveTime values from cfg.DefaultPeers,
preserving empty optional fields as omitted or explicitly rejecting unsupported
non-empty values. Extend the all-optional-fields test to verify these settings
are propagated.

In `@pkg/network/render.go`:
- Around line 132-138: In Render, evaluate the BGP VIP mode from the
Infrastructure CR once and store the result for the render operation. Pass this
shared value into both renderAdditionalRoutingCapabilities and
renderBGPVIPFRRConfiguration, updating their signatures and call sites so both
helpers use the same snapshot instead of independently reading the CR.

---

Duplicate comments:
In `@bindata/network/frr-k8s/003-static-pod-rbac.yaml`:
- Around line 20-31: Restrict the RBAC rule for node-bootstrapper in the
ClusterRole to read-only verbs, removing create, update, and patch access for
frrnodestates and bgpsessionstates. If writes are required, move them to a
per-node identity or authorization mechanism scoped to the local node rather
than granting cluster-wide write access.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 58526bcb-b4c8-41dd-8c10-d1aa6e838439

📥 Commits

Reviewing files that changed from the base of the PR and between 76e94f2 and f0979ba.

📒 Files selected for processing (7)
  • bindata/network/frr-k8s/003-static-pod-rbac.yaml
  • bindata/network/frr-k8s/frr-k8s.yaml
  • docs/bgp_vip_management.md
  • pkg/network/bgp_vip.go
  • pkg/network/bgp_vip_test.go
  • pkg/network/render.go
  • pkg/network/render_test.go

Comment thread docs/bgp_vip_management.md
Comment thread pkg/network/bgp_vip.go
Comment thread pkg/network/bgp_vip.go
Comment thread pkg/network/render.go Outdated
@mkowalski
mkowalski force-pushed the bgp-vip-management branch from f0979ba to 4c30cbe Compare July 16, 2026 09:49
@mkowalski

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/bgp_vip_management.md`:
- Around line 7-10: Update the documented Network operator resource path in the
BGP VIP management prerequisite from networks.operator/cluster to
network.operator.openshift.io/cluster, including the associated
additionalRoutingCapabilities.providers reference.

In `@pkg/network/bgp_vip.go`:
- Around line 70-81: The peer validation loop in the BGP configuration
validation function must allow-list the BFD and eBGP multihop fields to only "",
"true", or "false". Reject any other casing or malformed value before the
feature-handling logic that checks exact "true" values, using the existing peer
fields and returning a validation error that identifies the peer and invalid
value.
- Around line 311-324: Update the BGPSessionState list call in the surrounding
BGP VIP readiness check to restrict results to the openshift-frr-k8s namespace
and the selector identifying the bgp-vip FRRConfiguration or its owner labels.
Keep the existing status validation and empty-result behavior unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: a35c8e24-aa3c-4e94-ab2f-214afd65ddf1

📥 Commits

Reviewing files that changed from the base of the PR and between 76e94f2 and 4c30cbe.

📒 Files selected for processing (7)
  • bindata/network/frr-k8s/003-static-pod-rbac.yaml
  • bindata/network/frr-k8s/frr-k8s.yaml
  • docs/bgp_vip_management.md
  • pkg/network/bgp_vip.go
  • pkg/network/bgp_vip_test.go
  • pkg/network/render.go
  • pkg/network/render_test.go

Comment thread docs/bgp_vip_management.md Outdated
Comment thread pkg/network/bgp_vip.go
Comment thread pkg/network/bgp_vip.go Outdated
@mkowalski
mkowalski force-pushed the bgp-vip-management branch from 4c30cbe to e0b9f15 Compare July 16, 2026 10:10
@mkowalski

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@mkowalski
mkowalski force-pushed the bgp-vip-management branch from e0b9f15 to ef0900a Compare July 16, 2026 10:55
@mkowalski

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@mkowalski

Copy link
Copy Markdown
Contributor Author

@coderabbitai summary

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
✅ Action performed

Summary regeneration triggered.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
ℹ️ No Pre-Merge checks found.

No Per-Merge checks were run on this pull request. No override is required.

@mkowalski
mkowalski marked this pull request as ready for review July 16, 2026 11:20
@openshift-ci openshift-ci Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 16, 2026
@openshift-ci
openshift-ci Bot requested a review from fedepaol July 16, 2026 11:20
@mkowalski

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@bindata/network/frr-k8s/master-monitor.yaml`:
- Around line 34-68: Update the cp-metrics initContainer and frr-metrics
container resource definitions to include CPU and memory limits alongside their
existing requests. Add readiness and liveness probes to frr-metrics targeting
its HTTPS metrics endpoint on port 9141, so failed readiness removes it from
Service endpoints and failed liveness restarts it.
- Around line 26-68: Update the pod spec around the frr-metrics workload: remove
hostNetwork, disable automatic service-account token mounting, and add hardened
security contexts to both initContainer cp-metrics and container frr-metrics.
Configure each container to run as non-root with a read-only root filesystem,
disallow privilege escalation, and drop all Linux capabilities while preserving
the existing FRR volume mounts and commands.

In `@docs/bgp_vip_management.md`:
- Around line 40-45: Update the RBAC description near 003-static-pod-rbac.yaml
to state that it grants the static pod the read permissions required by the
frr-k8s controller informers, while preserving the surrounding write-access and
scoping statements.
- Around line 3-10: Clarify the activation prerequisites in the introductory
text: the feature gate, BareMetal platform, and Infrastructure CR status
activate BGP VIP management, while the FRR additional routing capability
provider is a separate hard prerequisite for successful rendering. Remove or
revise the “all three” inertness wording so it does not imply missing FRR leaves
the feature inert, and preserve the explicit rendering-failure behavior when the
provider is absent.

In `@pkg/network/bgp_vip.go`:
- Around line 58-89: Extend validateBGPVIPConfig to validate each peer’s
LocalASN and PeerASN before returning success. Reject missing or out-of-range
ASN values, including the zero LocalASN case, using the valid ASN bounds
expected by FRR; return descriptive validation errors so malformed values never
reach FRRConfiguration rendering.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 2694c27c-88dc-4879-9459-39c28ec80917

📥 Commits

Reviewing files that changed from the base of the PR and between 76e94f2 and 45184c0.

📒 Files selected for processing (8)
  • bindata/network/frr-k8s/003-static-pod-rbac.yaml
  • bindata/network/frr-k8s/frr-k8s.yaml
  • bindata/network/frr-k8s/master-monitor.yaml
  • docs/bgp_vip_management.md
  • pkg/network/bgp_vip.go
  • pkg/network/bgp_vip_test.go
  • pkg/network/render.go
  • pkg/network/render_test.go

Comment on lines +26 to +68
spec:
serviceAccountName: frr-k8s-daemon
hostNetwork: true
nodeSelector:
kubernetes.io/os: linux
node-role.kubernetes.io/master: ""
tolerations:
- operator: "Exists"
initContainers:
- name: cp-metrics
image: {{.FRRK8sImage}}
command: ["/bin/sh", "-c", "cp -f /frr-metrics /etc/frr_metrics/"]
terminationMessagePolicy: FallbackToLogsOnError
volumeMounts:
- name: metrics
mountPath: /etc/frr_metrics
containers:
- name: frr-metrics
image: {{.FRRK8sImage}}
command: ["/etc/frr_metrics/frr-metrics"]
args:
- --metrics-port=9141
- --metrics-bind-address=0.0.0.0
- --tls-cert-file=/etc/metrics/tls.crt
- --tls-private-key-file=/etc/metrics/tls.key
ports:
- containerPort: 9141
name: frrmetricshttps
resources:
requests:
cpu: 10m
memory: 20Mi
terminationMessagePolicy: FallbackToLogsOnError
volumeMounts:
- name: frr-sockets
mountPath: /var/run/frr
- name: frr-conf
mountPath: /etc/frr
- name: metrics
mountPath: /etc/frr_metrics
- name: metrics-certs
mountPath: /etc/metrics
readOnly: true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Remove avoidable host-level access and apply container hardening.

This exporter reaches FRR through mounted host paths; hostNetwork: true unnecessarily shares the control-plane node network namespace. The pod also lacks hardened security contexts and mounts its service-account token by default. Remove host networking unless required, disable token mounting if no API calls are made, and set non-root, read-only filesystem, no privilege escalation, and dropped capabilities on both containers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bindata/network/frr-k8s/master-monitor.yaml` around lines 26 - 68, Update the
pod spec around the frr-metrics workload: remove hostNetwork, disable automatic
service-account token mounting, and add hardened security contexts to both
initContainer cp-metrics and container frr-metrics. Configure each container to
run as non-root with a read-only root filesystem, disallow privilege escalation,
and drop all Linux capabilities while preserving the existing FRR volume mounts
and commands.

Sources: Coding guidelines, Path instructions

Comment on lines +34 to +68
initContainers:
- name: cp-metrics
image: {{.FRRK8sImage}}
command: ["/bin/sh", "-c", "cp -f /frr-metrics /etc/frr_metrics/"]
terminationMessagePolicy: FallbackToLogsOnError
volumeMounts:
- name: metrics
mountPath: /etc/frr_metrics
containers:
- name: frr-metrics
image: {{.FRRK8sImage}}
command: ["/etc/frr_metrics/frr-metrics"]
args:
- --metrics-port=9141
- --metrics-bind-address=0.0.0.0
- --tls-cert-file=/etc/metrics/tls.crt
- --tls-private-key-file=/etc/metrics/tls.key
ports:
- containerPort: 9141
name: frrmetricshttps
resources:
requests:
cpu: 10m
memory: 20Mi
terminationMessagePolicy: FallbackToLogsOnError
volumeMounts:
- name: frr-sockets
mountPath: /var/run/frr
- name: frr-conf
mountPath: /etc/frr
- name: metrics
mountPath: /etc/frr_metrics
- name: metrics-certs
mountPath: /etc/metrics
readOnly: true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Add limits and health probes for the control-plane exporter.

cp-metrics and frr-metrics have requests only, and frr-metrics has neither readiness nor liveness probes. Define CPU/memory limits for both containers and health checks for the serving container so an unresponsive exporter is removed from Service endpoints and restarted.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bindata/network/frr-k8s/master-monitor.yaml` around lines 34 - 68, Update the
cp-metrics initContainer and frr-metrics container resource definitions to
include CPU and memory limits alongside their existing requests. Add readiness
and liveness probes to frr-metrics targeting its HTTPS metrics endpoint on port
9141, so failed readiness removes it from Service endpoints and failed liveness
restarts it.

Source: Path instructions

Comment thread docs/bgp_vip_management.md Outdated
Comment on lines +40 to +45
The static pod authenticates with the node kubeconfig (the MCO
node-bootstrapper ServiceAccount). `003-static-pod-rbac.yaml` grants it the
reads the frr-k8s controller's informers need and write access to
`FRRNodeState`/`BGPSessionState`. Rendered only under BGP VIP management.
Per-node write scoping is not expressible in RBAC; a ValidatingAdmissionPolicy
is planned follow-up.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the RBAC sentence.

“Grants it the reads” is grammatically incorrect and obscures the permission being granted. Use “grants the static pod the read permissions required by the frr-k8s controller informers.”

Suggested wording
-`003-static-pod-rbac.yaml` grants it the
-reads the frr-k8s controller's informers need and write access to
+`003-static-pod-rbac.yaml` grants the static pod the read permissions
+required by the frr-k8s controller's informers and write access to
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
The static pod authenticates with the node kubeconfig (the MCO
node-bootstrapper ServiceAccount). `003-static-pod-rbac.yaml` grants it the
reads the frr-k8s controller's informers need and write access to
`FRRNodeState`/`BGPSessionState`. Rendered only under BGP VIP management.
Per-node write scoping is not expressible in RBAC; a ValidatingAdmissionPolicy
is planned follow-up.
The static pod authenticates with the node kubeconfig (the MCO
node-bootstrapper ServiceAccount). `003-static-pod-rbac.yaml` grants the static pod the read permissions
required by the frr-k8s controller's informers and write access to
`FRRNodeState`/`BGPSessionState`. Rendered only under BGP VIP management.
Per-node write scoping is not expressible in RBAC; a ValidatingAdmissionPolicy
is planned follow-up.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/bgp_vip_management.md` around lines 40 - 45, Update the RBAC description
near 003-static-pod-rbac.yaml to state that it grants the static pod the read
permissions required by the frr-k8s controller informers, while preserving the
surrounding write-access and scoping statements.

Comment thread pkg/network/bgp_vip.go
When the BGPBasedVIPManagement gate is enabled and the BareMetal
Infrastructure CR requests vipManagement "BGP", render a cluster-wide
sessions-only FRRConfiguration from the installer's bgp-vip-config
ConfigMap.

VIP advertisement lives in rawConfig as health-gated table-direct
redistribution of kernel table 198 (populated by kube-vip only while
the VIP's backend is healthy), filtered to exactly the VIP prefixes.
The CRD surface cannot express this: declared prefixes render as
unconditional network statements, defeating the health gating
(native support proposed in metallb/frr-k8s#469).
…anagement

Masters run the MCO-rendered frr-k8s static pod, so the DaemonSet must
not schedule there. Role-based required node-affinity avoids the
NodeRestriction and node bring-up races that label-based exclusion
hits. On compact/SNO the DaemonSet correctly matches zero nodes.
The static pod authenticates with the node kubeconfig, i.e. the MCO
node-bootstrapper ServiceAccount. Grant it the reads the stock frr-k8s
controller's informers require plus write access to the node state
CRs, only when BGP VIP management is active.

Per-node write scoping is not expressible in RBAC; admission-level
enforcement is planned before GA.
Static pods cannot mount Secrets, so the FRR metrics exporter cannot run
inside them. Run it in a masters-only companion DaemonSet instead: it
reads the static pod's FRR through the hostPath sockets MCO exposes
under /run/frr-k8s and serves TLS with a serving certificate, scraped
via its own Service and ServiceMonitor. Validated on a clean install:
metric coverage from every node, masters via the companion and workers
via the regular DaemonSet.
@mkowalski
mkowalski force-pushed the bgp-vip-management branch from 45184c0 to 07be631 Compare July 20, 2026 09:44
@mkowalski

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (2)
bindata/network/frr-k8s/master-monitor.yaml (1)

34-84: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Resource limits still missing on both containers.

Both cp-metrics and frr-metrics define CPU/memory requests but no limits. Path instructions require resource limits on every container. This was flagged in a prior review; probes were added but limits remain absent.

🛡️ Proposed fix
       resources:
         requests:
           cpu: 10m
           memory: 20Mi
+        limits:
+          cpu: 100m
+          memory: 50Mi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bindata/network/frr-k8s/master-monitor.yaml` around lines 34 - 84, Add CPU
and memory limits to both the cp-metrics and frr-metrics container resource
specifications, alongside their existing requests. Ensure every container in the
manifest, including the containers identified by those names, defines the
required limits while preserving the current request values and other settings.

Source: Path instructions

docs/bgp_vip_management.md (1)

42-44: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Grammar fix still needed in RBAC description.

"grants it the reads the frr-k8s controller's informers need" is grammatically incorrect. This was flagged in a prior review but not yet addressed.

📝 Proposed fix
-`003-static-pod-rbac.yaml` grants it the
-reads the frr-k8s controller's informers need and write access to
+`003-static-pod-rbac.yaml` grants the static pod the read permissions
+required by the frr-k8s controller's informers and write access to
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/bgp_vip_management.md` around lines 42 - 44, Correct the RBAC
description text around “003-static-pod-rbac.yaml” by rewriting the phrase about
informer permissions so it is grammatically complete, while preserving the
stated read access and write access to FRRNodeState/BGPSessionState.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@bindata/network/frr-k8s/master-monitor.yaml`:
- Around line 34-84: Add CPU and memory limits to both the cp-metrics and
frr-metrics container resource specifications, alongside their existing
requests. Ensure every container in the manifest, including the containers
identified by those names, defines the required limits while preserving the
current request values and other settings.

In `@docs/bgp_vip_management.md`:
- Around line 42-44: Correct the RBAC description text around
“003-static-pod-rbac.yaml” by rewriting the phrase about informer permissions so
it is grammatically complete, while preserving the stated read access and write
access to FRRNodeState/BGPSessionState.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: af1414d5-d25d-4a63-958b-49ec6d273f4c

📥 Commits

Reviewing files that changed from the base of the PR and between 76e94f2 and 07be631.

📒 Files selected for processing (8)
  • bindata/network/frr-k8s/003-static-pod-rbac.yaml
  • bindata/network/frr-k8s/frr-k8s.yaml
  • bindata/network/frr-k8s/master-monitor.yaml
  • docs/bgp_vip_management.md
  • pkg/network/bgp_vip.go
  • pkg/network/bgp_vip_test.go
  • pkg/network/render.go
  • pkg/network/render_test.go

@openshift-ci

openshift-ci Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

@mkowalski: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/5.0-upgrade-from-stable-4.22-e2e-gcp-ovn-upgrade 07be631 link false /test 5.0-upgrade-from-stable-4.22-e2e-gcp-ovn-upgrade
ci/prow/5.0-upgrade-from-stable-4.22-e2e-aws-ovn-upgrade 07be631 link false /test 5.0-upgrade-from-stable-4.22-e2e-aws-ovn-upgrade
ci/prow/5.0-upgrade-from-stable-4.22-e2e-azure-ovn-upgrade 07be631 link false /test 5.0-upgrade-from-stable-4.22-e2e-azure-ovn-upgrade

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants