Skip to content

fix: Stop the gateway rewriting unchanged rules on every pod attach - #786

Merged
privateip merged 1 commit into
mainfrom
fix/issue-719
Oct 7, 2026
Merged

privateip merged 1 commit into
mainfrom
fix/issue-719

Conversation

@privateip

Copy link
Copy Markdown
Collaborator

Summary

Each gateway node rewrote every VIP's load-balancing entries whenever any route object in its namespace changed, so every pod start or stop anywhere in the cluster triggered a full rewrite on every gateway node.

The gateway now rewrites a rule only when its inputs change, and it ignores route events that cannot affect a backend.

A rule whose last update or removal failed is still retried on the next pass. The gateway still restores its own VIP advertisements if someone deletes or edits them.

Test plan

  • Reconciling an unchanged rule three times writes to the datapath once
  • Moving one backend to a new node rewrites only that rule
  • A rule reverted after a failed update is reapplied
  • Unit tests and lint pass

Fixes #719

🤖 Generated with Claude Code

Every gateway node reconciled on any BGPAdvertisement, BGPVRFInstance or BGPRouter event in its namespace, status writes and its own VIP advertisements included. Each pass re-applied every rule: a fresh quota reservation, a rebuilt Maglev table, and a Put of every vip_table and vip_addr_table entry. Pod churn anywhere in the cluster therefore rewrote every VIP on every gateway node.

The engine now applies a rule only when it is new or differs from the active one, compared field by field including each backend's uSID. An unchanged rule still reports an applied status, so its advertisement and Programmed condition are untouched.

Skipping unchanged rules removes the every-pass rewrite that used to repair a failed update or removal, so the engine now tracks those itself. A failed apply releases the key's quota and can leave its datapath entries half-written, and a failed removal leaves the rule active with its quota already released. Either marks the key dirty, and a dirty key is applied on the next pass even when its desired rule equals the active one. A new rule that fails to apply never becomes active, so it is retried as before.

The NetworkGateway controller's watches now drop events that cannot change what a pass does:

- BGPAdvertisements without both a VRFID and a Function, which the backend resolver ignores, except a delete or spec edit of the gateway's own VIP advertisements, so a removed one is still restored.
- Status-only updates to all three kinds. Every field the resolver reads is in spec.

Unchanged rules are no longer rewritten after an external wipe of the pinned maps. A process restart, which empties the engine's active set, still rebuilds them.

Fixes #719

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@privateip privateip self-assigned this Oct 7, 2026
@privateip
privateip marked this pull request as ready for review October 7, 2026 19:22
@privateip
privateip requested a review from a team as a code owner October 7, 2026 19:22
@privateip
privateip enabled auto-merge October 7, 2026 19:22
@privateip

Copy link
Copy Markdown
Collaborator Author

pr-conventions-reviewer: VERDICT: merge. No reach, collision, ownership or convention findings. The change is Go-only under internal/gateway and internal/controller and touches no manifest, so it ships only with a release. It rolls out through the normal merge-to-staging, release-to-prod path, and no open PR owns the same files. PR #738 touches only the gateway architecture doc and the webhook, so the two can both land.

pr-adversary: VERDICT: merge. No correctness defect. rulesEqual covers every DesiredRule field including Backends[].USID, so a backend that moves nodes still triggers a rewrite. ReconcileOrphans spares any key in the live set, so skipped rules with older generations are not swept. The resolver reads only spec fields, so filtering status-only updates on BGPRouter, BGPVRFInstance and BGPAdvertisement is safe; deletes and spec edits of the gateway's own VIP advertisements still pass. A failed apply of an active rule, or a failed removal, is marked dirty and retried next pass.

pr-conventions-reviewer ran: gh pr view 786; git diff --stat base...head; gh pr list --state open (files); grep of docs/agents/CONVENTIONS.md for commit rules; git diff of the controller and gateway files filtered for added comment lines.

pr-adversary ran: gh pr view 786; gh issue view 719 --comments; gh pr checks 786; git diff --stat and full diff of the controller and gateway files; reads of types.go, kerneldatapath.go, usidresolver.go, edgemap/viptable.go and greps of ReconcileOrphans/Generation/ApplyRule call sites; go test ./internal/gateway/... ./internal/controller/... (both pass).

No findings to apply.

CI: All checks passed (Build, Lint, Unit Tests, Unit Tests (root), E2E Tests, all image publish jobs, kustomize bundle publish, CLA).

Auto-merge enabled with --merge. The base branch ruleset requires code owner review and approval of the last push. Auto-merge will complete once the required approvals are in place.

Generated with Claude Code

@privateip
privateip merged commit 6a04aed into main Oct 7, 2026
14 checks passed
@privateip
privateip deleted the fix/issue-719 branch October 7, 2026 19:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gateway rebuilds every rule on any route change

2 participants