From: Stefan Hanreich <s.hanreich@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH proxmox-ve-rs 7/9] ve-config: sdn: fabrics: add wireguard to the fabric config
Date: Thu, 19 Feb 2026 15:56:26 +0100 [thread overview]
Message-ID: <20260219145649.441418-10-s.hanreich@proxmox.com> (raw)
In-Reply-To: <20260219145649.441418-1-s.hanreich@proxmox.com>
Use the newly created WireGuard section types to add the WireGuard
variants to the existing fabrics section config enum. By adding the
new WireGuard variants, they are automatically exposed via the API
methods defined in proxmox-perl-rs and are available for the existing
CRUD endpoints in pve-network.
Originally-by: Christoph Heiss <c.heiss@proxmox.com>
Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
---
proxmox-ve-config/src/sdn/fabric/frr.rs | 1 +
proxmox-ve-config/src/sdn/fabric/mod.rs | 168 ++++++++++++++++++
.../src/sdn/fabric/section_config/fabric.rs | 25 +++
.../src/sdn/fabric/section_config/mod.rs | 58 ++++++
.../src/sdn/fabric/section_config/node.rs | 44 ++++-
5 files changed, 292 insertions(+), 4 deletions(-)
diff --git a/proxmox-ve-config/src/sdn/fabric/frr.rs b/proxmox-ve-config/src/sdn/fabric/frr.rs
index 10025b3..fc41410 100644
--- a/proxmox-ve-config/src/sdn/fabric/frr.rs
+++ b/proxmox-ve-config/src/sdn/fabric/frr.rs
@@ -232,6 +232,7 @@ pub fn build_fabric(
frr_config.protocol_routemaps.insert(protocol_routemap);
}
+ FabricEntry::WireGuard(_) => {} // not a frr fabric
}
}
Ok(())
diff --git a/proxmox-ve-config/src/sdn/fabric/mod.rs b/proxmox-ve-config/src/sdn/fabric/mod.rs
index d0add92..53ce87f 100644
--- a/proxmox-ve-config/src/sdn/fabric/mod.rs
+++ b/proxmox-ve-config/src/sdn/fabric/mod.rs
@@ -7,6 +7,7 @@ use std::marker::PhantomData;
use std::ops::Deref;
use anyhow::Error;
+use section_config::protocol::wireguard::WireGuardProperties;
use serde::{Deserialize, Serialize};
use proxmox_section_config::typed::{ApiSectionDataEntry, SectionConfigData};
@@ -28,6 +29,10 @@ use crate::sdn::fabric::section_config::protocol::ospf::{
OspfDeletableProperties, OspfNodeDeletableProperties, OspfNodeProperties,
OspfNodePropertiesUpdater, OspfProperties, OspfPropertiesUpdater,
};
+use crate::sdn::fabric::section_config::protocol::wireguard::{
+ WireGuardDeletableProperties, WireGuardNode, WireGuardNodeDeletableProperties,
+ WireGuardNodeUpdater, WireGuardPropertiesUpdater,
+};
use crate::sdn::fabric::section_config::{FabricOrNode, Section};
#[derive(thiserror::Error, Debug)]
@@ -189,6 +194,7 @@ macro_rules! impl_entry {
impl_entry!(Openfabric, OpenfabricProperties, OpenfabricNodeProperties);
impl_entry!(Ospf, OspfProperties, OspfNodeProperties);
+impl_entry!(WireGuard, WireGuardProperties, WireGuardNode);
/// All possible entries in a [`FabricConfig`].
///
@@ -198,6 +204,7 @@ impl_entry!(Ospf, OspfProperties, OspfNodeProperties);
pub enum FabricEntry {
Openfabric(Entry<OpenfabricProperties, OpenfabricNodeProperties>),
Ospf(Entry<OspfProperties, OspfNodeProperties>),
+ WireGuard(Entry<WireGuardProperties, WireGuardNode>),
}
impl FabricEntry {
@@ -209,6 +216,9 @@ impl FabricEntry {
entry.add_node(node_section)
}
(FabricEntry::Ospf(entry), Node::Ospf(node_section)) => entry.add_node(node_section),
+ (FabricEntry::WireGuard(entry), Node::WireGuard(node_section)) => {
+ entry.add_node(node_section)
+ }
_ => Err(FabricConfigError::ProtocolMismatch),
}
}
@@ -219,6 +229,7 @@ impl FabricEntry {
match self {
FabricEntry::Openfabric(entry) => entry.get_node(id),
FabricEntry::Ospf(entry) => entry.get_node(id),
+ FabricEntry::WireGuard(entry) => entry.get_node(id),
}
}
@@ -228,6 +239,7 @@ impl FabricEntry {
match self {
FabricEntry::Openfabric(entry) => entry.get_node_mut(id),
FabricEntry::Ospf(entry) => entry.get_node_mut(id),
+ FabricEntry::WireGuard(entry) => entry.get_node_mut(id),
}
}
@@ -307,6 +319,109 @@ impl FabricEntry {
Ok(())
}
+ (Node::WireGuard(node_section), NodeUpdater::WireGuard(updater)) => {
+ let NodeDataUpdater::<WireGuardNodeUpdater, WireGuardNodeDeletableProperties> {
+ ip,
+ ip6,
+ properties,
+ delete,
+ } = updater;
+
+ if let Some(ip) = ip {
+ node_section.ip = Some(ip);
+ }
+
+ if let Some(ip) = ip6 {
+ node_section.ip6 = Some(ip);
+ }
+
+ for property in &delete {
+ match property {
+ NodeDeletableProperties::Ip => node_section.ip = None,
+ NodeDeletableProperties::Ip6 => node_section.ip6 = None,
+ // handled below, since internal / external nodes have different properties
+ NodeDeletableProperties::Protocol(_) => continue,
+ }
+ }
+
+ match (node_section.properties_mut(), properties) {
+ (
+ WireGuardNode::Internal(internal_wireguard_node),
+ WireGuardNodeUpdater::Internal(internal_wireguard_node_updater),
+ ) => {
+ if let Some(interfaces) = internal_wireguard_node_updater.interfaces {
+ internal_wireguard_node.interfaces = interfaces;
+ }
+
+ if let Some(endpoint) = internal_wireguard_node_updater.endpoint {
+ internal_wireguard_node.endpoint = Some(endpoint);
+ }
+
+ if let Some(peers) = internal_wireguard_node_updater.peers {
+ internal_wireguard_node.peers = peers;
+ }
+
+ if let Some(allowed_ips) = internal_wireguard_node_updater.allowed_ips {
+ internal_wireguard_node.allowed_ips = allowed_ips;
+ }
+
+ for property in &delete {
+ match property {
+ NodeDeletableProperties::Protocol(protocol_property) => {
+ match protocol_property {
+ WireGuardNodeDeletableProperties::Interfaces => {
+ internal_wireguard_node.interfaces = Vec::new()
+ }
+ WireGuardNodeDeletableProperties::Endpoint => {
+ internal_wireguard_node.endpoint = None
+ }
+ WireGuardNodeDeletableProperties::Peers => {
+ internal_wireguard_node.peers = Vec::new()
+ }
+ WireGuardNodeDeletableProperties::AllowedIps => {
+ internal_wireguard_node.allowed_ips = Vec::new()
+ }
+ }
+ }
+ _ => continue,
+ }
+ }
+ }
+ (
+ WireGuardNode::External(external_wire_guard_node),
+ WireGuardNodeUpdater::External(external_wire_guard_node_updater),
+ ) => {
+ if let Some(endpoint) = external_wire_guard_node_updater.endpoint {
+ external_wire_guard_node.endpoint = endpoint;
+ }
+
+ if let Some(public_key) = external_wire_guard_node_updater.public_key {
+ external_wire_guard_node.public_key = public_key;
+ }
+
+ if let Some(allowed_ips) = external_wire_guard_node_updater.allowed_ips {
+ external_wire_guard_node.allowed_ips = allowed_ips;
+ }
+
+ for property in &delete {
+ match property {
+ NodeDeletableProperties::Protocol(protocol_property) => {
+ match protocol_property {
+ WireGuardNodeDeletableProperties::AllowedIps => {
+ external_wire_guard_node.allowed_ips = Vec::new()
+ }
+ _ => return Err(FabricConfigError::ProtocolMismatch),
+ }
+ }
+ _ => continue,
+ }
+ }
+ }
+ _ => return Err(FabricConfigError::ProtocolMismatch),
+ }
+
+ Ok(())
+ }
_ => Err(FabricConfigError::ProtocolMismatch),
}
}
@@ -316,6 +431,7 @@ impl FabricEntry {
match self {
FabricEntry::Openfabric(entry) => entry.nodes.iter(),
FabricEntry::Ospf(entry) => entry.nodes.iter(),
+ FabricEntry::WireGuard(entry) => entry.nodes.iter(),
}
}
@@ -324,6 +440,7 @@ impl FabricEntry {
match self {
FabricEntry::Openfabric(entry) => entry.delete_node(id),
FabricEntry::Ospf(entry) => entry.delete_node(id),
+ FabricEntry::WireGuard(entry) => entry.delete_node(id),
}
}
@@ -333,6 +450,7 @@ impl FabricEntry {
match self {
FabricEntry::Openfabric(entry) => entry.into_pair(),
FabricEntry::Ospf(entry) => entry.into_pair(),
+ FabricEntry::WireGuard(entry) => entry.into_pair(),
}
}
@@ -341,6 +459,7 @@ impl FabricEntry {
match self {
FabricEntry::Openfabric(entry) => &entry.fabric,
FabricEntry::Ospf(entry) => &entry.fabric,
+ FabricEntry::WireGuard(entry) => &entry.fabric,
}
}
@@ -349,6 +468,7 @@ impl FabricEntry {
match self {
FabricEntry::Openfabric(entry) => &mut entry.fabric,
FabricEntry::Ospf(entry) => &mut entry.fabric,
+ FabricEntry::WireGuard(entry) => &mut entry.fabric,
}
}
}
@@ -360,6 +480,7 @@ impl From<Fabric> for FabricEntry {
FabricEntry::Openfabric(Entry::new(fabric_section))
}
Fabric::Ospf(fabric_section) => FabricEntry::Ospf(Entry::new(fabric_section)),
+ Fabric::WireGuard(fabric_section) => FabricEntry::WireGuard(Entry::new(fabric_section)),
}
}
}
@@ -541,6 +662,9 @@ impl Validatable for FabricConfig {
return Err(FabricConfigError::DuplicateInterface);
}
}
+ Node::WireGuard(_node_section) => {
+ return Ok(());
+ }
}
}
@@ -695,6 +819,50 @@ impl FabricConfig {
Ok(())
}
+ (Fabric::WireGuard(fabric_section), FabricUpdater::WireGuard(updater)) => {
+ let FabricSectionUpdater::<
+ WireGuardPropertiesUpdater,
+ WireGuardDeletableProperties,
+ > {
+ ip_prefix,
+ ip6_prefix,
+ properties:
+ WireGuardPropertiesUpdater {
+ persistent_keepalive,
+ },
+ delete,
+ } = updater;
+
+ if let Some(prefix) = ip_prefix {
+ fabric_section.ip_prefix = Some(prefix);
+ }
+
+ if let Some(prefix) = ip6_prefix {
+ fabric_section.ip6_prefix = Some(prefix);
+ }
+
+ if let Some(keepalive) = persistent_keepalive {
+ fabric_section.properties.persistent_keepalive = Some(keepalive);
+ }
+
+ for property in delete {
+ match property {
+ FabricDeletableProperties::IpPrefix => {
+ fabric_section.ip_prefix = None;
+ }
+ FabricDeletableProperties::Ip6Prefix => {
+ fabric_section.ip6_prefix = None;
+ }
+ FabricDeletableProperties::Protocol(
+ WireGuardDeletableProperties::PersistentKeepalive,
+ ) => {
+ fabric_section.properties.persistent_keepalive = None;
+ }
+ }
+ }
+
+ Ok(())
+ }
_ => Err(FabricConfigError::ProtocolMismatch),
}
}
diff --git a/proxmox-ve-config/src/sdn/fabric/section_config/fabric.rs b/proxmox-ve-config/src/sdn/fabric/section_config/fabric.rs
index 38911a6..e92074c 100644
--- a/proxmox-ve-config/src/sdn/fabric/section_config/fabric.rs
+++ b/proxmox-ve-config/src/sdn/fabric/section_config/fabric.rs
@@ -16,6 +16,10 @@ use crate::sdn::fabric::section_config::protocol::ospf::{
};
use crate::sdn::fabric::FabricConfigError;
+use super::protocol::wireguard::{
+ WireGuardDeletableProperties, WireGuardProperties, WireGuardPropertiesUpdater,
+};
+
pub const FABRIC_ID_REGEX_STR: &str = r"(?:[a-zA-Z0-9])(?:[a-zA-Z0-9\-]){0,6}(?:[a-zA-Z0-9])?";
const_regex! {
@@ -139,6 +143,10 @@ impl UpdaterType for FabricSection<OspfProperties> {
type Updater = FabricSectionUpdater<OspfPropertiesUpdater, OspfDeletableProperties>;
}
+impl UpdaterType for FabricSection<WireGuardProperties> {
+ type Updater = FabricSectionUpdater<WireGuardPropertiesUpdater, WireGuardDeletableProperties>;
+}
+
/// Enum containing all types of fabrics.
///
/// It utilizes [`FabricSection<T>`] to define all possible types of fabrics. For parsing the
@@ -159,6 +167,8 @@ impl UpdaterType for FabricSection<OspfProperties> {
pub enum Fabric {
Openfabric(FabricSection<OpenfabricProperties>),
Ospf(FabricSection<OspfProperties>),
+ #[serde(rename = "wireguard")]
+ WireGuard(FabricSection<WireGuardProperties>),
}
impl UpdaterType for Fabric {
@@ -173,6 +183,7 @@ impl Fabric {
match self {
Self::Openfabric(fabric_section) => fabric_section.id(),
Self::Ospf(fabric_section) => fabric_section.id(),
+ Self::WireGuard(fabric_section) => fabric_section.id(),
}
}
@@ -183,6 +194,7 @@ impl Fabric {
match self {
Fabric::Openfabric(fabric_section) => fabric_section.ip_prefix(),
Fabric::Ospf(fabric_section) => fabric_section.ip_prefix(),
+ Fabric::WireGuard(fabric_section) => fabric_section.ip_prefix(),
}
}
@@ -193,6 +205,7 @@ impl Fabric {
match self {
Fabric::Openfabric(fabric_section) => fabric_section.ip_prefix = Some(ipv4_cidr),
Fabric::Ospf(fabric_section) => fabric_section.ip_prefix = Some(ipv4_cidr),
+ Fabric::WireGuard(fabric_section) => fabric_section.ip_prefix = Some(ipv4_cidr),
}
}
@@ -203,6 +216,7 @@ impl Fabric {
match self {
Fabric::Openfabric(fabric_section) => fabric_section.ip6_prefix(),
Fabric::Ospf(fabric_section) => fabric_section.ip6_prefix(),
+ Fabric::WireGuard(fabric_section) => fabric_section.ip6_prefix(),
}
}
@@ -213,6 +227,7 @@ impl Fabric {
match self {
Fabric::Openfabric(fabric_section) => fabric_section.ip6_prefix = Some(ipv6_cidr),
Fabric::Ospf(fabric_section) => fabric_section.ip6_prefix = Some(ipv6_cidr),
+ Fabric::WireGuard(fabric_section) => fabric_section.ip6_prefix = Some(ipv6_cidr),
}
}
}
@@ -225,6 +240,7 @@ impl Validatable for Fabric {
match self {
Fabric::Openfabric(fabric_section) => fabric_section.validate(),
Fabric::Ospf(fabric_section) => fabric_section.validate(),
+ Fabric::WireGuard(_fabric_section) => Ok(()),
}
}
}
@@ -241,12 +257,20 @@ impl From<FabricSection<OspfProperties>> for Fabric {
}
}
+impl From<FabricSection<WireGuardProperties>> for Fabric {
+ fn from(section: FabricSection<WireGuardProperties>) -> Self {
+ Fabric::WireGuard(section)
+ }
+}
+
/// Enum containing all updater types for fabrics
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case", tag = "protocol")]
pub enum FabricUpdater {
Openfabric(<FabricSection<OpenfabricProperties> as UpdaterType>::Updater),
Ospf(<FabricSection<OspfProperties> as UpdaterType>::Updater),
+ #[serde(rename = "wireguard")]
+ WireGuard(<FabricSection<WireGuardProperties> as UpdaterType>::Updater),
}
impl Updater for FabricUpdater {
@@ -254,6 +278,7 @@ impl Updater for FabricUpdater {
match self {
FabricUpdater::Openfabric(updater) => updater.is_empty(),
FabricUpdater::Ospf(updater) => updater.is_empty(),
+ FabricUpdater::WireGuard(updater) => updater.is_empty(),
}
}
}
diff --git a/proxmox-ve-config/src/sdn/fabric/section_config/mod.rs b/proxmox-ve-config/src/sdn/fabric/section_config/mod.rs
index d02d4ae..f47a522 100644
--- a/proxmox-ve-config/src/sdn/fabric/section_config/mod.rs
+++ b/proxmox-ve-config/src/sdn/fabric/section_config/mod.rs
@@ -4,6 +4,7 @@ pub mod node;
pub mod protocol;
use const_format::concatcp;
+use protocol::wireguard::WireGuardProperties;
use serde::{Deserialize, Serialize};
use crate::sdn::fabric::section_config::{
@@ -12,6 +13,7 @@ use crate::sdn::fabric::section_config::{
protocol::{
openfabric::{OpenfabricNodeProperties, OpenfabricProperties},
ospf::{OspfNodeProperties, OspfProperties},
+ wireguard::WireGuardNode,
},
};
@@ -31,8 +33,10 @@ impl From<Section> for FabricOrNode<Fabric, Node> {
match section {
Section::OpenfabricFabric(fabric_section) => Self::Fabric(fabric_section.into()),
Section::OspfFabric(fabric_section) => Self::Fabric(fabric_section.into()),
+ Section::WireGuardFabric(fabric_section) => Self::Fabric(fabric_section.into()),
Section::OpenfabricNode(node_section) => Self::Node(node_section.into()),
Section::OspfNode(node_section) => Self::Node(node_section.into()),
+ Section::WireGuardNode(node_section) => Self::Node(node_section.into()),
}
}
}
@@ -62,8 +66,12 @@ pub const SECTION_ID_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&SECTION
pub enum Section {
OpenfabricFabric(FabricSection<OpenfabricProperties>),
OspfFabric(FabricSection<OspfProperties>),
+ #[serde(rename = "wireguard_fabric")]
+ WireGuardFabric(FabricSection<WireGuardProperties>),
OpenfabricNode(NodeSection<OpenfabricNodeProperties>),
OspfNode(NodeSection<OspfNodeProperties>),
+ #[serde(rename = "wireguard_node")]
+ WireGuardNode(NodeSection<WireGuardNode>),
}
impl From<FabricSection<OpenfabricProperties>> for Section {
@@ -78,6 +86,12 @@ impl From<FabricSection<OspfProperties>> for Section {
}
}
+impl From<FabricSection<WireGuardProperties>> for Section {
+ fn from(section: FabricSection<WireGuardProperties>) -> Self {
+ Self::WireGuardFabric(section)
+ }
+}
+
impl From<NodeSection<OpenfabricNodeProperties>> for Section {
fn from(section: NodeSection<OpenfabricNodeProperties>) -> Self {
Self::OpenfabricNode(section)
@@ -90,11 +104,18 @@ impl From<NodeSection<OspfNodeProperties>> for Section {
}
}
+impl From<NodeSection<WireGuardNode>> for Section {
+ fn from(section: NodeSection<WireGuardNode>) -> Self {
+ Self::WireGuardNode(section)
+ }
+}
+
impl From<Fabric> for Section {
fn from(fabric: Fabric) -> Self {
match fabric {
Fabric::Openfabric(fabric_section) => fabric_section.into(),
Fabric::Ospf(fabric_section) => fabric_section.into(),
+ Fabric::WireGuard(fabric_section) => fabric_section.into(),
}
}
}
@@ -104,6 +125,43 @@ impl From<Node> for Section {
match node {
Node::Openfabric(node_section) => node_section.into(),
Node::Ospf(node_section) => node_section.into(),
+ Node::WireGuard(node_section) => node_section.into(),
}
}
}
+
+#[cfg(test)]
+mod tests {
+ use crate::sdn::fabric::FabricConfig;
+ use proxmox_section_config::typed::ApiSectionDataEntry;
+
+ use super::*;
+
+ #[test]
+ fn test_wireguard_fabric() -> Result<(), anyhow::Error> {
+ let section_config = r#"
+wireguard_fabric: wireg
+
+wireguard_node: wireg_external
+ role external
+ endpoint 192.0.2.1:123
+ public_key Kay64UG8yvCyLhqU000LxzYeUm0L/hLIl5S8kyKWbdc=
+
+wireguard_node: wireg_pve1
+ role internal
+ endpoint 192.0.2.2
+ interfaces name=wg0,listen_port=51111,public_key=Kay64UG8yvCyLhqU000LxzYeUm0L/hLIl5S8kyKWbdc=
+ peers type=internal,node=pve2,node_iface=wg0,iface=wg0
+
+wireguard_node: wireg_pve2
+ role internal
+ endpoint 192.0.2.3
+ interfaces name=wg0,listen_port=51111,public_key=Kay64UG8yvCyLhqU000LxzYeUm0L/hLIl5S8kyKWbdc=
+ peers type=internal,node=pve1,node_iface=wg0,iface=wg0
+"#;
+ let parsed_config = Section::parse_section_config("fabrics.cfg", section_config)?;
+ FabricConfig::from_section_config(parsed_config).expect("valid wireguard configuration");
+
+ Ok(())
+ }
+}
diff --git a/proxmox-ve-config/src/sdn/fabric/section_config/node.rs b/proxmox-ve-config/src/sdn/fabric/section_config/node.rs
index 17d2f0b..77ce15f 100644
--- a/proxmox-ve-config/src/sdn/fabric/section_config/node.rs
+++ b/proxmox-ve-config/src/sdn/fabric/section_config/node.rs
@@ -10,6 +10,7 @@ use proxmox_schema::{
};
use crate::common::valid::Validatable;
+use crate::sdn::fabric::section_config::protocol::wireguard::WireGuardNode;
use crate::sdn::fabric::section_config::{
fabric::{FabricId, FABRIC_ID_REGEX_STR},
protocol::{openfabric::OpenfabricNodeProperties, ospf::OspfNodeProperties},
@@ -36,6 +37,18 @@ api_string_type! {
pub struct NodeId(String);
}
+impl std::str::FromStr for NodeId {
+ type Err = anyhow::Error;
+
+ fn from_str(value: &str) -> Result<Self, Self::Err> {
+ Self::API_SCHEMA
+ .unwrap_string_schema()
+ .check_constraints(value)?;
+
+ Ok(unsafe { Self::from_string_unchecked(value.to_string()) })
+ }
+}
+
/// ID of a node in the section config.
///
/// This corresponds to the ID of the fabric, that contains this node, as well as the hostname of
@@ -147,8 +160,8 @@ impl<T> NodeSection<T> {
/// Get the IPv4 address (Router-ID) of the [`NodeSection`].
///
/// Either the [`NodeSection::ip`] (IPv4) address or the [`NodeSection::ip6`] (IPv6) address *must*
- /// be set. This is checked during the validation, so it's guaranteed. OpenFabric can also be
- /// used dual-stack, so both IPv4 and IPv6 addresses can be set.
+ /// be set. This is checked during the validation, so it's guaranteed. OpenFabric and WireGuard
+ /// can also be used dual-stack, so both IPv4 and IPv6 addresses can be set.
pub fn ip(&self) -> Option<std::net::Ipv4Addr> {
self.ip.as_deref().copied()
}
@@ -156,8 +169,8 @@ impl<T> NodeSection<T> {
/// Get the IPv6 address (Router-ID) of the [`NodeSection`].
///
/// Either the [`NodeSection::ip`] (IPv4) address or the [`NodeSection::ip6`] (IPv6) address *must*
- /// be set. This is checked during the validation, so it's guaranteed. OpenFabric can also be
- /// used dual-stack, so both IPv4 and IPv6 addresses can be set.
+ /// be set. This is checked during the validation, so it's guaranteed. OpenFabric and WireGuard
+ /// can also be used dual-stack, so both IPv4 and IPv6 addresses can be set.
pub fn ip6(&self) -> Option<std::net::Ipv6Addr> {
self.ip6.as_deref().copied()
}
@@ -186,6 +199,8 @@ impl<T: ApiType> ApiType for NodeSection<T> {
pub enum Node {
Openfabric(NodeSection<OpenfabricNodeProperties>),
Ospf(NodeSection<OspfNodeProperties>),
+ #[serde(rename = "wireguard")]
+ WireGuard(NodeSection<WireGuardNode>),
}
impl Node {
@@ -194,6 +209,7 @@ impl Node {
match self {
Node::Openfabric(node_section) => node_section.id(),
Node::Ospf(node_section) => node_section.id(),
+ Node::WireGuard(node_section) => node_section.id(),
}
}
@@ -202,6 +218,7 @@ impl Node {
match self {
Node::Openfabric(node_section) => node_section.ip(),
Node::Ospf(node_section) => node_section.ip(),
+ Node::WireGuard(node_section) => node_section.ip(),
}
}
@@ -210,6 +227,7 @@ impl Node {
match self {
Node::Openfabric(node_section) => node_section.ip6(),
Node::Ospf(node_section) => node_section.ip6(),
+ Node::WireGuard(node_section) => node_section.ip6(),
}
}
}
@@ -221,6 +239,7 @@ impl Validatable for Node {
match self {
Node::Openfabric(node_section) => node_section.validate(),
Node::Ospf(node_section) => node_section.validate(),
+ Node::WireGuard(_node_section) => Ok(()),
}
}
}
@@ -237,6 +256,12 @@ impl From<NodeSection<OspfNodeProperties>> for Node {
}
}
+impl From<NodeSection<WireGuardNode>> for Node {
+ fn from(value: NodeSection<WireGuardNode>) -> Self {
+ Self::WireGuard(value)
+ }
+}
+
/// API types for SDN fabric node configurations.
///
/// This module provides specialized types that are used for API interactions when retrieving,
@@ -263,6 +288,7 @@ pub mod api {
OpenfabricNodePropertiesUpdater,
},
ospf::{OspfNodeDeletableProperties, OspfNodeProperties, OspfNodePropertiesUpdater},
+ wireguard::{WireGuardNodeDeletableProperties, WireGuardNodeUpdater},
};
use super::*;
@@ -320,6 +346,8 @@ pub mod api {
pub enum Node {
Openfabric(NodeData<OpenfabricNodeProperties>),
Ospf(NodeData<OspfNodeProperties>),
+ #[serde(rename = "wireguard")]
+ WireGuard(NodeData<WireGuardNode>),
}
impl From<super::Node> for Node {
@@ -327,6 +355,7 @@ pub mod api {
match value {
super::Node::Openfabric(node_section) => Self::Openfabric(node_section.into()),
super::Node::Ospf(node_section) => Self::Ospf(node_section.into()),
+ super::Node::WireGuard(node_section) => Self::WireGuard(node_section.into()),
}
}
}
@@ -336,6 +365,7 @@ pub mod api {
match value {
Node::Openfabric(node_section) => Self::Openfabric(node_section.into()),
Node::Ospf(node_section) => Self::Ospf(node_section.into()),
+ Node::WireGuard(node_section) => Self::WireGuard(node_section.into()),
}
}
}
@@ -349,6 +379,10 @@ pub mod api {
type Updater = NodeDataUpdater<OspfNodePropertiesUpdater, OspfNodeDeletableProperties>;
}
+ impl UpdaterType for NodeData<WireGuardNode> {
+ type Updater = NodeDataUpdater<WireGuardNodeUpdater, WireGuardNodeDeletableProperties>;
+ }
+
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeDataUpdater<T, D> {
#[serde(skip_serializing_if = "Option::is_none")]
@@ -384,6 +418,8 @@ pub mod api {
NodeDataUpdater<OpenfabricNodePropertiesUpdater, OpenfabricNodeDeletableProperties>,
),
Ospf(NodeDataUpdater<OspfNodePropertiesUpdater, OspfNodeDeletableProperties>),
+ #[serde(rename = "wireguard")]
+ WireGuard(NodeDataUpdater<WireGuardNodeUpdater, WireGuardNodeDeletableProperties>),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
--
2.47.3
next prev parent reply other threads:[~2026-02-19 14:58 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-19 14:56 [RFC manager/network/proxmox{,-ve-rs,-perl-rs} 00/27] Add WireGuard as protocol to SDN fabrics Stefan Hanreich
2026-02-19 14:56 ` [PATCH proxmox 1/2] wireguard: skip serializing preshared_key if unset Stefan Hanreich
2026-02-19 14:56 ` [PATCH proxmox 2/2] wireguard: implement ApiType for endpoints and hostnames Stefan Hanreich
2026-02-19 14:56 ` [PATCH proxmox-ve-rs 1/9] debian: update control file Stefan Hanreich
2026-02-19 14:56 ` [PATCH proxmox-ve-rs 2/9] clippy: fix 'hiding a lifetime that's elided elsewhere is confusing' Stefan Hanreich
2026-02-19 14:56 ` [PATCH proxmox-ve-rs 3/9] sdn-types: add wireguard-specific PersistentKeepalive api type Stefan Hanreich
2026-02-19 14:56 ` [PATCH proxmox-ve-rs 4/9] ve-config: fabrics: split interface name regex into two parts Stefan Hanreich
2026-02-19 14:56 ` [PATCH proxmox-ve-rs 5/9] ve-config: fabric: refactor fabric config entry impl using macro Stefan Hanreich
2026-02-19 14:56 ` [PATCH proxmox-ve-rs 6/9] ve-config: fabrics: add protocol-specific properties for wireguard Stefan Hanreich
2026-02-19 14:56 ` Stefan Hanreich [this message]
2026-02-19 14:56 ` [PATCH proxmox-ve-rs 8/9] ve-config: fabrics: wireguard add validation for wireguard config Stefan Hanreich
2026-02-19 14:56 ` [PATCH proxmox-ve-rs 9/9] ve-config: fabrics: implement wireguard config generation Stefan Hanreich
2026-02-19 14:56 ` [PATCH proxmox-perl-rs 1/2] pve-rs: fabrics: wireguard: generate ifupdown2 configuration Stefan Hanreich
2026-02-19 14:56 ` [PATCH proxmox-perl-rs 2/2] pve-rs: fabrics: add helpers for parsing interface property strings Stefan Hanreich
2026-02-19 14:56 ` [PATCH pve-network 1/3] sdn: add wireguard helper module Stefan Hanreich
2026-02-19 14:56 ` [PATCH pve-network 2/3] fabrics: wireguard: add schema definitions for wireguard Stefan Hanreich
2026-02-19 14:56 ` [PATCH pve-network 3/3] fabrics: wireguard: implement wireguard key auto-generation Stefan Hanreich
2026-02-19 14:56 ` [PATCH pve-manager 01/11] network: sdn: generate wireguard configuration on apply Stefan Hanreich
2026-02-19 14:56 ` [PATCH pve-manager 02/11] ui: fix parsing of property-strings when values contain = Stefan Hanreich
2026-02-19 14:56 ` [PATCH pve-manager 03/11] ui: fabrics: i18n: make node loading string translatable Stefan Hanreich
2026-02-19 14:56 ` [PATCH pve-manager 04/11] ui: fabrics: split node selector creation and config Stefan Hanreich
2026-02-19 14:56 ` [PATCH pve-manager 05/11] ui: fabrics: edit: make ipv4/6 support generic over fabric panels Stefan Hanreich
2026-02-19 14:56 ` [PATCH pve-manager 06/11] ui: fabrics: node: make ipv4/6 support generic over edit panels Stefan Hanreich
2026-02-19 14:56 ` [PATCH pve-manager 07/11] ui: fabrics: interface: " Stefan Hanreich
2026-02-19 14:56 ` [PATCH pve-manager 08/11] ui: fabrics: wireguard: add interface edit panel Stefan Hanreich
2026-02-19 14:56 ` [PATCH pve-manager 09/11] ui: fabrics: wireguard: add node " Stefan Hanreich
2026-02-19 14:56 ` [PATCH pve-manager 10/11] ui: fabrics: wireguard: add fabric " Stefan Hanreich
2026-02-19 14:56 ` [PATCH pve-manager 11/11] ui: fabrics: hook up wireguard components Stefan Hanreich
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260219145649.441418-10-s.hanreich@proxmox.com \
--to=s.hanreich@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.