smartcontract,client: add topology CLI commands#3512
Merged
ben-malbeclabs merged 3 commits intomainfrom Apr 21, 2026
Merged
Conversation
This was referenced Apr 10, 2026
Merged
a1a2260 to
b710d74
Compare
834ffe0 to
ed49424
Compare
95364cc to
211dd11
Compare
ed49424 to
93ecaeb
Compare
ea17f91 to
5f08e8b
Compare
elitegreg
added a commit
that referenced
this pull request
Apr 18, 2026
…y processors (#3497) RFC-18 flex-algo · PR 1 of 5 · see `rfcs/rfc-0018-flex-algo.md` Series: #3497 · #3512 · #3513 · #3514 · #3515 ## Summary of Changes - Adds `TopologyInfo` onchain account (RFC-18 flex-algo) with `admin_group_bit`, `flex_algo_number`, and `TopologyConstraint`; creates `AdminGroupBits` resource extension singleton for bit allocation - Adds four new foundation-only instructions (107–110): `CreateTopology`, `DeleteTopology`, `ClearTopology`, `BackfillTopology` - Extends `Link` with `link_topologies` (Vec<Pubkey>) and `link_flags` (LINK_FLAG_UNICAST_DRAINED); extends `Tenant` with `include_topologies`; adds `flex_algo_node_segments` to Interface V2 - `CreateLink` now requires the unicast-default topology account and auto-tags the link into it - `UpdateLink` gains foundation-gated `link_topologies` update and contributor-gated `unicast_drained` flag ## Diff Breakdown | Category | Files | Lines (+/-) | Net | |-------------|-------|---------------|-------| | Core logic | 22 | +1,306 / -38 | +1,268| | Scaffolding | 49 | +133 / -3 | +130 | | Tests | 27 | +4,592 / -74 | +4,518| The scaffolding is mechanical struct field additions (`link_topologies: vec![]`, `include_topologies: vec![]`, `flex_algo_node_segments: vec![]`) across CLI, SDK, activator, and client to keep the workspace compiling. Core logic is concentrated in the new topology processors, state types, and link/activate updates. <details> <summary>Key files (click to expand)</summary> - `smartcontract/programs/doublezero-serviceability/src/state/interface.rs` — updates Interface V2 (discriminant 1) to include `flex_algo_node_segments: Vec<FlexAlgoNodeSegment>`; V1 accounts (pre-CYOA format) are left as-is; pre-RFC-18 V2 accounts on mainnet are upgraded in-place by `MigrateDeviceInterfaces` before this deserialization path is used - `smartcontract/programs/doublezero-serviceability/src/state/topology.rs` — new `TopologyInfo` account: `admin_group_bit` (u8), `flex_algo_number` (128+bit), `TopologyConstraint` (IncludeAny/Exclude) - `smartcontract/programs/doublezero-serviceability/src/processors/topology/` — five new processors: create (allocates AdminGroupBit, validates IdRange 1–127), delete, clear (removes topology from all links), backfill (allocates FlexAlgoNodeSegment on all device interfaces) - `smartcontract/programs/doublezero-serviceability/src/processors/link/update.rs` — adds foundation-gated `link_topologies` update (validates each topology account onchain) and contributor-gated `unicast_drained` flag (LINK_FLAG_UNICAST_DRAINED bit 0) - `smartcontract/programs/doublezero-serviceability/src/processors/link/activate.rs` — requires `unicast_default_topology_account` as a mandatory account; auto-tags new link into the unicast-default topology on activation - `smartcontract/programs/doublezero-serviceability/src/processors/globalconfig/set.rs` — creates `AdminGroupBits` ResourceExtension PDA on global config initialization - `smartcontract/programs/doublezero-serviceability/src/state/link.rs` — adds `link_topologies: Vec<Pubkey>`, `link_flags: u64`, and `LINK_FLAG_UNICAST_DRAINED = 0x01` - `smartcontract/programs/doublezero-serviceability/src/instructions.rs` — registers four new instruction variants (CreateTopology=107, DeleteTopology=108, ClearTopology=109, BackfillTopology=110) </details> ## Testing Verification - `make rust-lint` and `make rust-test` pass clean on this branch - `topology_test.rs` (~2,400 lines) covers all four topology processors: create/delete/clear/backfill, including error paths (duplicate names, out-of-range bits, unauthorized signers, invalid topology accounts), segment allocation, and multi-topology backfill - Existing `link_wan_test.rs`, `tenant_test.rs`, and telemetry tests updated to account for the new mandatory `unicast_default_topology_account` in `ActivateLink` --------- Co-authored-by: Greg Mitchell <greg@malbeclabs.com>
Adds `doublezero link topology {create,delete,clear,backfill,list}` subcommands.
- sdk/rs: topology command structs (create, delete, clear, backfill, list)
- cli: topology CLI wrappers with clap arg parsing and unit tests
- client/doublezero: wire topology subcommands into link command dispatch
- clear: auto-discovers tagged links when --links omitted; batches 29/tx
elitegreg
approved these changes
Apr 21, 2026
elitegreg
added a commit
that referenced
this pull request
Apr 22, 2026
migrate command (#3513) RFC-18 flex-algo · PR 3 of 5 · see `rfcs/rfc-0018-flex-algo.md` Depends on: #3512 (PR 2) Series: #3497 · #3512 · #3513 · #3514 · #3515 ## Summary of Changes - Extends `doublezero link get/list/update` to display topology assignments (`link_topologies`) and drain status; adds `--link-topology` (comma-separated topology names, `default` to clear all) and `--unicast-drained` flags to `link update`; adds `--topology` filter to `link list` - Extends `doublezero tenant get/list/update` to display included topologies (`include_topologies`) and adds `--include-topologies` (comma-separated topology names, `default` to clear) to `tenant update` - Adds `doublezero-admin migrate flex-algo [--dry-run]` command that backfills link topology assignments and VPNv4 loopback flex-algo node segments across all existing devices and links ## Diff Breakdown | Category | Files | Lines (+/-) | Net | |-------------|-------|-------------|------| | Core logic | 11 | +471 / -57 | +414 | | Scaffolding | 7 | +16 / -5 | +11 | Mostly core logic — the migrate command alone is 180 lines of backfill and dry-run orchestration. <details> <summary>Key files (click to expand)</summary> - `controlplane/doublezero-admin/src/cli/migrate.rs` — new: `migrate flex-algo` command; validates UNICAST-DEFAULT PDA exists, backfills link topologies for all links, backfills flex-algo node segments for all VPNv4 loopback interfaces on all devices; supports `--dry-run` - `smartcontract/cli/src/link/list.rs` — adds `--topology <name>` filter and displays `link_topologies`/`unicast_drained` columns, resolving topology pubkeys to human-readable names - `smartcontract/cli/src/link/get.rs` — displays topology assignments and drain status; fetches topology map to resolve pubkeys to names - `smartcontract/cli/src/link/update.rs` — adds `--link-topology` (accepts comma-separated list of topology names; use `default` to clear) and `--unicast-drained` flags - `smartcontract/cli/src/tenant/list.rs` — displays `include_topologies` column - `smartcontract/cli/src/tenant/get.rs` — displays included topology names - `smartcontract/cli/src/tenant/update.rs` — adds `--include-topologies` (accepts comma-separated list; use `default` to clear) </details> ## Testing Verification - `cargo test -p doublezero_sdk -p doublezero_cli -p doublezero-admin` passes - `cargo clippy -- -D warnings` clean - `make rust-fmt` applied before commit --------- Co-authored-by: Greg Mitchell <greg@malbeclabs.com>
elitegreg
pushed a commit
that referenced
this pull request
Apr 23, 2026
RFC-18 flex-algo · PR 4 of 5 · see [`rfcs/rfc-0018-flex-algo.md`](../tree/main/rfcs/rfc-0018-flex-algo.md) Depends on: #3512 (PR 2), #3513 (PR 3) Series: #3497 · #3512 · #3513 · #3514 · #3515 ## Summary of Changes - Python SDK: deserialize `TopologyConstraint`, `TopologyInfo`, and `FlexAlgoNodeSegment`; read `flex_algo_node_segments` from the RFC-18 `InterfaceV3` account format - TypeScript SDK: deserialize `FlexAlgoNodeSegment` from `InterfaceV3` account format; guard the segments loop against pre-RFC-18 mainnet accounts where the segment count reads garbage bytes - SDK fixtures: regenerate device, link, tenant, and user fixtures to include the new `InterfaceV3` fields - TypeScript RPC client: remove the `AbortController` timeout wrapper around `fetch` (was surfacing as spurious `TimeoutError` on slow `getProgramData` responses); bump the compat test's request timeout to 120s - `tryReadString` in `borsh-incremental`: check remaining buffer length before reading to avoid out-of-bounds reads - CHANGELOG / e2e compatibility test: document the mandatory CLI upgrade boundary for RFC-18 `InterfaceV3` (devices written by the new program cannot be deserialized by pre-RFC-18 CLI versions) Note: activator changes that were originally planned for this PR have been dropped — the doublezero activator is deprecated. ## Diff Breakdown | Category | Files | Lines (+/-) | |------------|-------|-------------| | Python SDK | 1 | +61 / -1 | | TS SDK | 3 | +27 / -3 | | Fixtures | 5 | +4 / -1 + bin | | Docs/e2e | 2 | +2 / -2 | ## Testing Verification - Python SDK: `uv run pytest` passes under `sdk/serviceability/python/`, including fixture deserialization - TypeScript SDK: `bun test` passes under `sdk/serviceability/typescript/`, including compat fixture deserialization with the new `InterfaceV3` fields - `cargo check --workspace` clean
ben-malbeclabs
added a commit
that referenced
this pull request
Apr 29, 2026
…troller support RFC-18 flex-algo · PR 5 of 5 · see `rfcs/rfc-0018-flex-algo.md` Depends on: #3497 (PR 1) — does not require PRs 2–4; can merge after PR 1 Series: #3497 · #3512 · #3513 · #3514 · #3515 ## Summary of Changes - Adds `TopologyInfo` account type to the Go SDK (`state.go`, `deserialize.go`, `client.go`), including `TopologyType`, `TopologyConstraint`, `LinkFlagUnicastDrained`, `LinkTopologies`/`LinkFlags` on `Link`, and `IncludeTopologies` on `Tenant` - Auto-loads `/etc/doublezero-controller/features.yaml` at startup if present (silently skips if absent); when `flex_algo.enabled: true`, populates topology data into the state cache, resolves tenant color communities via `resolveTenantColors`, and emits IS-IS flex-algo node segment and link configuration into the Arista EOS template - Template emits correct flex-algo definitions for both `include-any` constraint (`administrative-group include any N exclude 0`) and `exclude` constraint (`administrative-group exclude N,0`) topologies; gated per-link via `link_tagging.exclude` and per-tenant via `community_stamping` - Updates `e2e/compatibility_test.go` to set the mandatory upgrade boundary for RFC-18 interface/link operations to `before: "0.18.0"` ## Diff Breakdown | Category | Files | Lines (+/-) | Net | |-------------|-------|--------------|-------| | Core logic | 6 | +368 / -6 | +362 | | Scaffolding | 2 | +22 / -0 | +22 | | Tests | 4 | +482 / -2 | +480 | | Fixtures | 2 | +415 / -0 | +415 | | Docs | 1 | +4 / -0 | +4 | Most of the weight is tests and fixtures; core logic is the controller cache/template and Go SDK deserialization. > **Note on diff size:** The full diff vs `main` is large because this branch is stacked on PR 1 (#3497), which has not yet merged. The table above reflects only PR 5's contribution. After PR 1 merges and this branch is rebased, the diff shrinks to the ~15 files shown here. <details> <summary>Key files (click to expand)</summary> - [`controlplane/controller/internal/controller/server.go`](https://github.com/malbeclabs/doublezero/pull/3515/files#diff-f5e715ed1377ac408a4ecde2c60cbcb98327512c7d1496114ef143cb27e7afaf) — populates `Topologies` map in state cache; resolves `LinkTopologies` pubkeys to topology names and `UnicastDrained` from `LinkFlags`; computes `TenantTopologyColors`; `resolveTenantColors` falls back to `unicast-default` when tenant has no explicit topology assignments - [`controlplane/controller/internal/controller/templates/tunnel.tmpl`](https://github.com/malbeclabs/doublezero/pull/3515/files#diff-d67a980326aca35fdabdd5445fbbab4716f1ae412af4540770d5a9ee116b04d9) — IS-IS flex-algo node segment config, link admin-group tagging, BGP `next-hop resolution ribs` and `set extcommunity` stamping, and full rollback (`no` commands) when disabled; handles both `include-any` and `exclude` constraint topologies - [`controlplane/controller/internal/controller/features_config.go`](https://github.com/malbeclabs/doublezero/pull/3515/files#diff-24f09aab331b4d309662e5ee6550fd38fa173676ae868db381d9af23cf645f1d) — `FeaturesConfig` struct with `flex_algo.enabled`, `link_tagging.exclude`, and `community_stamping` controls; auto-loaded from `/etc/doublezero-controller/features.yaml` - [`controlplane/controller/internal/controller/models.go`](https://github.com/malbeclabs/doublezero/pull/3515/files#diff-bdc4e34592a7435dcde7dab78ffd735dcb9847447f0113bd9f3afc8d3d01f864) — adds `LinkTopologies`, `UnicastDrained`, `FlexAlgoNodeSegments`, `TenantTopologyColors` to controller model types; `TopologyModel` and `FlexAlgoEnabled()` for template rendering - [`smartcontract/sdk/go/serviceability/state.go`](https://github.com/malbeclabs/doublezero/pull/3515/files#diff-057f627e5f2629b35f1976fba6eaa1b3c507c511b0f47d2f80a3a1d0c684c4a1) — adds `TopologyType`, `TopologyConstraint`, `TopologyInfo`, `LinkFlagUnicastDrained`; extends `Link` with `LinkTopologies`/`LinkFlags` and `Tenant` with `IncludeTopologies` - [`smartcontract/sdk/go/serviceability/deserialize.go`](https://github.com/malbeclabs/doublezero/pull/3515/files#diff-b71f90b1b3e00de9bd820920e63f5615edb9b7d110c2b39f38895847509a7844) — adds `DeserializeTopologyInfo`; extends `DeserializeLink` with `LinkTopologies`/`LinkFlags` and `DeserializeTenant` with `IncludeTopologies` </details> ## Testing Verification - `TestGetConfig_FlexAlgo` (new): render tests for flex-algo disabled, enabled with both constraint types (`include-any` and `exclude`), and link excluded from tagging — all pass - `Test_resolveTenantColors` (new): 5 table-driven cases covering fallback to `unicast-default`, missing topology, single/multiple known pubkeys, and unknown pubkey — all pass - `TestE2E_IBRL`, `TestE2E_IBRL_WithAllocatedAddr`, `TestE2E_Multicast` — all pass; flex-algo config is suppressed in e2e (no `features.yaml` present) - `exclude` constraint flex-algo syntax validated on physical lab switches (chi-dn-dzd5–dzd8) --------- Co-authored-by: Greg Mitchell <greg@malbeclabs.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
RFC-18 flex-algo · PR 2 of 5 · see
rfcs/rfc-0018-flex-algo.mdDepends on: #3497 (PR 1)
Series: #3497 · #3512 · #3513 · #3514 · #3515
Summary of Changes
doublezero link topologysubcommands:create,delete,clear,list,backfilldoublezero_sdk::commands::topologytopology listdisplays name, admin-group bit, flex-algo number, BGP color community, constraint, and linked link counttopology clearremoves a topology from all links that reference it;topology backfillallocates flex-algo node segments on all activated devices for a given topologylink topologysubcommand group into the existingdoublezero linkcommand treeDiff Breakdown
Heavy on new code — all five CLI commands and five SDK commands are new files with no prior equivalent.
Key files (click to expand)
smartcontract/cli/src/topology/list.rs— lists all TopologyInfo accounts; shows BGP color (128 + admin_group_bit), constraint, and how many links are tagged with each topologysmartcontract/cli/src/topology/clear.rs— removes a topology from all links that reference it; confirms or dry-runs before submitting transactionssmartcontract/cli/src/topology/create.rs— creates a topology with name, constraint (include-anyorexclude); admin-group bit and flex-algo number are allocated automatically onchainsmartcontract/cli/src/topology/backfill.rs— callsBackfillTopologyfor a named topology, optionally scoped to specific device pubkeyssmartcontract/sdk/rs/src/commands/topology/backfill.rs— SDK command forBackfillTopology; includes unit tests with mock clientsmartcontract/sdk/rs/src/commands/topology/list.rs— SDK command for listing topology accounts; includes unit testsTesting Verification
cargo test -p doublezero_sdk -p doublezero_clipassescargo clippy -- -D warningscleanmake rust-fmtapplied before commit