From 1dcd87090041ed6d49cc5a0a1652e7cb048286ac Mon Sep 17 00:00:00 2001 From: Rain Date: Tue, 13 Jan 2026 18:27:19 +0000 Subject: [PATCH] [spr] initial version Created using spr 1.3.6-beta.1 --- Cargo.lock | 10 +- Cargo.toml | 2 + lldpd-api/Cargo.toml | 2 +- lldpd-api/src/lib.rs | 125 ++++++------------ lldpd-client/Cargo.toml | 1 + lldpd-types/Cargo.toml | 6 +- lldpd-types/src/build_info.rs | 19 +-- lldpd-types/src/interfaces.rs | 26 +--- lldpd-types/src/neighbor.rs | 53 +------- lldpd-types/src/system_info.rs | 78 +---------- lldpd-types/versions/Cargo.toml | 12 ++ lldpd-types/versions/src/impls/mod.rs | 10 ++ lldpd-types/versions/src/impls/neighbor.rs | 18 +++ lldpd-types/versions/src/impls/system_info.rs | 64 +++++++++ .../versions/src/initial/build_info.rs | 24 ++++ .../versions/src/initial/interfaces.rs | 56 ++++++++ lldpd-types/versions/src/initial/mod.rs | 14 ++ lldpd-types/versions/src/initial/neighbor.rs | 56 ++++++++ .../versions/src/initial/system_info.rs | 37 ++++++ lldpd-types/versions/src/latest.rs | 31 +++++ lldpd-types/versions/src/lib.rs | 37 ++++++ lldpd/src/api_server.rs | 10 +- 22 files changed, 426 insertions(+), 265 deletions(-) create mode 100644 lldpd-types/versions/Cargo.toml create mode 100644 lldpd-types/versions/src/impls/mod.rs create mode 100644 lldpd-types/versions/src/impls/neighbor.rs create mode 100644 lldpd-types/versions/src/impls/system_info.rs create mode 100644 lldpd-types/versions/src/initial/build_info.rs create mode 100644 lldpd-types/versions/src/initial/interfaces.rs create mode 100644 lldpd-types/versions/src/initial/mod.rs create mode 100644 lldpd-types/versions/src/initial/neighbor.rs create mode 100644 lldpd-types/versions/src/initial/system_info.rs create mode 100644 lldpd-types/versions/src/latest.rs create mode 100644 lldpd-types/versions/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 2f85186..fed97d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1890,7 +1890,7 @@ version = "0.1.0" dependencies = [ "dropshot", "dropshot-api-manager-types", - "lldpd-types", + "lldpd-types-versions", "protocol 0.1.0", "schemars", "serde", @@ -1903,6 +1903,7 @@ dependencies = [ "chrono", "futures", "lldpd-common", + "lldpd-types-versions", "progenitor", "protocol 0.1.0", "reqwest", @@ -1932,6 +1933,13 @@ dependencies = [ [[package]] name = "lldpd-types" version = "0.1.0" +dependencies = [ + "lldpd-types-versions", +] + +[[package]] +name = "lldpd-types-versions" +version = "0.1.0" dependencies = [ "chrono", "protocol 0.1.0", diff --git a/Cargo.toml b/Cargo.toml index 746fc31..c6bcfd1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "lldpd-client", "lldpd-common", "lldpd-types", + "lldpd-types/versions", "lldpd", "protocol", "xtask", @@ -21,6 +22,7 @@ lldpd-api = { path = "lldpd-api" } lldpd-client = { path = "lldpd-client" } lldpd-common = { path = "lldpd-common" } lldpd-types = { path = "lldpd-types" } +lldpd-types-versions = { path = "lldpd-types/versions" } protocol = { path = "protocol" } # oxide dependencies from github diff --git a/lldpd-api/Cargo.toml b/lldpd-api/Cargo.toml index fee92ef..13f15d7 100644 --- a/lldpd-api/Cargo.toml +++ b/lldpd-api/Cargo.toml @@ -7,7 +7,7 @@ license = "MPL-2.0" [dependencies] dropshot.workspace = true dropshot-api-manager-types.workspace = true -lldpd-types.workspace = true +lldpd-types-versions.workspace = true protocol.workspace = true schemars.workspace = true serde.workspace = true diff --git a/lldpd-api/src/lib.rs b/lldpd-api/src/lib.rs index b13884a..63427b2 100644 --- a/lldpd-api/src/lib.rs +++ b/lldpd-api/src/lib.rs @@ -4,22 +4,14 @@ // // Copyright 2025 Oxide Computer Company -use std::net::IpAddr; - use dropshot::{ EmptyScanParams, HttpError, HttpResponseCreated, HttpResponseDeleted, HttpResponseOk, HttpResponseUpdatedNoContent, PaginationParams, Path, Query, RequestContext, ResultsPage, TypedBody, }; use dropshot_api_manager_types::api_versions; -use lldpd_types::{ - build_info::BuildInfo, - interfaces::{Interface, InterfaceAdd}, - neighbor::{Neighbor, NeighborId}, -}; -use protocol::types::{ChassisId, PortId, SystemCapabilities}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; +use lldpd_types_versions::latest; +use protocol::types::{ChassisId, PortId}; api_versions!([ // WHEN CHANGING THE API (part 1 of 2): @@ -109,7 +101,7 @@ pub trait LldpdApi { }] async fn sys_add_system_capability( rqctx: RequestContext, - path: Path, + path: Path, ) -> Result; /// Remove a capability from the set of those advertised on all interfaces @@ -119,7 +111,7 @@ pub trait LldpdApi { }] async fn sys_del_system_capability( rqctx: RequestContext, - path: Path, + path: Path, ) -> Result; /// Add a capability to the set of those advertised as enabled on all interfaces @@ -129,7 +121,7 @@ pub trait LldpdApi { }] async fn sys_enable_system_capability( rqctx: RequestContext, - path: Path, + path: Path, ) -> Result; /// Remove a capability from the set of those advertised as enabled on all interfaces @@ -139,7 +131,7 @@ pub trait LldpdApi { }] async fn sys_disable_system_capability( rqctx: RequestContext, - path: Path, + path: Path, ) -> Result; /// Add a management address to the set of those advertised on all interfaces @@ -149,7 +141,7 @@ pub trait LldpdApi { }] async fn sys_add_management_addr( rqctx: RequestContext, - path: Path, + path: Path, ) -> Result; /// Remove a management address from the set of those advertised on all interfaces @@ -159,7 +151,7 @@ pub trait LldpdApi { }] async fn sys_del_management_addr( rqctx: RequestContext, - path: Path, + path: Path, ) -> Result; /// Remove all management addresses from the set of those advertised on all @@ -178,8 +170,8 @@ pub trait LldpdApi { }] async fn interface_add( rqctx: RequestContext, - path: Path, - params: TypedBody, + path: Path, + params: TypedBody, ) -> Result, HttpError>; #[endpoint { @@ -188,7 +180,7 @@ pub trait LldpdApi { }] async fn interface_del( rqctx: RequestContext, - path: Path, + path: Path, ) -> Result; #[endpoint { @@ -197,8 +189,8 @@ pub trait LldpdApi { }] async fn interface_get( rqctx: RequestContext, - path: Path, - ) -> Result, HttpError>; + path: Path, + ) -> Result, HttpError>; #[endpoint { method = GET, @@ -206,7 +198,7 @@ pub trait LldpdApi { }] async fn interface_list( rqctx: RequestContext, - ) -> Result>, HttpError>; + ) -> Result>, HttpError>; #[endpoint { method = POST, @@ -214,7 +206,7 @@ pub trait LldpdApi { }] async fn interface_set_disabled( rqctx: RequestContext, - path: Path, + path: Path, body: TypedBody, ) -> Result; @@ -224,7 +216,7 @@ pub trait LldpdApi { }] async fn interface_set_chassis_id( rqctx: RequestContext, - path: Path, + path: Path, body: TypedBody, ) -> Result; @@ -234,7 +226,7 @@ pub trait LldpdApi { }] async fn interface_del_chassis_id( rqctx: RequestContext, - path: Path, + path: Path, ) -> Result; #[endpoint { @@ -243,7 +235,7 @@ pub trait LldpdApi { }] async fn interface_set_port_id( rqctx: RequestContext, - path: Path, + path: Path, body: TypedBody, ) -> Result; @@ -253,7 +245,7 @@ pub trait LldpdApi { }] async fn interface_set_port_description( rqctx: RequestContext, - path: Path, + path: Path, body: TypedBody, ) -> Result; @@ -263,7 +255,7 @@ pub trait LldpdApi { }] async fn interface_del_port_description( rqctx: RequestContext, - path: Path, + path: Path, ) -> Result; #[endpoint { @@ -272,7 +264,7 @@ pub trait LldpdApi { }] async fn interface_set_system_name( rqctx: RequestContext, - path: Path, + path: Path, body: TypedBody, ) -> Result; @@ -282,7 +274,7 @@ pub trait LldpdApi { }] async fn interface_del_system_name( rqctx: RequestContext, - path: Path, + path: Path, ) -> Result; #[endpoint { @@ -291,7 +283,7 @@ pub trait LldpdApi { }] async fn interface_set_system_description( rqctx: RequestContext, - path: Path, + path: Path, body: TypedBody, ) -> Result; #[endpoint { @@ -300,7 +292,7 @@ pub trait LldpdApi { }] async fn interface_del_system_description( rqctx: RequestContext, - path: Path, + path: Path, ) -> Result; #[endpoint { @@ -309,7 +301,7 @@ pub trait LldpdApi { }] async fn interface_add_system_capability( rqctx: RequestContext, - path: Path, + path: Path, ) -> Result; #[endpoint { @@ -318,7 +310,7 @@ pub trait LldpdApi { }] async fn interface_del_system_capability( rqctx: RequestContext, - path: Path, + path: Path, ) -> Result; #[endpoint { @@ -327,7 +319,7 @@ pub trait LldpdApi { }] async fn interface_enable_system_capability( rqctx: RequestContext, - path: Path, + path: Path, ) -> Result; #[endpoint { @@ -336,7 +328,7 @@ pub trait LldpdApi { }] async fn interface_disable_system_capability( rqctx: RequestContext, - path: Path, + path: Path, ) -> Result; #[endpoint { @@ -345,7 +337,7 @@ pub trait LldpdApi { }] async fn interface_add_management_addr( rqctx: RequestContext, - path: Path, + path: Path, ) -> Result; #[endpoint { @@ -354,7 +346,7 @@ pub trait LldpdApi { }] async fn interface_del_management_addr( rqctx: RequestContext, - path: Path, + path: Path, ) -> Result; #[endpoint { @@ -363,7 +355,7 @@ pub trait LldpdApi { }] async fn interface_clear_management_addr( rqctx: RequestContext, - path: Path, + path: Path, ) -> Result; /// Return a list of the active neighbors @@ -373,9 +365,14 @@ pub trait LldpdApi { }] async fn get_neighbors( rqctx: RequestContext, - path: Path, - query: Query>, - ) -> Result>, HttpError>; + path: Path, + query: Query< + PaginationParams, + >, + ) -> Result< + HttpResponseOk>, + HttpError, + >; /// Return detailed build information about the `dpd` server itself. #[endpoint { @@ -384,47 +381,5 @@ pub trait LldpdApi { }] async fn build_info( _rqctx: RequestContext, - ) -> Result, HttpError>; -} - -#[derive(Deserialize, Serialize, JsonSchema)] -pub struct SystemCapabilityPathParams { - pub capability: SystemCapabilities, -} - -#[derive(Deserialize, Serialize, JsonSchema)] -pub struct SystemAddressPathParams { - pub address: IpAddr, -} - -#[derive(Deserialize, Serialize, JsonSchema)] -pub struct InterfacePathParams { - /// The switch port on which to operate. - pub iface: String, -} - -#[derive(Deserialize, Serialize, JsonSchema)] -pub struct InterfaceCapabilityPathParams { - /// The switch port on which to operate. - pub iface: String, - pub capability: SystemCapabilities, -} - -#[derive(Deserialize, Serialize, JsonSchema)] -pub struct InterfaceAddressPathParams { - /// The switch port on which to operate. - pub iface: String, - /// Management Address to advertise on this port - // TODO-completeness: this should allow non-IP addresses to be specified (as - // per the standard) and should include an optional interface number. - pub address: IpAddr, -} - -/** - * Represents a cursor into a paginated request for the contents of the neighbor - * list. - */ -#[derive(Deserialize, Serialize, JsonSchema)] -pub struct NeighborToken { - pub id: NeighborId, + ) -> Result, HttpError>; } diff --git a/lldpd-client/Cargo.toml b/lldpd-client/Cargo.toml index 1adca1a..17df22c 100644 --- a/lldpd-client/Cargo.toml +++ b/lldpd-client/Cargo.toml @@ -8,6 +8,7 @@ description = "Client library for the Oxide LLDP daemon" chrono.workspace = true futures.workspace = true lldpd-common.workspace = true +lldpd-types-versions.workspace = true protocol.workspace = true progenitor.workspace = true reqwest.workspace = true diff --git a/lldpd-types/Cargo.toml b/lldpd-types/Cargo.toml index 6e2ca82..91ce9a3 100644 --- a/lldpd-types/Cargo.toml +++ b/lldpd-types/Cargo.toml @@ -5,8 +5,4 @@ edition = "2021" license = "MPL-2.0" [dependencies] -chrono.workspace = true -protocol.workspace = true -schemars = { workspace = true, features = ["chrono"] } -serde.workspace = true -uuid.workspace = true +lldpd-types-versions.workspace = true diff --git a/lldpd-types/src/build_info.rs b/lldpd-types/src/build_info.rs index 7426f60..0bf3ce3 100644 --- a/lldpd-types/src/build_info.rs +++ b/lldpd-types/src/build_info.rs @@ -4,21 +4,4 @@ // // Copyright 2025 Oxide Computer Company -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; - -/// Detailed build information about `lldpd`. -#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] -pub struct BuildInfo { - pub version: String, - pub git_sha: String, - pub git_commit_timestamp: String, - pub git_branch: String, - pub rustc_semver: String, - pub rustc_channel: String, - pub rustc_host_triple: String, - pub rustc_commit_sha: String, - pub cargo_triple: String, - pub debug: bool, - pub opt_level: u8, -} +pub use lldpd_types_versions::latest::build_info::*; diff --git a/lldpd-types/src/interfaces.rs b/lldpd-types/src/interfaces.rs index d0df85c..ff0f04a 100644 --- a/lldpd-types/src/interfaces.rs +++ b/lldpd-types/src/interfaces.rs @@ -4,28 +4,4 @@ // // Copyright 2025 Oxide Computer Company -use protocol::types::{ChassisId, PortId}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; - -use crate::system_info::SystemInfo; - -/// A local interface on which we are listening for, and dispatching, LLDPDUs -#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] -pub struct Interface { - pub port: String, - pub iface: String, - pub disabled: bool, - pub system_info: SystemInfo, -} - -/// Optional arguments when adding an interface to LLDPD. Any argument left -/// unspecified will be assigned the default values for this system. -#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] -pub struct InterfaceAdd { - pub chassis_id: Option, - pub port_id: Option, - pub system_name: Option, - pub system_description: Option, - pub port_description: Option, -} +pub use lldpd_types_versions::latest::interfaces::*; diff --git a/lldpd-types/src/neighbor.rs b/lldpd-types/src/neighbor.rs index c2b242f..54ea150 100644 --- a/lldpd-types/src/neighbor.rs +++ b/lldpd-types/src/neighbor.rs @@ -4,55 +4,4 @@ // // Copyright 2025 Oxide Computer Company -use chrono::{DateTime, Utc}; -use protocol::types::{ChassisId, Lldpdu, PortId}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; - -use crate::system_info::SystemInfo; - -#[derive( - Debug, - Clone, - Deserialize, - JsonSchema, - Serialize, - Hash, - PartialEq, - Eq, - PartialOrd, - Ord, -)] -pub struct NeighborId { - pub chassis_id: ChassisId, - pub port_id: PortId, -} - -impl NeighborId { - pub fn new(lldpdu: &Lldpdu) -> Self { - NeighborId { - chassis_id: lldpdu.chassis_id.clone(), - port_id: lldpdu.port_id.clone(), - } - } -} - -/// A remote system that has been discovered on one of our configured interfaces -#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] -pub struct Neighbor { - /// The port on which the neighbor was seen - pub port: String, - /// An ID that uniquely identifies the neighbor. Note: this ID is assigned - /// when we first see a neighbor we are currently tracking. If a neighbor - /// goes offline long enough to be forgotten, it will be assigned a new ID - /// if and when it comes back online. - pub id: uuid::Uuid, - /// When was the first beacon received from this neighbor. - pub first_seen: DateTime, - /// When was the latest beacon received from this neighbor. - pub last_seen: DateTime, - /// When was the last time this neighbor's beaconed LLDPDU contents changed. - pub last_changed: DateTime, - /// Contents of the neighbor's LLDPDU beacon. - pub system_info: SystemInfo, -} +pub use lldpd_types_versions::latest::neighbor::*; diff --git a/lldpd-types/src/system_info.rs b/lldpd-types/src/system_info.rs index 6cf9ed9..9e5735b 100644 --- a/lldpd-types/src/system_info.rs +++ b/lldpd-types/src/system_info.rs @@ -1,81 +1,7 @@ // This Source Code Form is subject to the terms of the Mozilla Public // 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 -use std::fmt; - -use protocol::types::{ - ChassisId, Lldpdu, ManagementAddress, PortId, SystemCapabilities, -}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] -pub struct SystemInfo { - pub chassis_id: ChassisId, - pub port_id: PortId, - pub ttl: u16, - pub port_description: Option, - pub system_name: Option, - pub system_description: Option, - pub capabilities_available: Vec, - pub capabilities_enabled: Vec, - pub management_addresses: Vec, - pub organizationally_specific: Vec, -} - -impl fmt::Display for SystemInfo { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - writeln!(f, "Chassis ID: {}", self.chassis_id)?; - writeln!(f, "Port ID: {}", self.port_id)?; - writeln!(f, "Time To Live: {} seconds", self.ttl)?; - if let Some(pd) = &self.port_description { - writeln!(f, "Port description: {pd}")?; - } - if let Some(sn) = &self.system_name { - writeln!(f, "System name: {sn}")?; - } - if let Some(sd) = &self.system_description { - writeln!(f, "System description: {sd}")?; - } - // system_capabilities: Option<(BTreeSet, BTreeSet)>, - for ma in &self.management_addresses { - writeln!(f, "Management address: {ma}")?; - } - for os in &self.organizationally_specific { - writeln!(f, "Organizationally Specific: {os}")?; - } - Ok(()) - } -} - -impl From<&Lldpdu> for SystemInfo { - fn from(lldpdu: &Lldpdu) -> SystemInfo { - let (capabilities_available, capabilities_enabled) = - match &lldpdu.system_capabilities { - Some((a, e)) => { - (a.iter().cloned().collect(), e.iter().cloned().collect()) - } - None => (Vec::new(), Vec::new()), - }; - - SystemInfo { - chassis_id: lldpdu.chassis_id.clone(), - port_id: lldpdu.port_id.clone(), - ttl: lldpdu.ttl, - port_description: lldpdu.port_description.clone(), - system_name: lldpdu.system_name.clone(), - system_description: lldpdu.system_description.clone(), - capabilities_available, - capabilities_enabled, - management_addresses: lldpdu.management_addresses.to_vec(), - organizationally_specific: lldpdu - .organizationally_specific - .iter() - .map(|os| os.to_string()) - .collect(), - } - } -} +pub use lldpd_types_versions::latest::system_info::*; diff --git a/lldpd-types/versions/Cargo.toml b/lldpd-types/versions/Cargo.toml new file mode 100644 index 0000000..7bc5ab8 --- /dev/null +++ b/lldpd-types/versions/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "lldpd-types-versions" +version = "0.1.0" +edition = "2021" +license = "MPL-2.0" + +[dependencies] +chrono.workspace = true +protocol.workspace = true +schemars = { workspace = true, features = ["chrono"] } +serde.workspace = true +uuid.workspace = true diff --git a/lldpd-types/versions/src/impls/mod.rs b/lldpd-types/versions/src/impls/mod.rs new file mode 100644 index 0000000..c791c15 --- /dev/null +++ b/lldpd-types/versions/src/impls/mod.rs @@ -0,0 +1,10 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// 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 + +//! Functional code for the latest versions of types. + +mod neighbor; +mod system_info; diff --git a/lldpd-types/versions/src/impls/neighbor.rs b/lldpd-types/versions/src/impls/neighbor.rs new file mode 100644 index 0000000..0eb0423 --- /dev/null +++ b/lldpd-types/versions/src/impls/neighbor.rs @@ -0,0 +1,18 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// 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 + +use protocol::types::Lldpdu; + +use crate::latest::neighbor::NeighborId; + +impl NeighborId { + pub fn new(lldpdu: &Lldpdu) -> Self { + NeighborId { + chassis_id: lldpdu.chassis_id.clone(), + port_id: lldpdu.port_id.clone(), + } + } +} diff --git a/lldpd-types/versions/src/impls/system_info.rs b/lldpd-types/versions/src/impls/system_info.rs new file mode 100644 index 0000000..8b297b5 --- /dev/null +++ b/lldpd-types/versions/src/impls/system_info.rs @@ -0,0 +1,64 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// 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 + +use std::fmt; + +use protocol::types::Lldpdu; + +use crate::latest::system_info::SystemInfo; + +impl fmt::Display for SystemInfo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + writeln!(f, "Chassis ID: {}", self.chassis_id)?; + writeln!(f, "Port ID: {}", self.port_id)?; + writeln!(f, "Time To Live: {} seconds", self.ttl)?; + if let Some(pd) = &self.port_description { + writeln!(f, "Port description: {pd}")?; + } + if let Some(sn) = &self.system_name { + writeln!(f, "System name: {sn}")?; + } + if let Some(sd) = &self.system_description { + writeln!(f, "System description: {sd}")?; + } + for ma in &self.management_addresses { + writeln!(f, "Management address: {ma}")?; + } + for os in &self.organizationally_specific { + writeln!(f, "Organizationally Specific: {os}")?; + } + Ok(()) + } +} + +impl From<&Lldpdu> for SystemInfo { + fn from(lldpdu: &Lldpdu) -> SystemInfo { + let (capabilities_available, capabilities_enabled) = + match &lldpdu.system_capabilities { + Some((a, e)) => { + (a.iter().cloned().collect(), e.iter().cloned().collect()) + } + None => (Vec::new(), Vec::new()), + }; + + SystemInfo { + chassis_id: lldpdu.chassis_id.clone(), + port_id: lldpdu.port_id.clone(), + ttl: lldpdu.ttl, + port_description: lldpdu.port_description.clone(), + system_name: lldpdu.system_name.clone(), + system_description: lldpdu.system_description.clone(), + capabilities_available, + capabilities_enabled, + management_addresses: lldpdu.management_addresses.to_vec(), + organizationally_specific: lldpdu + .organizationally_specific + .iter() + .map(|os| os.to_string()) + .collect(), + } + } +} diff --git a/lldpd-types/versions/src/initial/build_info.rs b/lldpd-types/versions/src/initial/build_info.rs new file mode 100644 index 0000000..7426f60 --- /dev/null +++ b/lldpd-types/versions/src/initial/build_info.rs @@ -0,0 +1,24 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// 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 + +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +/// Detailed build information about `lldpd`. +#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] +pub struct BuildInfo { + pub version: String, + pub git_sha: String, + pub git_commit_timestamp: String, + pub git_branch: String, + pub rustc_semver: String, + pub rustc_channel: String, + pub rustc_host_triple: String, + pub rustc_commit_sha: String, + pub cargo_triple: String, + pub debug: bool, + pub opt_level: u8, +} diff --git a/lldpd-types/versions/src/initial/interfaces.rs b/lldpd-types/versions/src/initial/interfaces.rs new file mode 100644 index 0000000..081a254 --- /dev/null +++ b/lldpd-types/versions/src/initial/interfaces.rs @@ -0,0 +1,56 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// 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 + +use std::net::IpAddr; + +use protocol::types::{ChassisId, PortId, SystemCapabilities}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use super::system_info::SystemInfo; + +#[derive(Deserialize, Serialize, JsonSchema)] +pub struct InterfacePathParams { + /// The switch port on which to operate. + pub iface: String, +} + +#[derive(Deserialize, Serialize, JsonSchema)] +pub struct InterfaceCapabilityPathParams { + /// The switch port on which to operate. + pub iface: String, + pub capability: SystemCapabilities, +} + +#[derive(Deserialize, Serialize, JsonSchema)] +pub struct InterfaceAddressPathParams { + /// The switch port on which to operate. + pub iface: String, + /// Management Address to advertise on this port + // TODO-completeness: this should allow non-IP addresses to be specified (as + // per the standard) and should include an optional interface number. + pub address: IpAddr, +} + +/// A local interface on which we are listening for, and dispatching, LLDPDUs +#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] +pub struct Interface { + pub port: String, + pub iface: String, + pub disabled: bool, + pub system_info: SystemInfo, +} + +/// Optional arguments when adding an interface to LLDPD. Any argument left +/// unspecified will be assigned the default values for this system. +#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] +pub struct InterfaceAdd { + pub chassis_id: Option, + pub port_id: Option, + pub system_name: Option, + pub system_description: Option, + pub port_description: Option, +} diff --git a/lldpd-types/versions/src/initial/mod.rs b/lldpd-types/versions/src/initial/mod.rs new file mode 100644 index 0000000..bb3d74f --- /dev/null +++ b/lldpd-types/versions/src/initial/mod.rs @@ -0,0 +1,14 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// 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 + +//! Version `INITIAL` of the LLDP daemon API. +//! +//! This is the first version of the API. + +pub mod build_info; +pub mod interfaces; +pub mod neighbor; +pub mod system_info; diff --git a/lldpd-types/versions/src/initial/neighbor.rs b/lldpd-types/versions/src/initial/neighbor.rs new file mode 100644 index 0000000..e321066 --- /dev/null +++ b/lldpd-types/versions/src/initial/neighbor.rs @@ -0,0 +1,56 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// 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 + +use chrono::{DateTime, Utc}; +use protocol::types::{ChassisId, PortId}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use super::system_info::SystemInfo; + +/// Represents a cursor into a paginated request for the contents of the neighbor +/// list. +#[derive(Deserialize, Serialize, JsonSchema)] +pub struct NeighborToken { + pub id: NeighborId, +} + +#[derive( + Debug, + Clone, + Deserialize, + JsonSchema, + Serialize, + Hash, + PartialEq, + Eq, + PartialOrd, + Ord, +)] +pub struct NeighborId { + pub chassis_id: ChassisId, + pub port_id: PortId, +} + +/// A remote system that has been discovered on one of our configured interfaces +#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] +pub struct Neighbor { + /// The port on which the neighbor was seen + pub port: String, + /// An ID that uniquely identifies the neighbor. Note: this ID is assigned + /// when we first see a neighbor we are currently tracking. If a neighbor + /// goes offline long enough to be forgotten, it will be assigned a new ID + /// if and when it comes back online. + pub id: uuid::Uuid, + /// When was the first beacon received from this neighbor. + pub first_seen: DateTime, + /// When was the latest beacon received from this neighbor. + pub last_seen: DateTime, + /// When was the last time this neighbor's beaconed LLDPDU contents changed. + pub last_changed: DateTime, + /// Contents of the neighbor's LLDPDU beacon. + pub system_info: SystemInfo, +} diff --git a/lldpd-types/versions/src/initial/system_info.rs b/lldpd-types/versions/src/initial/system_info.rs new file mode 100644 index 0000000..35b4ca7 --- /dev/null +++ b/lldpd-types/versions/src/initial/system_info.rs @@ -0,0 +1,37 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// 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 + +use std::net::IpAddr; + +use protocol::types::{ + ChassisId, ManagementAddress, PortId, SystemCapabilities, +}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize, JsonSchema)] +pub struct SystemCapabilityPathParams { + pub capability: SystemCapabilities, +} + +#[derive(Deserialize, Serialize, JsonSchema)] +pub struct SystemAddressPathParams { + pub address: IpAddr, +} + +#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] +pub struct SystemInfo { + pub chassis_id: ChassisId, + pub port_id: PortId, + pub ttl: u16, + pub port_description: Option, + pub system_name: Option, + pub system_description: Option, + pub capabilities_available: Vec, + pub capabilities_enabled: Vec, + pub management_addresses: Vec, + pub organizationally_specific: Vec, +} diff --git a/lldpd-types/versions/src/latest.rs b/lldpd-types/versions/src/latest.rs new file mode 100644 index 0000000..eb686b9 --- /dev/null +++ b/lldpd-types/versions/src/latest.rs @@ -0,0 +1,31 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// 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 + +//! Re-exports the latest versions of each type. + +pub mod build_info { + pub use crate::v1::build_info::BuildInfo; +} + +pub mod interfaces { + pub use crate::v1::interfaces::Interface; + pub use crate::v1::interfaces::InterfaceAdd; + pub use crate::v1::interfaces::InterfaceAddressPathParams; + pub use crate::v1::interfaces::InterfaceCapabilityPathParams; + pub use crate::v1::interfaces::InterfacePathParams; +} + +pub mod neighbor { + pub use crate::v1::neighbor::Neighbor; + pub use crate::v1::neighbor::NeighborId; + pub use crate::v1::neighbor::NeighborToken; +} + +pub mod system_info { + pub use crate::v1::system_info::SystemAddressPathParams; + pub use crate::v1::system_info::SystemCapabilityPathParams; + pub use crate::v1::system_info::SystemInfo; +} diff --git a/lldpd-types/versions/src/lib.rs b/lldpd-types/versions/src/lib.rs new file mode 100644 index 0000000..59f4d81 --- /dev/null +++ b/lldpd-types/versions/src/lib.rs @@ -0,0 +1,37 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// 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 + +//! Versioned types for the LLDP daemon API. +//! +//! # Adding a new API version +//! +//! When adding a new API version N with added or changed types: +//! +//! 1. Create /mod.rs, where is the lowercase +//! form of the new version's identifier, as defined in the API trait's +//! `api_versions!` macro. +//! +//! 2. Add to the end of this list: +//! +//! ```rust,ignore +//! #[path = "/mod.rs"] +//! pub mod vN; +//! ``` +//! +//! 3. Add your types to the new module, mirroring the module structure from +//! earlier versions. +//! +//! 4. Update `latest.rs` with new and updated types from the new version. +//! +//! For more information, see the [detailed guide] and [RFD 619]. +//! +//! [detailed guide]: https://github.com/oxidecomputer/dropshot-api-manager/blob/main/guides/new-version.md +//! [RFD 619]: https://rfd.shared.oxide.computer/rfd/619 + +mod impls; +pub mod latest; +#[path = "initial/mod.rs"] +pub mod v1; diff --git a/lldpd/src/api_server.rs b/lldpd/src/api_server.rs index f0c3d13..a5cbdbd 100644 --- a/lldpd/src/api_server.rs +++ b/lldpd/src/api_server.rs @@ -27,12 +27,18 @@ use dropshot::ResultsPage; use dropshot::TypedBody; use dropshot::VersionPolicy; use dropshot::WhichPage; -use lldpd_api::*; +use lldpd_api::LldpdApi; use lldpd_types::build_info::BuildInfo; use lldpd_types::interfaces::Interface; use lldpd_types::interfaces::InterfaceAdd; +use lldpd_types::interfaces::InterfaceAddressPathParams; +use lldpd_types::interfaces::InterfaceCapabilityPathParams; +use lldpd_types::interfaces::InterfacePathParams; use lldpd_types::neighbor::Neighbor; use lldpd_types::neighbor::NeighborId; +use lldpd_types::neighbor::NeighborToken; +use lldpd_types::system_info::SystemAddressPathParams; +use lldpd_types::system_info::SystemCapabilityPathParams; use slog::debug; use slog::error; use slog::info; @@ -660,7 +666,7 @@ pub async fn api_server_manager( } pub fn http_api() -> dropshot::ApiDescription> { - lldpd_api_mod::api_description::().unwrap() + lldpd_api::lldpd_api_mod::api_description::().unwrap() } #[cfg(test)]