Skip to content

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

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

OPNET-783: network: Add BGP VIP management support#3047
mkowalski wants to merge 3 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). Three 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).

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 20 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: 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)
ℹ️ Recent review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: 30fc485e-e474-4c7d-be79-c1dcb9791606

📥 Commits

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

📒 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

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting


Summary by CodeRabbit

  • New Features
    • Added preview support for BGP-based virtual IP management on Bare Metal, gated by the BGP VIP management platform setting and feature gate.
    • Generates an bgp-vip FRRConfiguration from the installer bgp-vip-config, including IPv4/IPv6 VIPs, peer options, BFD, and health-gated route advertisement.
    • Adds bootstrap-time FRRConfiguration placement and required RBAC.
  • Bug Fixes
    • When enabled, prevents FRR DaemonSet scheduling on control-plane nodes via master-avoiding node affinity.
    • Validates VIP, peer, duration, and boolean-like configuration values.
  • Documentation
    • Documented how to enable and operate BGP-based VIP management and its requirements.

Walkthrough

Adds feature-gated BGP VIP management for BareMetal clusters, rendering validated FRR configuration from a ConfigMap and conditionally changing FRR-K8s placement 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 and peer settings and 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
Computes BGP VIP state, passes it to routing-capability rendering, appends generated FRR resources, and tests enabled and inactive paths.
Conditional FRR-K8s placement and RBAC
bindata/network/frr-k8s/frr-k8s.yaml, bindata/network/frr-k8s/003-static-pod-rbac.yaml
Excludes master-labeled nodes from scheduling when enabled and adds conditional static-pod permissions and bindings.
Feature documentation
docs/bgp_vip_management.md
Documents activation conditions, FRR rendering, VIP advertisement, placement, and RBAC.

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

Sequence Diagram(s)

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

Suggested reviewers: arkadeepsen, bpickard22


Caution

Pre-merge checks failed

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

  • Ignore

❌ Failed checks (1 error, 2 warnings)

Check name Status Explanation Resolution
E2e Tests For Feature Changes ❌ Error User-facing BGP VIP behavior changed in pkg/network, but no test/e2e/ files were added or modified. Add or update e2e coverage under test/e2e/ for the new behavior, or document why it’s infeasible in How to verify it and use @coderabbitai ignore pre-merge checks.
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Topology-Aware Scheduling Compatibility ⚠️ Warning The new frr-k8s DaemonSet affinity excludes only master nodes and the pod tolerates all NoSchedule taints, so on Two-Node+Arbiter it can land on the arbiter; no topology check exists. Gate BGPVIPManagement on ControlPlaneTopology or add an explicit arbiter exclusion (and avoid wildcard tolerations) so the DaemonSet only runs on supported nodes.
✅ Passed checks (21 passed)
Check name Status Explanation
Title check ✅ Passed The title is specific, imperative, under 72 characters, and clearly describes the BGP VIP management changes.
Description check ✅ Passed The description directly explains the BGP VIP management feature, implementation details, and testing for this changeset.
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 and upgrade-safety notes; diff is 757 lines across 7 feature-focused files, well under the 7000-line cap.
Commit Message Quality ✅ Passed Three PR commits are logical network-scoped units, each has a descriptive subject and intent-focused body, and no merge commits appear in the PR range.
Unit Tests For Go Changes ✅ Passed PR changes production Go and bindata YAMLs, and includes matching test updates in pkg/network/bgp_vip_test.go and pkg/network/render_test.go.
Rbac Least Privilege ✅ Passed No wildcards; mutation verbs are limited to named FRRNodeState/BGPSessionState resources and are documented as required controller writes.
Docs For Feature And Behavior Changes ✅ Passed A new docs file, docs/bgp_vip_management.md, is added in the PR diff and documents the feature, placement, RBAC, and behavior.
Stale Project Docs And Config ✅ Passed PASS: The PR adds docs/bgp_vip_management.md for the new BGP VIP feature, and no existing docs/config reference renamed or removed paths/behaviors.
Go And Test Code Quality ✅ Passed The only modified Go file is render_test.go, and its new assertions use contextual errors; no banned logging, bare returns, Sleep, or env misuse appear.
Ai-Generated Code Smell ✅ Passed No AI/tool markers or unrelated test bloat; the new comments explain non-obvious BGP/VIP behavior and the tests target the added logic.
Stable And Deterministic Test Names ✅ Passed All added/changed test titles are static strings; no Ginkgo titles or subtest names embed dynamic data like IPs, nodes, timestamps, or suffixes.
Test Structure And Quality ✅ Passed Not applicable: the added tests are plain unit tests, not Ginkgo/cluster tests, so there are no BeforeEach/Eventually/cleanup concerns; they follow existing repo style.
Microshift Test Compatibility ✅ Passed Only unit tests using testing.T were added; no new Ginkgo e2e tests or MicroShift-unsupported APIs/features are present.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the new tests are plain Go unit tests (testing.T/Gomega) and do not assume multi-node scheduling or HA.
Ote Binary Stdout Contract ✅ Passed No main/init/TestMain/suite-level stdout writes were added; touched code only logs inside helper functions/tests, with no stdout redirection.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the only new test is a unit test in pkg/network/render_test.go with no external connectivity or IPv4-only assumptions.
No-Weak-Crypto ✅ Passed No MD5/SHA1/DES/RC4/3DES/Blowfish/ECB, custom crypto, or secret comparisons appear in the PR files; changes are RBAC/rendering only.
Container-Privileges ✅ Passed The only changed manifest is RBAC; no new privileged/hostNetwork/SYS_ADMIN/allowPrivilegeEscalation settings were added in the PR.
No-Sensitive-Data-In-Logs ✅ Passed New logs are generic only; no code paths log passwords, tokens, PII, hostnames, or customer data.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
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.

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.
@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
@openshift-ci

openshift-ci Bot commented Jul 16, 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-azure-ovn-upgrade ef0900a link false /test 5.0-upgrade-from-stable-4.22-e2e-azure-ovn-upgrade
ci/prow/5.0-upgrade-from-stable-4.22-e2e-gcp-ovn-upgrade ef0900a 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 ef0900a link false /test 5.0-upgrade-from-stable-4.22-e2e-aws-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