diff --git a/Cargo.lock b/Cargo.lock index 003fc332..5a92dd31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1465,6 +1465,12 @@ dependencies = [ "foldhash 0.2.0", ] +[[package]] +name = "hashbrown" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" + [[package]] name = "headers" version = "0.4.1" @@ -1855,12 +1861,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.13.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.0", "serde", "serde_core", ] @@ -2974,7 +2980,7 @@ dependencies = [ [[package]] name = "progenitor" version = "0.13.0" -source = "git+https://github.com/oxidecomputer/progenitor#f0b9dbc35214adfdc13eb7deb7884582397ee31d" +source = "git+https://github.com/oxidecomputer/progenitor#0fbc56b6eb4e73e7ffb2bbef5c78c4805948fb9b" dependencies = [ "progenitor-impl", ] @@ -2997,7 +3003,7 @@ dependencies = [ [[package]] name = "progenitor-impl" version = "0.13.0" -source = "git+https://github.com/oxidecomputer/progenitor#f0b9dbc35214adfdc13eb7deb7884582397ee31d" +source = "git+https://github.com/oxidecomputer/progenitor#0fbc56b6eb4e73e7ffb2bbef5c78c4805948fb9b" dependencies = [ "heck", "http 1.4.0", diff --git a/cli/src/cmd_net.rs b/cli/src/cmd_net.rs index cacc0e80..8faebd11 100644 --- a/cli/src/cmd_net.rs +++ b/cli/src/cmd_net.rs @@ -16,7 +16,7 @@ use oxide::{ types::{ Address, AddressConfig, BgpAnnounceSetCreate, BgpAnnouncementCreate, BgpPeer, BgpPeerConfig, BgpPeerStatus, ImportExportPolicy, IpNet, LinkConfigCreate, LinkFec, - LinkSpeed, LldpLinkConfigCreate, Name, NameOrId, Route, RouteConfig, + LinkSpeed, LldpLinkConfigCreate, Name, NameOrId, Route, RouteConfig, RouterPeerType, SwitchInterfaceConfigCreate, SwitchInterfaceKind, SwitchInterfaceKind2, SwitchPort, SwitchPortConfigCreate, SwitchPortGeometry, SwitchPortGeometry2, SwitchPortRouteConfig, SwitchPortSettingsCreate, SwitchSlot, @@ -421,7 +421,10 @@ impl AuthenticatedCmd for CmdBgpFilter { let peer = config .peers .iter_mut() - .find(|x| x.addr == Some(self.peer)) + .find(|x| { + matches!( &x.addr, + RouterPeerType::Numbered { ip } if *ip == self.peer) + }) .ok_or(anyhow::anyhow!("specified peer does not exist"))?; let list: Vec = self @@ -502,7 +505,10 @@ impl AuthenticatedCmd for CmdBgpAuth { let peer = config .peers .iter_mut() - .find(|x| x.addr == Some(self.peer)) + .find(|x| { + matches!(&x.addr, + RouterPeerType::Numbered { ip } if *ip == self.peer) + }) .ok_or(anyhow::anyhow!("specified peer does not exist"))?; peer.md5_auth_key = self.authstring.clone(); @@ -564,7 +570,10 @@ impl AuthenticatedCmd for CmdBgpLocalPref { let peer = config .peers .iter_mut() - .find(|x| x.addr == Some(self.peer)) + .find(|x| { + matches!(&x.addr, + RouterPeerType::Numbered { ip } if *ip == self.peer) + }) .ok_or(anyhow::anyhow!("specified peer does not exist"))?; peer.local_pref = self.local_pref @@ -1089,7 +1098,7 @@ impl AuthenticatedCmd for CmdBgpPeerSet { let mut settings = current_port_settings(client, &self.rack, self.switch.into(), &self.port).await?; let peer = BgpPeer { - addr: Some(self.addr), + addr: RouterPeerType::Numbered { ip: self.addr }, allowed_import: if self.allowed_imports.is_empty() { ImportExportPolicy::NoFiltering } else { @@ -1119,7 +1128,6 @@ impl AuthenticatedCmd for CmdBgpPeerSet { enforce_first_as: self.enforce_first_as, hold_time: self.hold_time, idle_hold_time: self.idle_hold_time, - interface_name: PHY0.try_into().unwrap(), keepalive: self.keepalive, local_pref: self.local_pref, md5_auth_key: self.authstring.clone(), @@ -1127,14 +1135,24 @@ impl AuthenticatedCmd for CmdBgpPeerSet { multi_exit_discriminator: self.multi_exit_discriminator, remote_asn: self.remote_asn, vlan_id: self.vlan_id, - router_lifetime: self.router_lifetime.unwrap_or(0), }; match settings .bgp_peers .iter_mut() .find(|link| *link.link_name == PHY0) { - Some(conf) => match conf.peers.iter_mut().find(|x| x.addr == peer.addr) { + Some(conf) => match conf.peers.iter_mut().find(|x| match (&x.addr, &peer.addr) { + ( + RouterPeerType::Unnumbered { router_lifetime: a }, + RouterPeerType::Unnumbered { router_lifetime: b }, + ) if **a == **b => true, + (RouterPeerType::Numbered { ip: a }, RouterPeerType::Numbered { ip: b }) + if a == b => + { + true + } + _ => false, + }) { Some(p) => *p = peer, None => conf.peers.push(peer), }, @@ -1190,7 +1208,10 @@ impl AuthenticatedCmd for CmdBgpPeerDel { .find(|link| *link.link_name == PHY0) { let before = config.peers.len(); - config.peers.retain(|x| x.addr != Some(self.addr)); + config.peers.retain(|x| { + matches!(&x.addr, + RouterPeerType::Numbered { ip } if *ip == self.addr) + }); let after = config.peers.len(); if before == after { eprintln_nopipe!("no peers match the provided address"); @@ -1350,7 +1371,11 @@ impl AuthenticatedCmd for CmdPortConfig { writeln!( &mut tw, "{}\t{}\t[{}]\t[{}]\t{:?}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}", - p.addr.map_or("-".to_string(), |a| a.to_string()), + match &p.addr { + RouterPeerType::Unnumbered { router_lifetime } => + format!("({router_lifetime})"), + RouterPeerType::Numbered { ip } => ip.to_string(), + }, match &p.bgp_config { NameOrId::Id(id) => bgp_configs[id].to_string(), NameOrId::Name(name) => name.to_string(), diff --git a/cli/tests/data/test_switch_port_settings_show.stdout b/cli/tests/data/test_switch_port_settings_show.stdout index 62da18cd..83bce616 100644 --- a/cli/tests/data/test_switch_port_settings_show.stdout +++ b/cli/tests/data/test_switch_port_settings_show.stdout @@ -26,7 +26,7 @@ Address Lot VLAN BGP Peer Config Export Import Communities Connect Retry Delay Open Enforce First AS Hold Time Idle Hold Time Keepalive Local Pref Md5 Auth Min TTL MED Remote ASN VLAN 169.254.20.1 as65547 [198.51.100.0/24] [no filtering] [] 3 3 false 6 3 2 - - - - - - 169.254.40.1 as65547 [203.0.113.0/24] [no filtering] [] 0 0 false 6 0 2 - - - - - 400 -- as65547 [203.0.113.0/24] [no filtering] [] 0 0 false 6 0 2 - - - - - 400 +(0) as65547 [203.0.113.0/24] [no filtering] [] 0 0 false 6 0 2 - - - - - 400 Destination Nexthop Vlan Preference diff --git a/cli/tests/test_net.rs b/cli/tests/test_net.rs index 9c994a21..1ae3546a 100644 --- a/cli/tests/test_net.rs +++ b/cli/tests/test_net.rs @@ -2,16 +2,16 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -// Copyright 2025 Oxide Computer Company +// Copyright 2026 Oxide Computer Company use chrono::prelude::*; use httpmock::MockServer; use oxide::types::{ AddressLot, AddressLotBlock, AddressLotBlockResultsPage, AddressLotKind, AddressLotResultsPage, BgpConfig, BgpConfigResultsPage, BgpPeer, ImportExportPolicy, LinkFec, LinkSpeed, - MaxPathConfig, Name, NameOrId, SwitchPort, SwitchPortAddressView, SwitchPortConfig, - SwitchPortGeometry2, SwitchPortLinkConfig, SwitchPortResultsPage, SwitchPortRouteConfig, - SwitchPortSettings, SwitchSlot, + MaxPathConfig, Name, NameOrId, RouterPeerType, SwitchPort, SwitchPortAddressView, + SwitchPortConfig, SwitchPortGeometry2, SwitchPortLinkConfig, SwitchPortResultsPage, + SwitchPortRouteConfig, SwitchPortSettings, SwitchSlot, }; use oxide_httpmock::MockServerExt; use uuid::Uuid; @@ -130,8 +130,9 @@ fn test_port_config() { ], bgp_peers: vec![ BgpPeer { - interface_name: "phy0".try_into().unwrap(), - addr: Some("169.254.10.1".parse().unwrap()), + addr: RouterPeerType::Numbered { + ip: "169.254.10.1".parse().unwrap(), + }, bgp_config: NameOrId::Id(bgp_configs.items[0].id), allowed_export: ImportExportPolicy::Allow(vec!["198.51.100.0/24".parse().unwrap()]), allowed_import: ImportExportPolicy::NoFiltering, @@ -148,11 +149,11 @@ fn test_port_config() { multi_exit_discriminator: None, remote_asn: None, vlan_id: None, - router_lifetime: 0, }, BgpPeer { - interface_name: "phy0".try_into().unwrap(), - addr: Some("169.254.30.1".parse().unwrap()), + addr: RouterPeerType::Numbered { + ip: "169.254.30.1".parse().unwrap(), + }, bgp_config: NameOrId::Id(bgp_configs.items[0].id), allowed_export: ImportExportPolicy::Allow(vec!["203.0.113.0/24".parse().unwrap()]), allowed_import: ImportExportPolicy::NoFiltering, @@ -169,7 +170,6 @@ fn test_port_config() { multi_exit_discriminator: None, remote_asn: None, vlan_id: Some(300), - router_lifetime: 0, }, ], groups: Vec::new(), @@ -226,8 +226,9 @@ fn test_port_config() { ], bgp_peers: vec![ BgpPeer { - interface_name: "phy0".try_into().unwrap(), - addr: Some("169.254.20.1".parse().unwrap()), + addr: RouterPeerType::Numbered { + ip: "169.254.20.1".parse().unwrap(), + }, bgp_config: NameOrId::Id(bgp_configs.items[0].id), allowed_export: ImportExportPolicy::Allow(vec!["198.51.100.0/24".parse().unwrap()]), allowed_import: ImportExportPolicy::NoFiltering, @@ -244,11 +245,11 @@ fn test_port_config() { multi_exit_discriminator: None, remote_asn: None, vlan_id: None, - router_lifetime: 0, }, BgpPeer { - interface_name: "phy0".try_into().unwrap(), - addr: Some("169.254.40.1".parse().unwrap()), + addr: RouterPeerType::Numbered { + ip: "169.254.40.1".parse().unwrap(), + }, bgp_config: NameOrId::Id(bgp_configs.items[0].id), allowed_export: ImportExportPolicy::Allow(vec!["203.0.113.0/24".parse().unwrap()]), allowed_import: ImportExportPolicy::NoFiltering, @@ -265,11 +266,11 @@ fn test_port_config() { multi_exit_discriminator: None, remote_asn: None, vlan_id: Some(400), - router_lifetime: 0, }, BgpPeer { - interface_name: "phy0".try_into().unwrap(), - addr: None, + addr: RouterPeerType::Unnumbered { + router_lifetime: 0.into(), + }, bgp_config: NameOrId::Id(bgp_configs.items[0].id), allowed_export: ImportExportPolicy::Allow(vec!["203.0.113.0/24".parse().unwrap()]), allowed_import: ImportExportPolicy::NoFiltering, @@ -286,7 +287,6 @@ fn test_port_config() { multi_exit_discriminator: None, remote_asn: None, vlan_id: Some(400), - router_lifetime: 0, }, ], groups: Vec::new(), diff --git a/oxide.json b/oxide.json index 72d5a2e5..aad8895b 100644 --- a/oxide.json +++ b/oxide.json @@ -7,7 +7,7 @@ "url": "https://oxide.computer", "email": "api@oxide.computer" }, - "version": "2026032500.0.0" + "version": "2026041900.0.0" }, "paths": { "/device/auth": { @@ -17362,14 +17362,16 @@ }, "BgpMessageHistory": {}, "BgpPeer": { - "description": "A BGP peer configuration for an interface. Includes the set of announcements that will be advertised to the peer identified by `addr`. The `bgp_config` parameter is a reference to global BGP parameters. The `interface_name` indicates what interface the peer should be contacted on.", + "description": "A BGP peer configuration for an interface. Includes the set of announcements that will be advertised to the peer. The `bgp_config` parameter is a reference to global BGP parameters.", "type": "object", "properties": { "addr": { - "nullable": true, - "description": "The address of the host to peer with. If not provided, this is an unnumbered BGP session that will be established over the interface specified by `interface_name`.", - "type": "string", - "format": "ip" + "description": "The address of the host to peer with, or specifying the configuration of an unnumbered BGP session.", + "allOf": [ + { + "$ref": "#/components/schemas/RouterPeerType" + } + ] }, "allowed_export": { "description": "Define export policy for a peer.", @@ -17405,7 +17407,7 @@ } }, "connect_retry": { - "description": "How long to to wait between TCP connection retries (seconds).", + "description": "How long to wait between TCP connection retries (seconds).", "type": "integer", "format": "uint32", "minimum": 0 @@ -17432,14 +17434,6 @@ "format": "uint32", "minimum": 0 }, - "interface_name": { - "description": "The name of interface to peer on. This is relative to the port configuration this BGP peer configuration is a part of. For example this value could be phy0 to refer to a primary physical interface. Or it could be vlan47 to refer to a VLAN interface.", - "allOf": [ - { - "$ref": "#/components/schemas/Name" - } - ] - }, "keepalive": { "description": "How often to send keepalive requests (seconds).", "type": "integer", @@ -17479,12 +17473,6 @@ "format": "uint32", "minimum": 0 }, - "router_lifetime": { - "description": "Router lifetime in seconds for unnumbered BGP peers.", - "type": "integer", - "format": "uint16", - "minimum": 0 - }, "vlan_id": { "nullable": true, "description": "Associate a VLAN ID with a peer.", @@ -17494,6 +17482,7 @@ } }, "required": [ + "addr", "allowed_export", "allowed_import", "bgp_config", @@ -17503,9 +17492,7 @@ "enforce_first_as", "hold_time", "idle_hold_time", - "interface_name", - "keepalive", - "router_lifetime" + "keepalive" ] }, "BgpPeerConfig": { @@ -26511,6 +26498,60 @@ } ] }, + "RouterLifetimeConfig": { + "description": "Router lifetime in seconds for unnumbered BGP peers", + "type": "integer", + "format": "uint16", + "minimum": 0, + "maximum": 9000 + }, + "RouterPeerType": { + "oneOf": [ + { + "type": "object", + "properties": { + "router_lifetime": { + "description": "Router lifetime in seconds for unnumbered BGP peers.", + "allOf": [ + { + "$ref": "#/components/schemas/RouterLifetimeConfig" + } + ] + }, + "type": { + "type": "string", + "enum": [ + "unnumbered" + ] + } + }, + "required": [ + "router_lifetime", + "type" + ] + }, + { + "type": "object", + "properties": { + "ip": { + "description": "IP address for numbered BGP peers.", + "type": "string", + "format": "ip" + }, + "type": { + "type": "string", + "enum": [ + "numbered" + ] + } + }, + "required": [ + "ip", + "type" + ] + } + ] + }, "RouterRoute": { "description": "A route defines a rule that governs where traffic should be sent based on its destination.", "type": "object", diff --git a/sdk/src/generated_sdk.rs b/sdk/src/generated_sdk.rs index b4c9a31f..722a17d5 100644 --- a/sdk/src/generated_sdk.rs +++ b/sdk/src/generated_sdk.rs @@ -4560,22 +4560,19 @@ pub mod types { } /// A BGP peer configuration for an interface. Includes the set of - /// announcements that will be advertised to the peer identified by `addr`. - /// The `bgp_config` parameter is a reference to global BGP parameters. The - /// `interface_name` indicates what interface the peer should be contacted - /// on. + /// announcements that will be advertised to the peer. The `bgp_config` + /// parameter is a reference to global BGP parameters. /// ///
JSON schema /// /// ```json /// { /// "description": "A BGP peer configuration for an interface. Includes the - /// set of announcements that will be advertised to the peer identified by - /// `addr`. The `bgp_config` parameter is a reference to global BGP - /// parameters. The `interface_name` indicates what interface the peer - /// should be contacted on.", + /// set of announcements that will be advertised to the peer. The + /// `bgp_config` parameter is a reference to global BGP parameters.", /// "type": "object", /// "required": [ + /// "addr", /// "allowed_export", /// "allowed_import", /// "bgp_config", @@ -4585,20 +4582,17 @@ pub mod types { /// "enforce_first_as", /// "hold_time", /// "idle_hold_time", - /// "interface_name", - /// "keepalive", - /// "router_lifetime" + /// "keepalive" /// ], /// "properties": { /// "addr": { - /// "description": "The address of the host to peer with. If not - /// provided, this is an unnumbered BGP session that will be established - /// over the interface specified by `interface_name`.", - /// "type": [ - /// "string", - /// "null" - /// ], - /// "format": "ip" + /// "description": "The address of the host to peer with, or specifying + /// the configuration of an unnumbered BGP session.", + /// "allOf": [ + /// { + /// "$ref": "#/components/schemas/RouterPeerType" + /// } + /// ] /// }, /// "allowed_export": { /// "description": "Define export policy for a peer.", @@ -4636,7 +4630,7 @@ pub mod types { /// } /// }, /// "connect_retry": { - /// "description": "How long to to wait between TCP connection retries + /// "description": "How long to wait between TCP connection retries /// (seconds).", /// "type": "integer", /// "format": "uint32", @@ -4668,17 +4662,6 @@ pub mod types { /// "format": "uint32", /// "minimum": 0.0 /// }, - /// "interface_name": { - /// "description": "The name of interface to peer on. This is relative - /// to the port configuration this BGP peer configuration is a part of. For - /// example this value could be phy0 to refer to a primary physical - /// interface. Or it could be vlan47 to refer to a VLAN interface.", - /// "allOf": [ - /// { - /// "$ref": "#/components/schemas/Name" - /// } - /// ] - /// }, /// "keepalive": { /// "description": "How often to send keepalive requests (seconds).", /// "type": "integer", @@ -4732,13 +4715,6 @@ pub mod types { /// "format": "uint32", /// "minimum": 0.0 /// }, - /// "router_lifetime": { - /// "description": "Router lifetime in seconds for unnumbered BGP - /// peers.", - /// "type": "integer", - /// "format": "uint16", - /// "minimum": 0.0 - /// }, /// "vlan_id": { /// "description": "Associate a VLAN ID with a peer.", /// "type": [ @@ -4756,11 +4732,9 @@ pub mod types { :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, )] pub struct BgpPeer { - /// The address of the host to peer with. If not provided, this is an - /// unnumbered BGP session that will be established over the interface - /// specified by `interface_name`. - #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] - pub addr: ::std::option::Option<::std::net::IpAddr>, + /// The address of the host to peer with, or specifying the + /// configuration of an unnumbered BGP session. + pub addr: RouterPeerType, /// Define export policy for a peer. pub allowed_export: ImportExportPolicy, /// Define import policy for a peer. @@ -4770,7 +4744,7 @@ pub mod types { pub bgp_config: NameOrId, /// Include the provided communities in updates sent to the peer. pub communities: ::std::vec::Vec, - /// How long to to wait between TCP connection retries (seconds). + /// How long to wait between TCP connection retries (seconds). pub connect_retry: u32, /// How long to delay sending an open request after establishing a TCP /// session (seconds). @@ -4783,11 +4757,6 @@ pub mod types { /// How long to hold a peer in idle before attempting a new session /// (seconds). pub idle_hold_time: u32, - /// The name of interface to peer on. This is relative to the port - /// configuration this BGP peer configuration is a part of. For example - /// this value could be phy0 to refer to a primary physical interface. - /// Or it could be vlan47 to refer to a VLAN interface. - pub interface_name: Name, /// How often to send keepalive requests (seconds). pub keepalive: u32, /// Apply a local preference to routes received from this peer. @@ -4806,8 +4775,6 @@ pub mod types { /// Require that a peer has a specified ASN. #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] pub remote_asn: ::std::option::Option, - /// Router lifetime in seconds for unnumbered BGP peers. - pub router_lifetime: u16, /// Associate a VLAN ID with a peer. #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] pub vlan_id: ::std::option::Option, @@ -24346,6 +24313,143 @@ pub mod types { } } + /// Router lifetime in seconds for unnumbered BGP peers + /// + ///
JSON schema + /// + /// ```json + /// { + /// "description": "Router lifetime in seconds for unnumbered BGP peers", + /// "type": "integer", + /// "format": "uint16", + /// "maximum": 9000.0, + /// "minimum": 0.0 + /// } + /// ``` + ///
+ #[derive( + :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, + )] + #[serde(transparent)] + pub struct RouterLifetimeConfig(pub u16); + impl ::std::ops::Deref for RouterLifetimeConfig { + type Target = u16; + fn deref(&self) -> &u16 { + &self.0 + } + } + + impl ::std::convert::From for u16 { + fn from(value: RouterLifetimeConfig) -> Self { + value.0 + } + } + + impl ::std::convert::From for RouterLifetimeConfig { + fn from(value: u16) -> Self { + Self(value) + } + } + + impl ::std::str::FromStr for RouterLifetimeConfig { + type Err = ::Err; + fn from_str(value: &str) -> ::std::result::Result { + Ok(Self(value.parse()?)) + } + } + + impl ::std::convert::TryFrom<&str> for RouterLifetimeConfig { + type Error = ::Err; + fn try_from(value: &str) -> ::std::result::Result { + value.parse() + } + } + + impl ::std::convert::TryFrom for RouterLifetimeConfig { + type Error = ::Err; + fn try_from(value: String) -> ::std::result::Result { + value.parse() + } + } + + impl ::std::fmt::Display for RouterLifetimeConfig { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + self.0.fmt(f) + } + } + + /// `RouterPeerType` + /// + ///
JSON schema + /// + /// ```json + /// { + /// "oneOf": [ + /// { + /// "type": "object", + /// "required": [ + /// "router_lifetime", + /// "type" + /// ], + /// "properties": { + /// "router_lifetime": { + /// "description": "Router lifetime in seconds for unnumbered BGP + /// peers.", + /// "allOf": [ + /// { + /// "$ref": "#/components/schemas/RouterLifetimeConfig" + /// } + /// ] + /// }, + /// "type": { + /// "type": "string", + /// "enum": [ + /// "unnumbered" + /// ] + /// } + /// } + /// }, + /// { + /// "type": "object", + /// "required": [ + /// "ip", + /// "type" + /// ], + /// "properties": { + /// "ip": { + /// "description": "IP address for numbered BGP peers.", + /// "type": "string", + /// "format": "ip" + /// }, + /// "type": { + /// "type": "string", + /// "enum": [ + /// "numbered" + /// ] + /// } + /// } + /// } + /// ] + /// } + /// ``` + ///
+ #[derive( + :: serde :: Deserialize, :: serde :: Serialize, Clone, Debug, schemars :: JsonSchema, + )] + #[serde(tag = "type")] + pub enum RouterPeerType { + #[serde(rename = "unnumbered")] + Unnumbered { + /// Router lifetime in seconds for unnumbered BGP peers. + router_lifetime: RouterLifetimeConfig, + }, + #[serde(rename = "numbered")] + Numbered { + /// IP address for numbered BGP peers. + ip: ::std::net::IpAddr, + }, + } + /// A route defines a rule that governs where traffic should be sent based /// on its destination. /// @@ -40449,10 +40553,7 @@ pub mod types { #[derive(Clone, Debug)] pub struct BgpPeer { - addr: ::std::result::Result< - ::std::option::Option<::std::net::IpAddr>, - ::std::string::String, - >, + addr: ::std::result::Result, allowed_export: ::std::result::Result, allowed_import: ::std::result::Result, bgp_config: ::std::result::Result, @@ -40462,7 +40563,6 @@ pub mod types { enforce_first_as: ::std::result::Result, hold_time: ::std::result::Result, idle_hold_time: ::std::result::Result, - interface_name: ::std::result::Result, keepalive: ::std::result::Result, local_pref: ::std::result::Result<::std::option::Option, ::std::string::String>, md5_auth_key: ::std::result::Result< @@ -40473,14 +40573,13 @@ pub mod types { multi_exit_discriminator: ::std::result::Result<::std::option::Option, ::std::string::String>, remote_asn: ::std::result::Result<::std::option::Option, ::std::string::String>, - router_lifetime: ::std::result::Result, vlan_id: ::std::result::Result<::std::option::Option, ::std::string::String>, } impl ::std::default::Default for BgpPeer { fn default() -> Self { Self { - addr: Ok(Default::default()), + addr: Err("no value supplied for addr".to_string()), allowed_export: Err("no value supplied for allowed_export".to_string()), allowed_import: Err("no value supplied for allowed_import".to_string()), bgp_config: Err("no value supplied for bgp_config".to_string()), @@ -40490,14 +40589,12 @@ pub mod types { enforce_first_as: Err("no value supplied for enforce_first_as".to_string()), hold_time: Err("no value supplied for hold_time".to_string()), idle_hold_time: Err("no value supplied for idle_hold_time".to_string()), - interface_name: Err("no value supplied for interface_name".to_string()), keepalive: Err("no value supplied for keepalive".to_string()), local_pref: Ok(Default::default()), md5_auth_key: Ok(Default::default()), min_ttl: Ok(Default::default()), multi_exit_discriminator: Ok(Default::default()), remote_asn: Ok(Default::default()), - router_lifetime: Err("no value supplied for router_lifetime".to_string()), vlan_id: Ok(Default::default()), } } @@ -40506,7 +40603,7 @@ pub mod types { impl BgpPeer { pub fn addr(mut self, value: T) -> Self where - T: ::std::convert::TryInto<::std::option::Option<::std::net::IpAddr>>, + T: ::std::convert::TryInto, T::Error: ::std::fmt::Display, { self.addr = value @@ -40604,16 +40701,6 @@ pub mod types { }); self } - pub fn interface_name(mut self, value: T) -> Self - where - T: ::std::convert::TryInto, - T::Error: ::std::fmt::Display, - { - self.interface_name = value.try_into().map_err(|e| { - format!("error converting supplied value for interface_name: {e}") - }); - self - } pub fn keepalive(mut self, value: T) -> Self where T: ::std::convert::TryInto, @@ -40674,16 +40761,6 @@ pub mod types { .map_err(|e| format!("error converting supplied value for remote_asn: {e}")); self } - pub fn router_lifetime(mut self, value: T) -> Self - where - T: ::std::convert::TryInto, - T::Error: ::std::fmt::Display, - { - self.router_lifetime = value.try_into().map_err(|e| { - format!("error converting supplied value for router_lifetime: {e}") - }); - self - } pub fn vlan_id(mut self, value: T) -> Self where T: ::std::convert::TryInto<::std::option::Option>, @@ -40712,14 +40789,12 @@ pub mod types { enforce_first_as: value.enforce_first_as?, hold_time: value.hold_time?, idle_hold_time: value.idle_hold_time?, - interface_name: value.interface_name?, keepalive: value.keepalive?, local_pref: value.local_pref?, md5_auth_key: value.md5_auth_key?, min_ttl: value.min_ttl?, multi_exit_discriminator: value.multi_exit_discriminator?, remote_asn: value.remote_asn?, - router_lifetime: value.router_lifetime?, vlan_id: value.vlan_id?, }) } @@ -40738,14 +40813,12 @@ pub mod types { enforce_first_as: Ok(value.enforce_first_as), hold_time: Ok(value.hold_time), idle_hold_time: Ok(value.idle_hold_time), - interface_name: Ok(value.interface_name), keepalive: Ok(value.keepalive), local_pref: Ok(value.local_pref), md5_auth_key: Ok(value.md5_auth_key), min_ttl: Ok(value.min_ttl), multi_exit_discriminator: Ok(value.multi_exit_discriminator), remote_asn: Ok(value.remote_asn), - router_lifetime: Ok(value.router_lifetime), vlan_id: Ok(value.vlan_id), } } @@ -65703,7 +65776,7 @@ pub mod types { /// /// API for interacting with the Oxide control plane /// -/// Version: 2026032500.0.0 +/// Version: 2026041900.0.0 pub struct Client { pub(crate) baseurl: String, pub(crate) client: reqwest::Client, @@ -65744,7 +65817,7 @@ impl Client { impl ClientInfo<()> for Client { fn api_version() -> &'static str { - "2026032500.0.0" + "2026041900.0.0" } fn baseurl(&self) -> &str {