Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ All notable changes to this project will be documented in this file.
- SDK
- Go serviceability SDK adds `TopologyInfo` account type with `TopologyConstraint`, `IndexType` / `TopologyType` account-type constants, and `GetProgramData` dispatch case; extends `Link` with `LinkTopologies` and `LinkFlags`; extends `Tenant` with `IncludeTopologies`
- CLI
- Add `tunnel_endpoint` field to `doublezero user list` output (table and JSON) showing the device-side GRE endpoint IP assigned to each user
- Add `cyoa_ips` field to `doublezero device get` and `doublezero device list` output, showing the IP networks of interfaces with `user_tunnel_endpoint` enabled
- Add `--tunnel_endpoint` flag to `user update` command so operators can set the tunnel endpoint IP of an existing user
- Extend `doublezero resource verify` to check `MulticastPublisherBlock` against multicast publisher users' `dz_ip` allocations; legacy `dz_ip`s that fall outside the block's range are ignored so pre-existing users allocated before this extension existed do not produce false discrepancies
Expand Down
4 changes: 2 additions & 2 deletions e2e/fixtures/ibrl/doublezero_user_list_user_added.tmpl
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
account | tenant | user_type | groups | device | location | cyoa_type | client_ip | dz_ip | accesspass | tunnel_id | tunnel_net | status | bgp_status | owner
IGNORED | | IBRL | | ny5-dz01 | New York | GREOverDIA | {{.ClientIP}} | {{.ClientIP}} | Prepaid: (MAX) | 500 | 169.254.0.0/31 | activated | unknown | {{.ClientPubkeyAddress}}
account | tenant | user_type | groups | device | location | cyoa_type | client_ip | dz_ip | accesspass | tunnel_id | tunnel_net | tunnel_endpoint | status | bgp_status | owner
IGNORED | | IBRL | | ny5-dz01 | New York | GREOverDIA | {{.ClientIP}} | {{.ClientIP}} | Prepaid: (MAX) | 500 | 169.254.0.0/31 | {{.DeviceIP}} | activated | unknown | {{.ClientPubkeyAddress}}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
account | tenant | user_type | groups | device | location | cyoa_type | client_ip | dz_ip | accesspass | tunnel_id | tunnel_net | status | bgp_status | owner
account | tenant | user_type | groups | device | location | cyoa_type | client_ip | dz_ip | accesspass | tunnel_id | tunnel_net | tunnel_endpoint | status | bgp_status | owner
{{- range .IBRLUsers}}
IGNORED | | IBRL | | la2-dz01 | Los Angeles | GREOverDIA | {{.ClientIP}} | {{.ClientIP}} | Prepaid: (MAX) | {{.TunnelID}} | {{.TunnelNet}} | activated | unknown | {{$.ClientPubkeyAddress}}
IGNORED | | IBRL | | la2-dz01 | Los Angeles | GREOverDIA | {{.ClientIP}} | {{.ClientIP}} | Prepaid: (MAX) | {{.TunnelID}} | {{.TunnelNet}} | {{.TunnelEndpoint}} | activated | unknown | {{$.ClientPubkeyAddress}}
{{- end}}
IGNORED | | IBRLWithAllocatedIP | | ny5-dz01 | New York | GREOverDIA | {{.ClientIP}} | {{.ExpectedAllocatedClientIP}} | Prepaid: (MAX) | {{.AllocatedUserTunnelID}} | {{.AllocatedUserTunnelNet}} | activated | unknown | {{.ClientPubkeyAddress}}
IGNORED | | IBRLWithAllocatedIP | | ny5-dz01 | New York | GREOverDIA | {{.ClientIP}} | {{.ExpectedAllocatedClientIP}} | Prepaid: (MAX) | {{.AllocatedUserTunnelID}} | {{.AllocatedUserTunnelNet}} | {{.DeviceIP}} | activated | unknown | {{.ClientPubkeyAddress}}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
account | tenant | user_type | groups | device | location | cyoa_type | client_ip | dz_ip | accesspass | tunnel_id | tunnel_net | status | bgp_status | owner
account | tenant | user_type | groups | device | location | cyoa_type | client_ip | dz_ip | accesspass | tunnel_id | tunnel_net | tunnel_endpoint | status | bgp_status | owner
{{- range .IBRLUsers}}
IGNORED | | IBRL | | la2-dz01 | Los Angeles | GREOverDIA | {{.ClientIP}} | {{if eq .ClientIP "3.4.5.6"}}0.0.0.0{{else}}{{.ClientIP}}{{end}} | Prepaid: (MAX) | {{.TunnelID}} | {{.TunnelNet}} | {{if eq .ClientIP "3.4.5.6"}}banned{{else}}activated{{end}} | unknown | {{$.ClientPubkeyAddress}}
IGNORED | | IBRL | | la2-dz01 | Los Angeles | GREOverDIA | {{.ClientIP}} | {{if eq .ClientIP "3.4.5.6"}}0.0.0.0{{else}}{{.ClientIP}}{{end}} | Prepaid: (MAX) | {{.TunnelID}} | {{.TunnelNet}} | {{.TunnelEndpoint}} | {{if eq .ClientIP "3.4.5.6"}}banned{{else}}activated{{end}} | unknown | {{$.ClientPubkeyAddress}}
{{- end}}
1 change: 1 addition & 0 deletions e2e/ibrl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ func checkIBRLPostConnect(t *testing.T, dn *TestDevnet, device *devnet.Device, c
data: map[string]any{
"ClientIP": client.CYOANetworkIP,
"ClientPubkeyAddress": client.Pubkey,
"DeviceIP": device.CYOANetworkIP,
},
cmd: []string{"doublezero", "user", "list"},
},
Expand Down
14 changes: 8 additions & 6 deletions e2e/ibrl_with_allocated_ip_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ import (

// ibrlUserTunnelInfo holds tunnel assignment info for an IBRL user, parsed from user list output.
type ibrlUserTunnelInfo struct {
ClientIP string
TunnelID string
TunnelNet string
ClientIP string
TunnelID string
TunnelNet string
TunnelEndpoint string
}

// parseIBRLTunnelInfo parses user list output and returns tunnel info for IBRL and IBRLWithAllocatedIP users.
Expand All @@ -32,9 +33,10 @@ func parseIBRLTunnelInfo(output []byte) (ibrlUsers []ibrlUserTunnelInfo, allocUs
switch row["user_type"] {
case "IBRL":
ibrlUsers = append(ibrlUsers, ibrlUserTunnelInfo{
ClientIP: row["client_ip"],
TunnelID: row["tunnel_id"],
TunnelNet: row["tunnel_net"],
ClientIP: row["client_ip"],
TunnelID: row["tunnel_id"],
TunnelNet: row["tunnel_net"],
TunnelEndpoint: row["tunnel_endpoint"],
})
case "IBRLWithAllocatedIP":
allocUserTunnelID = row["tunnel_id"]
Expand Down
10 changes: 6 additions & 4 deletions smartcontract/cli/src/user/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ pub struct UserDisplay {
pub accesspass: String,
pub tunnel_id: u16,
pub tunnel_net: NetworkV4,
pub tunnel_endpoint: Ipv4Addr,
pub status: UserStatus,
pub bgp_status: BGPStatus,
#[serde(serialize_with = "serializer::serialize_pubkey_as_string")]
Expand Down Expand Up @@ -362,6 +363,7 @@ impl ListUserCliCommand {
},
tunnel_id: user.tunnel_id,
tunnel_net: user.tunnel_net,
tunnel_endpoint: user.tunnel_endpoint,
status: user.status,
bgp_status: user.bgp_status,
owner: user.owner,
Expand Down Expand Up @@ -782,7 +784,7 @@ mod tests {
publishers: vec![],
subscribers: vec![],
validator_pubkey: Pubkey::default(),
tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED,
tunnel_endpoint: [1, 2, 3, 4].into(),
tunnel_flags: 0,
bgp_status: Default::default(),
last_bgp_up_at: 0,
Expand Down Expand Up @@ -824,7 +826,7 @@ mod tests {
publishers: vec![],
subscribers: vec![mgroup1_pubkey],
validator_pubkey: Pubkey::default(),
tunnel_endpoint: std::net::Ipv4Addr::UNSPECIFIED,
tunnel_endpoint: [5, 6, 7, 8].into(),
tunnel_flags: 0,
bgp_status: Default::default(),
last_bgp_up_at: 0,
Expand Down Expand Up @@ -894,7 +896,7 @@ mod tests {
.execute(&client, &mut output);
assert!(res.is_ok());
let output_str = String::from_utf8(output).unwrap();
assert_eq!(output_str, " account | tenant | user_type | groups | device | location | cyoa_type | client_ip | dz_ip | accesspass | tunnel_id | tunnel_net | status | bgp_status | owner \n 11111115RidqCHAoz6dzmXxGcfWLNzevYqNpaRAUo | 11111115q4EpJaTXAZWpCg3J2zppWGSZ46KXozzo9 | Multicast | S:m_code | device1_code | location1_name | GREOverDIA | 1.2.3.4 | 2.3.4.5 | Prepaid: (expires epoch 10) | 500 | 1.2.3.5/32 | activated | unknown | 11111115RidqCHAoz6dzmXxGcfWLNzevYqNpaRAUo \n");
assert_eq!(output_str, " account | tenant | user_type | groups | device | location | cyoa_type | client_ip | dz_ip | accesspass | tunnel_id | tunnel_net | tunnel_endpoint | status | bgp_status | owner \n 11111115RidqCHAoz6dzmXxGcfWLNzevYqNpaRAUo | 11111115q4EpJaTXAZWpCg3J2zppWGSZ46KXozzo9 | Multicast | S:m_code | device1_code | location1_name | GREOverDIA | 1.2.3.4 | 2.3.4.5 | Prepaid: (expires epoch 10) | 500 | 1.2.3.5/32 | 5.6.7.8 | activated | unknown | 11111115RidqCHAoz6dzmXxGcfWLNzevYqNpaRAUo \n");

let mut output = Vec::new();
let res = ListUserCliCommand {
Expand Down Expand Up @@ -922,7 +924,7 @@ mod tests {
assert!(res.is_ok());

let output_str = String::from_utf8(output).unwrap();
assert_eq!(output_str, "[{\"account\":\"11111115RidqCHAoz6dzmXxGcfWLNzevYqNpaRAUo\",\"tenant\":\"11111115q4EpJaTXAZWpCg3J2zppWGSZ46KXozzo9\",\"user_type\":\"Multicast\",\"device_pk\":\"11111115q4EpJaTXAZWpCg3J2zppWGSZ46KXozzo9\",\"multicast\":\"S:m_code\",\"publishers\":\"\",\"subscribers\":\"11111115q4EpJaTXAZWpCg3J2zppWGSZ46KXozzo8\",\"device_name\":\"device1_code\",\"location_code\":\"location1_code\",\"location_name\":\"location1_name\",\"cyoa_type\":\"GREOverDIA\",\"client_ip\":\"1.2.3.4\",\"dz_ip\":\"2.3.4.5\",\"accesspass\":\"Prepaid: (expires epoch 10)\",\"tunnel_id\":500,\"tunnel_net\":\"1.2.3.5/32\",\"status\":\"Activated\",\"bgp_status\":\"Unknown\",\"owner\":\"11111115RidqCHAoz6dzmXxGcfWLNzevYqNpaRAUo\"}]\n");
assert_eq!(output_str, "[{\"account\":\"11111115RidqCHAoz6dzmXxGcfWLNzevYqNpaRAUo\",\"tenant\":\"11111115q4EpJaTXAZWpCg3J2zppWGSZ46KXozzo9\",\"user_type\":\"Multicast\",\"device_pk\":\"11111115q4EpJaTXAZWpCg3J2zppWGSZ46KXozzo9\",\"multicast\":\"S:m_code\",\"publishers\":\"\",\"subscribers\":\"11111115q4EpJaTXAZWpCg3J2zppWGSZ46KXozzo8\",\"device_name\":\"device1_code\",\"location_code\":\"location1_code\",\"location_name\":\"location1_name\",\"cyoa_type\":\"GREOverDIA\",\"client_ip\":\"1.2.3.4\",\"dz_ip\":\"2.3.4.5\",\"accesspass\":\"Prepaid: (expires epoch 10)\",\"tunnel_id\":500,\"tunnel_net\":\"1.2.3.5/32\",\"tunnel_endpoint\":\"5.6.7.8\",\"status\":\"Activated\",\"bgp_status\":\"Unknown\",\"owner\":\"11111115RidqCHAoz6dzmXxGcfWLNzevYqNpaRAUo\"}]\n");

let mut output = Vec::new();
let res = ListUserCliCommand {
Expand Down
Loading