Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
7e9d258
smartcontract: add AdminGroupBits ResourceExtension with UNICAST-DRAI…
ben-malbeclabs Mar 31, 2026
60b0f72
smartcontract: add TopologyInfo, FlexAlgoNodeSegment state structs; I…
ben-malbeclabs Mar 31, 2026
69000d4
smartcontract: add TopologyCreate instruction with admin-group bit al…
ben-malbeclabs Mar 31, 2026
d527bab
smartcontract: add TopologyDelete and TopologyClear instructions
ben-malbeclabs Apr 1, 2026
476b7be
smartcontract: add unicast_drained field to Link; contributor-writable
ben-malbeclabs Apr 1, 2026
d852675
smartcontract: add include_topologies to Tenant account; foundation-only
ben-malbeclabs Apr 1, 2026
495c7d7
smartcontract: fix include_topologies test assert and fixture generator
ben-malbeclabs Apr 1, 2026
d51866a
smartcontract: auto-tag UNICAST-DEFAULT topology at link activation
ben-malbeclabs Apr 1, 2026
02b0692
smartcontract: fix activate: add unicast-default owner check; refacto…
ben-malbeclabs Apr 1, 2026
8a322e0
smartcontract: fix activate: fold owner check into InvalidArgument gu…
ben-malbeclabs Apr 1, 2026
590e0c6
smartcontract: fix lint — missing include_topologies fields, unused i…
ben-malbeclabs Apr 1, 2026
f22446d
cli: add doublezero link topology create/delete/clear/list subcommands
ben-malbeclabs Apr 1, 2026
36aa817
cli: topology delete guard referencing links; list shows link counts …
ben-malbeclabs Apr 1, 2026
418f3d7
cli: add --include-topologies to doublezero tenant update
ben-malbeclabs Apr 1, 2026
665b731
cli: add --link-topology and --unicast-drained to doublezero link update
ben-malbeclabs Apr 1, 2026
c9dc2dd
cli: resolve topology names in link/tenant get and list display
ben-malbeclabs Apr 1, 2026
eba7807
cli: add doublezero-admin migrate command for RFC-18 link topology ba…
ben-malbeclabs Apr 1, 2026
a7de290
cli: fix migrate command — unicast-default seed case, dry-run counter…
ben-malbeclabs Apr 1, 2026
a320deb
cli: add AdminGroupBits to resource CLI type enum
ben-malbeclabs Apr 1, 2026
ec0a0e7
smartcontract: create AdminGroupBits in global-config set
ben-malbeclabs Apr 1, 2026
fe40363
cli: remove AdminGroupBits from resource operator commands
ben-malbeclabs Apr 1, 2026
92bf96c
smartcontract: fix topology/clear missing payer account in SDK comman…
ben-malbeclabs Apr 2, 2026
57075db
smartcontract: add BackfillTopology instruction for post-creation Vpn…
ben-malbeclabs Apr 2, 2026
12630d7
cli: validate topology name length before PDA derivation
ben-malbeclabs Apr 2, 2026
c7749b6
e2e: add doublezero-admin to manager container
ben-malbeclabs Apr 2, 2026
6177a0e
sdk: regenerate fixtures with RFC-18 fields; enable flex_algo_node_se…
ben-malbeclabs Apr 2, 2026
bfc8b2d
sdk: fix InterfaceV3 deserialization in Go, Python, and TypeScript SDKs
ben-malbeclabs Apr 2, 2026
1170ccb
sdk: fix duplicate payer in execute_transaction_inner when payer alre…
ben-malbeclabs Apr 2, 2026
6802647
sdk/serviceability: add FlexAlgoNodeSegment type to Python and TypeSc…
ben-malbeclabs Apr 2, 2026
60c1daa
smartcontract: rustfmt formatting fixes in instructions.rs
ben-malbeclabs Apr 2, 2026
86ce831
controlplane/controller: fix Interface zero-value comparison after sl…
ben-malbeclabs Apr 2, 2026
1335a0a
smartcontract: add link_flags, topology list/filter CLI, SDK updates …
ben-malbeclabs Apr 6, 2026
6f08edb
smartcontract: link_flags bitmask, update validation, topology PDA ch…
ben-malbeclabs Apr 6, 2026
beb1852
smartcontract: add topology account validation and cap enforcement to…
ben-malbeclabs Apr 6, 2026
66c1435
smartcontract: fix mtu values in link_wan_test fixtures; add topology…
ben-malbeclabs Apr 6, 2026
a6e3a59
sdk/go: fix parse_valid_link test and controller findLink after LinkT…
ben-malbeclabs Apr 6, 2026
ab98df5
smartcontract: restore start-test.sh to match main
ben-malbeclabs Apr 6, 2026
f828206
smartcontract: fix post-rebase
ben-malbeclabs Apr 7, 2026
cdc1abe
smartcontract: add RFC-18 flex-algo CHANGELOG entries
ben-malbeclabs Apr 7, 2026
a75bc55
smartcontract: fix incorrect MTU in test_update_cyoa_interface_with_i…
ben-malbeclabs Apr 7, 2026
a917712
sdk/ts: fix deserializeInterface to read flex_algo_node_segments for …
ben-malbeclabs Apr 7, 2026
d8f3300
e2e/smartcontract: fix CI failures on PR #3474
ben-malbeclabs Apr 7, 2026
2367d4a
smartcontract: fix rustfmt formatting in sdk/rs client.rs
ben-malbeclabs Apr 7, 2026
fe08d2a
smartcontract: fix post-rebase compile errors in topology/create.rs a…
ben-malbeclabs Apr 7, 2026
f8ffb7d
smartcontract: fix missing include_topologies field in cli user get test
ben-malbeclabs Apr 7, 2026
58e846f
smartcontract: remove duplicate test_link_create_invalid_mtu from lin…
ben-malbeclabs Apr 7, 2026
3c428f2
smartcontract: fix Cargo.lock conflict and regenerate fixtures after …
ben-malbeclabs Apr 7, 2026
baa3a44
smartcontract: restore link MTU validation lost in rebase; fix CYOA i…
ben-malbeclabs Apr 7, 2026
d6881e1
e2e/smartcontract: fix e2e failures caused by missing unicast-default…
ben-malbeclabs Apr 7, 2026
a92da56
e2e: move unicast-default topology creation after global-config set
ben-malbeclabs Apr 7, 2026
086fc12
Merge branch 'main' into bc/rfc18-smartcontract
ben-malbeclabs Apr 7, 2026
1cc8cff
smartcontract/e2e: fix topology UpdateLink accounts and compat ranges
ben-malbeclabs Apr 7, 2026
0551df2
smartcontract: fix telemetry and serviceability test setup for RFC-18
ben-malbeclabs Apr 8, 2026
7fb3523
e2e,sdk: fix device_interface_create known-incompat range; increase T…
ben-malbeclabs Apr 8, 2026
a3a2833
sdk/ts: add per-request timeout to RPC connection to prevent indefini…
ben-malbeclabs Apr 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ dev/.deploy/
# Ignore the directory used for checking out the monitor tool in CI
/doublezero_monitor/
.claude/settings.local.json
.worktrees/
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,19 @@ All notable changes to this project will be documented in this file.
- Client
- Add `doublezero_connection_info` Prometheus metric exposing connection metadata (user_type, network, current_device, metro, tunnel_name, tunnel_src, tunnel_dst) ([#3201](https://github.com/malbeclabs/doublezero/pull/3201))
- Add `doublezero_connection_rtt_nanoseconds` and `doublezero_connection_loss_percentage` Prometheus metrics reporting RTT and packet loss to the current connected device
- Smartcontract
- Add `TopologyInfo` onchain account for IS-IS flex-algo link classification: auto-assigned TE admin-group bit (1–62), derived flex-algo number (128 + bit), and constraint type (`include-any`/`include-all`); capped at 62 topologies via `AdminGroupBits` resource extension
- Add `link_topologies: Vec<Pubkey>` (capped at 8) and `link_flags: u8` (bit 0 = unicast-drained) to the `Link` account
- Add `include_topologies` to the `Tenant` account for topology-filtered routing opt-in
- Enforce UNICAST-DEFAULT topology existence as a precondition for link activation
- CLI
- Add `doublezero link topology` subcommands: `create`, `delete`, `clear`, `list`, `backfill`
- Add `--link-topology <name>` and `--unicast-drained <bool>` flags to `doublezero link update`
- Add `--topology <name>` filter to `doublezero link list` (`default` = untagged links)
- Add `--include-topologies <name>` flag to `doublezero tenant update`
- Add `doublezero-admin migrate flex-algo [--dry-run]` to tag existing links with UNICAST-DEFAULT and backfill node segments
- SDK
- Update Go, Python, and TypeScript SDKs with `TopologyInfo` deserialization and new `link_topologies`, `link_flags`, and `include_topologies` fields

## [v0.15.0](https://github.com/malbeclabs/doublezero/compare/client/v0.14.0...client/v0.15.0) - 2026-03-27

Expand Down
15 changes: 15 additions & 0 deletions activator/src/process/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,9 @@ mod tests {
link_health: doublezero_serviceability::state::link::LinkHealth::Pending,
desired_status:
doublezero_serviceability::state::link::LinkDesiredStatus::Activated,

link_topologies: Vec::new(),
link_flags: 0,
};

let tunnel_cloned = tunnel.clone();
Expand Down Expand Up @@ -397,6 +400,9 @@ mod tests {
side_z_iface_name: "Ethernet1".to_string(),
link_health: doublezero_serviceability::state::link::LinkHealth::Pending,
desired_status: doublezero_serviceability::state::link::LinkDesiredStatus::Activated,

link_topologies: Vec::new(),
link_flags: 0,
};

let link_cloned = link.clone();
Expand Down Expand Up @@ -457,6 +463,9 @@ mod tests {
link_health: doublezero_serviceability::state::link::LinkHealth::Pending,
desired_status:
doublezero_serviceability::state::link::LinkDesiredStatus::Activated,

link_topologies: Vec::new(),
link_flags: 0,
};

let tunnel_clone = tunnel.clone();
Expand Down Expand Up @@ -544,6 +553,9 @@ mod tests {
link_health: doublezero_serviceability::state::link::LinkHealth::Pending,
desired_status:
doublezero_serviceability::state::link::LinkDesiredStatus::Activated,

link_topologies: Vec::new(),
link_flags: 0,
};

// SDK command fetches the link internally
Expand Down Expand Up @@ -623,6 +635,9 @@ mod tests {
link_health: doublezero_serviceability::state::link::LinkHealth::Pending,
desired_status:
doublezero_serviceability::state::link::LinkDesiredStatus::Activated,

link_topologies: Vec::new(),
link_flags: 0,
};

// SDK command fetches the link internally
Expand Down
6 changes: 6 additions & 0 deletions activator/src/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,9 @@ mod tests {
side_z_iface_name: "Ethernet1".to_string(),
link_health: doublezero_serviceability::state::link::LinkHealth::Pending,
desired_status: doublezero_serviceability::state::link::LinkDesiredStatus::Activated,

link_topologies: Vec::new(),
link_flags: 0,
};

let mut existing_links: HashMap<Pubkey, Link> = HashMap::new();
Expand Down Expand Up @@ -798,6 +801,9 @@ mod tests {
side_z_iface_name: "Ethernet3".to_string(),
link_health: doublezero_serviceability::state::link::LinkHealth::Pending,
desired_status: doublezero_serviceability::state::link::LinkDesiredStatus::Activated,

link_topologies: Vec::new(),
link_flags: 0,
};

let new_link_cloned = new_link.clone();
Expand Down
38 changes: 34 additions & 4 deletions client/doublezero/src/cli/link.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
use clap::{Args, Subcommand};
use doublezero_cli::link::{
accept::AcceptLinkCliCommand, delete::*, dzx_create::CreateDZXLinkCliCommand, get::*,
latency::LinkLatencyCliCommand, list::*, sethealth::SetLinkHealthCliCommand, update::*,
wan_create::*,
use doublezero_cli::{
link::{
accept::AcceptLinkCliCommand, delete::*, dzx_create::CreateDZXLinkCliCommand, get::*,
latency::LinkLatencyCliCommand, list::*, sethealth::SetLinkHealthCliCommand, update::*,
wan_create::*,
},
topology::{
backfill::BackfillTopologyCliCommand, clear::ClearTopologyCliCommand,
create::CreateTopologyCliCommand, delete::DeleteTopologyCliCommand,
list::ListTopologyCliCommand,
},
};

#[derive(Args, Debug)]
Expand Down Expand Up @@ -53,4 +60,27 @@ pub enum LinkCommands {
// Hidden because this is an internal/operational command not intended for general CLI users.
#[clap(hide = true)]
SetHealth(SetLinkHealthCliCommand),
/// Manage link topologies
#[clap()]
Topology(TopologyLinkCommand),
}

#[derive(Args, Debug)]
pub struct TopologyLinkCommand {
#[command(subcommand)]
pub command: TopologyCommands,
}

#[derive(Debug, Subcommand)]
pub enum TopologyCommands {
/// Create a new topology
Create(CreateTopologyCliCommand),
/// Delete a topology
Delete(DeleteTopologyCliCommand),
/// Clear a topology from links
Clear(ClearTopologyCliCommand),
/// Backfill FlexAlgoNodeSegment entries on existing Vpnv4 loopbacks
Backfill(BackfillTopologyCliCommand),
/// List all topologies
List(ListTopologyCliCommand),
}
2 changes: 2 additions & 0 deletions client/doublezero/src/command/connect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1072,6 +1072,7 @@ mod tests {
metro_routing: false,
route_liveness: false,
billing: TenantBillingConfig::default(),
include_topologies: vec![],
};

let mut tenants = HashMap::new();
Expand Down Expand Up @@ -1397,6 +1398,7 @@ mod tests {
metro_routing: false,
route_liveness: false,
billing: TenantBillingConfig::default(),
include_topologies: vec![],
};
tenants.insert(pk, tenant.clone());
(pk, tenant)
Expand Down
1 change: 1 addition & 0 deletions client/doublezero/src/dzd_latency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ mod tests {
ip_net: NetworkV4::new(ip, 32).unwrap(),
node_segment_idx: 0,
user_tunnel_endpoint: true,
flex_algo_node_segments: vec![],
})
})
.collect();
Expand Down
9 changes: 8 additions & 1 deletion client/doublezero/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::cli::{
AirdropCommands, AuthorityCommands, FeatureFlagsCommands, FoundationAllowlistCommands,
GlobalConfigCommands, QaAllowlistCommands,
},
link::LinkCommands,
link::{LinkCommands, TopologyCommands},
location::LocationCommands,
user::UserCommands,
};
Expand Down Expand Up @@ -232,6 +232,13 @@ async fn main() -> eyre::Result<()> {
LinkCommands::Latency(args) => args.execute(&client, &mut handle),
LinkCommands::Delete(args) => args.execute(&client, &mut handle),
LinkCommands::SetHealth(args) => args.execute(&client, &mut handle),
LinkCommands::Topology(args) => match args.command {
TopologyCommands::Create(args) => args.execute(&client, &mut handle),
TopologyCommands::Delete(args) => args.execute(&client, &mut handle),
TopologyCommands::Clear(args) => args.execute(&client, &mut handle),
TopologyCommands::Backfill(args) => args.execute(&client, &mut handle),
TopologyCommands::List(args) => args.execute(&client, &mut handle),
},
},
Command::AccessPass(command) => match command.command {
cli::accesspass::AccessPassCommands::Set(args) => args.execute(&client, &mut handle),
Expand Down
2 changes: 1 addition & 1 deletion controlplane/controller/internal/controller/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ type Interface struct {

// toInterface validates onchain data for a serviceability interface and converts it to a controller interface.
func toInterface(iface serviceability.Interface) (Interface, error) {
if iface == (serviceability.Interface{}) {
if iface.IpNet == ([5]byte{}) && iface.Name == "" {
return Interface{}, errors.New("serviceability interface cannot be nil")
}

Expand Down
12 changes: 6 additions & 6 deletions controlplane/controller/internal/controller/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,22 +348,22 @@ func (c *Controller) updateStateCache(ctx context.Context) error {
cache.Ipv4BgpPeers = append(cache.Ipv4BgpPeers, candidateIpv4BgpPeer)

// determine if interface is in an onchain link and assign metrics
findLink := func(intf Interface) serviceability.Link {
for _, link := range links {
findLink := func(intf Interface) *serviceability.Link {
for i, link := range links {
if d.PubKey == base58.Encode(link.SideAPubKey[:]) && intf.Name == link.SideAIfaceName {
return link
return &links[i]
}
if d.PubKey == base58.Encode(link.SideZPubKey[:]) && intf.Name == link.SideZIfaceName {
return link
return &links[i]
}
}
return serviceability.Link{}
return nil
}

for i, iface := range d.Interfaces {
link := findLink(iface)

if link == (serviceability.Link{}) || (link.Status != serviceability.LinkStatusActivated && link.Status != serviceability.LinkStatusSoftDrained && link.Status != serviceability.LinkStatusHardDrained) {
if link == nil || (link.Status != serviceability.LinkStatusActivated && link.Status != serviceability.LinkStatusSoftDrained && link.Status != serviceability.LinkStatusHardDrained) {
d.Interfaces[i].IsLink = false
d.Interfaces[i].Metric = 0
d.Interfaces[i].LinkStatus = serviceability.LinkStatusPending
Expand Down
7 changes: 5 additions & 2 deletions controlplane/doublezero-admin/src/cli/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use super::{multicast::MulticastCliCommand, sentinel::SentinelCliCommand};
use crate::cli::{
accesspass::AccessPassCliCommand, config::ConfigCliCommand, contributor::ContributorCliCommand,
device::DeviceCliCommand, exchange::ExchangeCliCommand, globalconfig::GlobalConfigCliCommand,
link::LinkCliCommand, location::LocationCliCommand, permission::PermissionCliCommand,
tenant::TenantCliCommand, user::UserCliCommand,
link::LinkCliCommand, location::LocationCliCommand, migrate::MigrateCliCommand,
permission::PermissionCliCommand, tenant::TenantCliCommand, user::UserCliCommand,
};
use clap::{Args, Subcommand};
use clap_complete::Shell;
Expand Down Expand Up @@ -69,6 +69,9 @@ pub enum Command {
/// Sentinel admin commands
#[command()]
Sentinel(SentinelCliCommand),
/// Backfill link topologies and report Vpnv4 loopback gaps (RFC-18 migration)
#[command()]
Migrate(MigrateCliCommand),
/// Export all data to files
#[command()]
Export(ExportCliCommand),
Expand Down
Loading
Loading