Skip to content

Multi-VAN support - #2564

Open
fgiorgetti wants to merge 8 commits into
skupperproject:mainfrom
fgiorgetti:multi-van-slim
Open

Multi-VAN support#2564
fgiorgetti wants to merge 8 commits into
skupperproject:mainfrom
fgiorgetti:multi-van-slim

Conversation

@fgiorgetti

@fgiorgetti fgiorgetti commented Aug 28, 2026

Copy link
Copy Markdown
Member
  • No new CRDs needed
  • Network ID can be set through site.spec.networkId
  • Router Access and Link now accept inter-network role
  • Router Access and Link now accept spec.routingKeys (inter-network role)
  • Dynamic port allocation for Router Access (only supported with updated CRD)
  • CRDs have been updated, but all updates are optional if not using multi-van
  • New validation added to RouterAccess (prevent duplicated role names or ports)
  • Dynamic port allocation on RouterAccess shares the same pool used by Listeners (bindings)
  • Unit and integration tests added

Summary by CodeRabbit

  • New Features
    • Added multi-network connectivity using site network identifiers and inter-network links.
    • Added routing key configuration for links and router access resources.
    • Added router access status reporting for allocated roles and ports.
    • Improved router configuration synchronization and dynamic port allocation.
  • Bug Fixes
    • Limited generated links and access hosts to supported endpoint types.
    • Added detection for conflicting router access ports.
  • Tests
    • Expanded coverage for multi-network routing, port allocation, CRD detection, and router configuration reconciliation.

* No new CRDs needed
* Network ID can be set through site.spec.networkId
* Router Access and Link now accept inter-network role
* Router Access and Link now accept spec.routingKeys (inter-network role)
* Dynamic port allocation for Router Access (only supported with updated CRD)
* CRDs have been updated, but all updates are optional if not using multi-van
* Unit and integration tests added
@coderabbitai

coderabbitai Bot commented Aug 28, 2026

Copy link
Copy Markdown

Review Change Stack

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
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 3960f725-6748-4fed-880b-34b70ced5f67

📥 Commits

Reviewing files that changed from the base of the PR and between 21014ea and 5006483.

📒 Files selected for processing (3)
  • config/crd/bases/skupper_router_access_crd.yaml
  • internal/kube/site/site.go
  • pkg/apis/skupper/v2alpha1/types.go

Included review availability: Your plan provides up to 4 included reviews per hour; 3 remain after this review.


📝 Walkthrough

Walkthrough

The change adds multi-VAN fields to Skupper resources, synchronizes router networks and auto-links, supports inter-network roles and routing keys, shares router-access port allocation, and detects CRD capabilities for dynamic ports.

Changes

Multi-VAN routing and router access

Layer / File(s) Summary
Resource contracts and port allocation
config/crd/bases/*, pkg/apis/skupper/v2alpha1/*, internal/ports/*, internal/qdr/port_mapping.go
Schemas and API types add network IDs, routing keys, inter-network roles, allocated role status, validation, and shared port-management methods.
CRD capability detection and controller wiring
internal/kube/client/*, internal/kube/controller/controller.go, internal/kube/watchers/watchers.go, config/rbac/cluster/clusterrole.yaml
Kubernetes clients inspect CRD schemas. The controller detects status.roles support and passes the capability to site creation.
Router network and auto-link synchronization
internal/qdr/*, internal/kube/adaptor/config_sync.go
Router configuration models networks and auto-links. AMQP management queries and updates these records. Synchronization reconciles configuration differences.
Site, link, and router-access reconciliation
internal/kube/site/*, internal/site/*, internal/kube/grants/tokens.go, internal/cmd/skupper/link/kube/link_generate.go
Sites propagate network IDs. Links and router accesses create inter-network auto-links. Router accesses use shared ports and detect conflicts.
Integration flow validation
tests/integration/kube/controller/*, internal/site/*_test.go, internal/qdr/qdr_test.go, pkg/apis/skupper/v2alpha1/link_types_test.go, internal/fixtures/skupper_resources.go
Tests cover inter-network roles, routing-key auto-links, port conflicts, CRD path detection, endpoint filtering, and router configuration convergence.

Estimated code review effort: 5 (Critical) | ~120 minutes

Merge Risk: 🟠 High · up to 50064

The PR adds dynamic RouterAccess port allocation and multi-network synchronization, but failed updates can leave released ports recorded as active, causing duplicate assignments, while certain network-management entities can stop later router configuration synchronization and valid allocated ports can be rejected during cleanup. These correctness and availability risks should be fixed before merge.

Suggested reviewers: nluaces, pwright, aryanp123

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.85% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 73 functions across 31 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the primary change: adding Multi-VAN support. It is concise and related to the main changeset.
Full details: Docstring Coverage

Explanation

Docstring coverage is 6.85% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 73 functions across 31 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch

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

@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


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a5e06ede-299f-4f21-89a9-0b358c270f1f

📥 Commits

Reviewing files that changed from the base of the PR and between 06223ca and f287422.

📒 Files selected for processing (32)
  • config/crd/bases/skupper_link_crd.yaml
  • config/crd/bases/skupper_router_access_crd.yaml
  • config/crd/bases/skupper_site_crd.yaml
  • config/rbac/cluster/clusterrole.yaml
  • internal/cmd/skupper/debug/sweeper/ports_test.go
  • internal/cmd/skupper/link/kube/link_generate.go
  • internal/fixtures/skupper_resources.go
  • internal/kube/adaptor/config_sync.go
  • internal/kube/client/client.go
  • internal/kube/client/crds.go
  • internal/kube/client/crds_test.go
  • internal/kube/client/fake/fake_client.go
  • internal/kube/controller/controller.go
  • internal/kube/grants/tokens.go
  • internal/kube/site/site.go
  • internal/kube/site/site_test.go
  • internal/kube/watchers/watchers.go
  • internal/ports/ports.go
  • internal/ports/ports_test.go
  • internal/qdr/amqp_mgmt.go
  • internal/qdr/qdr.go
  • internal/qdr/qdr_test.go
  • internal/qdr/sync_router_ops.go
  • internal/site/link.go
  • internal/site/link_test.go
  • internal/site/routeraccess.go
  • internal/site/routeraccess_test.go
  • pkg/apis/skupper/v2alpha1/link_types_test.go
  • pkg/apis/skupper/v2alpha1/types.go
  • pkg/apis/skupper/v2alpha1/zz_generated.deepcopy.go
  • tests/integration/kube/controller/site_test.go
  • tests/integration/kube/controller/suite_test.go

Included review availability: Your plan provides up to 4 included reviews per hour; 3 remain after this review.

Comment thread config/crd/bases/skupper_router_access_crd.yaml
Comment thread internal/kube/adaptor/config_sync.go
Comment thread internal/ports/ports.go Outdated
Comment thread internal/site/link.go Outdated
Comment thread pkg/apis/skupper/v2alpha1/types.go

@c-kruse c-kruse left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Curious if you've got a plan for status for multi-van Links. IIUC these would stay Pending right now.

@fgiorgetti

Copy link
Copy Markdown
Member Author

Curious if you've got a plan for status for multi-van Links. IIUC these would stay Pending right now.

@c-kruse not yet. I believe it is better to handle it separately.
Do you remember we discussed about collecting network info from $management instead of deriving from flow events? I was thinking we could incorporate things like that as part of the new mechanism. WDYT?

* RouterAccess description improved
* Debug Sweeper now uses its own constant
* Validate port collisions during RouterAccess reconciliation

@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


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 82420edb-7eef-457a-a19b-a9cdbbafdb62

📥 Commits

Reviewing files that changed from the base of the PR and between f287422 and 76cde3a.

📒 Files selected for processing (7)
  • config/crd/bases/skupper_router_access_crd.yaml
  • internal/cmd/skupper/debug/sweeper/ports.go
  • internal/kube/site/site.go
  • internal/site/link.go
  • internal/site/routeraccess.go
  • internal/site/routeraccess_test.go
  • pkg/apis/skupper/v2alpha1/types.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • internal/site/link.go
  • config/crd/bases/skupper_router_access_crd.yaml

Included review availability: Your plan provides up to 4 included reviews per hour; 3 remain after this review.

Comment thread internal/kube/site/site.go

@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: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 6d96efc0-5cbe-41f9-bc1b-7fb150389ac2

📥 Commits

Reviewing files that changed from the base of the PR and between 76cde3a and 168015e.

📒 Files selected for processing (5)
  • internal/kube/site/extended_bindings.go
  • internal/kube/site/site.go
  • internal/ports/ports.go
  • internal/ports/ports_test.go
  • internal/qdr/port_mapping.go

Included review availability: Your plan provides up to 4 included reviews per hour; 2 remain after this review.

Comment thread internal/kube/site/site.go
Comment on lines +1824 to +1826
port, err = s.getPool().NextFreePort()
if err != nil {
return err

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

Roll back partial allocations when a later role fails.

If a RouterAccess has multiple dynamic roles, NextFreePort() can allocate an earlier role and fail on a later role. The return at Line 1826 exits without releasing allocatedPorts or undoing the matching la.AllocatePort mutation. Each retry can leak another port from the shared pool and eventually block allocations for other RouterAccesses and listeners.

Release the partial allocations before returning from this loop.

Proposed fix
 				port, err = s.getPool().NextFreePort()
 				if err != nil {
+					la.ReleaseUnusedPorts(allocatedPorts...)
+					s.getPool().ReleaseAll(allocatedPorts...)
 					return err
 				}
📝 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
port, err = s.getPool().NextFreePort()
if err != nil {
return err
port, err = s.getPool().NextFreePort()
if err != nil {
la.ReleaseUnusedPorts(allocatedPorts...)
s.getPool().ReleaseAll(allocatedPorts...)
return err

@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: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: bc711717-56aa-494a-a20c-064a8121a915

📥 Commits

Reviewing files that changed from the base of the PR and between 168015e and 21014ea.

📒 Files selected for processing (5)
  • internal/kube/site/extended_bindings.go
  • internal/kube/site/site.go
  • internal/qdr/port_mapping.go
  • internal/site/routeraccess.go
  • internal/site/routeraccess_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/kube/site/site.go

Included review availability: Your plan provides up to 4 included reviews per hour; 2 remain after this review.

continue
}
if name, ok := usedPorts[int32(role.Port)]; ok && name != ra.Name {
return true, fmt.Sprintf("router access: %s", name), role.Port

@coderabbitai coderabbitai Bot Aug 31, 2026

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 | 🟡 Minor | ⚡ Quick win

Release allocated ports on the conflict path.

When this check reports a conflict, internal/kube/site/site.go at Lines [1714-1740] removes the existing entry but does not release its GetAllocatedPorts() from the shared pool. A dynamic port then remains unavailable after the RouterAccess is removed. Repeated conflicts can exhaust the pool and make later allocation return No available ports. Release the previous entry’s allocated ports before deleting it. Apply the same cleanup to the mixed static/dynamic rejection path. (raw.githubusercontent.com)

Source: MCP tools


🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- applicable repository conventions ---'
find /tmp/coderabbit-repo-knowledge/skupperproject-skupper-1bf01da4 -maxdepth 2 -type f -name '*.md' -print \
  | sort \
  | while read -r f; do
      case "$f" in
        */learnings/*|*/architecture/*) ;;
        *) printf '\n### %s\n' "$f"; sed -n '1,220p' "$f" ;;
      esac
    done

printf '%s\n' '--- target file outline ---'
ast-grep outline internal/site/routeraccess.go

printf '%s\n' '--- target implementation and nearby definitions ---'
sed -n '1,230p' internal/site/routeraccess.go

printf '%s\n' '--- direct callers and conflict handling ---'
rg -n -C 8 'HasPortConflict|GetPortForRole|desiredListeners|RouterAccessConfig\.Apply|Apply\(.*RouterAccess' internal internal 2>/dev/null

Repository: skupperproject/skupper

Length of output: 30926


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- RouterAccess port semantics ---'
rg -n -C 12 'func \(.*RouterAccess.*GetPortForRole|type RouterAccessRole|type RouterAccess struct|func \(.*RouterAccess.*FindRole' pkg internal

printf '%s\n' '--- conflict caller and update path ---'
sed -n '1746,1865p' internal/kube/site/site.go

printf '%s\n' '--- listener contract and endpoint handling ---'
rg -n -C 12 'func .*AddListener|type Listener|ListenersDifference|GetMatchingListeners|RemoveListener' internal/qdr

Repository: skupperproject/skupper

Length of output: 28230


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- allocated-port and role definitions ---'
sed -n '977,1025p' pkg/apis/skupper/v2alpha1/types.go
rg -n -C 8 'MixesDynamicAndStaticPorts|RouterAccess.*(Validate|validate)|roles:|port:' pkg internal | head -240

printf '%s\n' '--- HasPortConflict test cases ---'
sed -n '586,915p' internal/site/routeraccess_test.go

printf '%s\n' '--- RouterAccess map population ---'
rg -n -C 10 'linkAccess\s*=|linkAccess\[|CheckRouterAccess\(' internal/kube/site/site.go

Repository: skupperproject/skupper

Length of output: 36169


Reject duplicate ports within one RouterAccess.

HasPortConflict does not compare ports between candidate roles. Two roles on port 55671 can pass the check, while desiredListeners creates two listeners on the same bind endpoint. Add an intra-resource duplicate-port check and a table case.

Source: MCP tools

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I am going to write a CEL expression to handle it. Since RouterAccess CRD is changing anyway.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@fgiorgetti, that is appropriate for duplicate ports within one RouterAccess. A CEL expression can reject the invalid resource before reconciliation.

The allocated-port release path is separate from this validation. It still needs cleanup when reconciliation rejects or removes an existing RouterAccess.


🧠 Learnings used
Learnt from: fgiorgetti
Repo: skupperproject/skupper PR: 2564
File: pkg/apis/skupper/v2alpha1/types.go:982-991
Timestamp: 2026-08-31T15:10:14.858Z
Learning: In `pkg/apis/skupper/v2alpha1/types.go`, RouterAccess did not previously prevent conflicts between manually assigned role ports. Manual port-conflict validation is required when allocating dynamic router-access ports.

You are interacting with an AI system.

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.

2 participants