all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Stefan Hanreich <s.hanreich@proxmox.com>
To: pdm-devel@lists.proxmox.com
Subject: [pdm-devel] [PATCH proxmox-api-types 02/12] sdn: generate zones endpoints
Date: Fri, 28 Feb 2025 16:17:39 +0100	[thread overview]
Message-ID: <20250228151803.158984-3-s.hanreich@proxmox.com> (raw)
In-Reply-To: <20250228151803.158984-1-s.hanreich@proxmox.com>

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
---
 pve-api-types/src/generated/code.rs  |  39 +-
 pve-api-types/src/generated/types.rs | 789 +++++++++++++++++++++++++++
 2 files changed, 827 insertions(+), 1 deletion(-)

diff --git a/pve-api-types/src/generated/code.rs b/pve-api-types/src/generated/code.rs
index 401d3bc..c1f0e74 100644
--- a/pve-api-types/src/generated/code.rs
+++ b/pve-api-types/src/generated/code.rs
@@ -116,6 +116,8 @@
 /// - /cluster/sdn/ipams
 /// - /cluster/sdn/ipams/{ipam}
 /// - /cluster/sdn/ipams/{ipam}/status
+/// - /cluster/sdn/lock
+/// - /cluster/sdn/rollback
 /// - /cluster/sdn/vnets
 /// - /cluster/sdn/vnets/{vnet}
 /// - /cluster/sdn/vnets/{vnet}/firewall
@@ -125,7 +127,6 @@
 /// - /cluster/sdn/vnets/{vnet}/ips
 /// - /cluster/sdn/vnets/{vnet}/subnets
 /// - /cluster/sdn/vnets/{vnet}/subnets/{subnet}
-/// - /cluster/sdn/zones
 /// - /cluster/sdn/zones/{zone}
 /// - /cluster/tasks
 /// - /nodes/{node}
@@ -410,6 +411,11 @@ pub trait PveClient {
         Err(Error::Other("create_token not implemented"))
     }
 
+    /// Create a new sdn zone object.
+    async fn create_zone(&self, params: CreateZone) -> Result<(), Error> {
+        Err(Error::Other("create_zone not implemented"))
+    }
+
     /// Read subscription info.
     async fn get_subscription(&self, node: &str) -> Result<NodeSubscriptionInfo, Error> {
         Err(Error::Other("get_subscription not implemented"))
@@ -483,6 +489,16 @@ pub trait PveClient {
         Err(Error::Other("list_storages not implemented"))
     }
 
+    /// SDN zones index.
+    async fn list_zones(
+        &self,
+        pending: Option<bool>,
+        running: Option<bool>,
+        ty: Option<ListZonesType>,
+    ) -> Result<Vec<SdnZone>, Error> {
+        Err(Error::Other("list_zones not implemented"))
+    }
+
     /// Get container configuration.
     async fn lxc_get_config(
         &self,
@@ -710,6 +726,12 @@ where
         Ok(self.0.post(url, &params).await?.expect_json()?.data)
     }
 
+    /// Create a new sdn zone object.
+    async fn create_zone(&self, params: CreateZone) -> Result<(), Error> {
+        let url = "/api2/extjs/cluster/sdn/zones";
+        self.0.post(url, &params).await?.nodata()
+    }
+
     /// Read subscription info.
     async fn get_subscription(&self, node: &str) -> Result<NodeSubscriptionInfo, Error> {
         let url = &format!("/api2/extjs/nodes/{node}/subscription");
@@ -830,6 +852,21 @@ where
         Ok(self.0.get(url).await?.expect_json()?.data)
     }
 
+    /// SDN zones index.
+    async fn list_zones(
+        &self,
+        pending: Option<bool>,
+        running: Option<bool>,
+        ty: Option<ListZonesType>,
+    ) -> Result<Vec<SdnZone>, Error> {
+        let (mut query, mut sep) = (String::new(), '?');
+        add_query_bool(&mut query, &mut sep, "pending", pending);
+        add_query_bool(&mut query, &mut sep, "running", running);
+        add_query_arg(&mut query, &mut sep, "type", &ty);
+        let url = &format!("/api2/extjs/cluster/sdn/zones{query}");
+        Ok(self.0.get(url).await?.expect_json()?.data)
+    }
+
     /// Get container configuration.
     async fn lxc_get_config(
         &self,
diff --git a/pve-api-types/src/generated/types.rs b/pve-api-types/src/generated/types.rs
index 5a656ba..408d8ca 100644
--- a/pve-api-types/src/generated/types.rs
+++ b/pve-api-types/src/generated/types.rs
@@ -930,6 +930,262 @@ pub struct CreateTokenResponseInfo {
     pub privsep: Option<bool>,
 }
 
+const_regex! {
+
+CREATE_ZONE_EXITNODES_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9])?)$"##;
+CREATE_ZONE_EXITNODES_PRIMARY_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9])?)$"##;
+CREATE_ZONE_MAC_RE = r##"^(?i)[a-f0-9][02468ace](?::[a-f0-9]{2}){5}$"##;
+CREATE_ZONE_NODES_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9])?)$"##;
+CREATE_ZONE_RT_IMPORT_RE = r##"^(\d+):(\d+)$"##;
+CREATE_ZONE_ZONE_RE = r##"^[a-z][a-z0-9]*[a-z0-9]$"##;
+
+}
+
+#[api(
+    properties: {
+        "advertise-subnets": {
+            default: false,
+            optional: true,
+        },
+        bridge: {
+            optional: true,
+            type: String,
+        },
+        "bridge-disable-mac-learning": {
+            default: false,
+            optional: true,
+        },
+        controller: {
+            optional: true,
+            type: String,
+        },
+        dhcp: {
+            optional: true,
+            type: SdnZoneDhcp,
+        },
+        "disable-arp-nd-suppression": {
+            default: false,
+            optional: true,
+        },
+        dns: {
+            optional: true,
+            type: String,
+        },
+        dnszone: {
+            format: &ApiStringFormat::VerifyFn(verifiers::verify_dns_name),
+            optional: true,
+            type: String,
+        },
+        "dp-id": {
+            optional: true,
+            type: Integer,
+        },
+        exitnodes: {
+            format: &ApiStringFormat::Pattern(&CREATE_ZONE_EXITNODES_RE),
+            optional: true,
+            type: String,
+        },
+        "exitnodes-local-routing": {
+            default: false,
+            optional: true,
+        },
+        "exitnodes-primary": {
+            format: &ApiStringFormat::Pattern(&CREATE_ZONE_EXITNODES_PRIMARY_RE),
+            optional: true,
+            type: String,
+        },
+        ipam: {
+            optional: true,
+            type: String,
+        },
+        "lock-secret": {
+            optional: true,
+            type: String,
+        },
+        mac: {
+            format: &ApiStringFormat::Pattern(&CREATE_ZONE_MAC_RE),
+            optional: true,
+            type: String,
+        },
+        mtu: {
+            optional: true,
+            type: Integer,
+        },
+        nodes: {
+            format: &ApiStringFormat::Pattern(&CREATE_ZONE_NODES_RE),
+            optional: true,
+            type: String,
+        },
+        peers: {
+            format: &ApiStringFormat::VerifyFn(verifiers::verify_ip),
+            optional: true,
+            type: String,
+        },
+        reversedns: {
+            optional: true,
+            type: String,
+        },
+        "rt-import": {
+            format: &ApiStringFormat::Pattern(&CREATE_ZONE_RT_IMPORT_RE),
+            optional: true,
+            type: String,
+        },
+        tag: {
+            minimum: 0,
+            optional: true,
+            type: Integer,
+        },
+        type: {
+            type: ListZonesType,
+        },
+        "vlan-protocol": {
+            optional: true,
+            type: NetworkInterfaceVlanProtocol,
+        },
+        "vrf-vxlan": {
+            maximum: 16777215,
+            minimum: 1,
+            optional: true,
+            type: Integer,
+        },
+        "vxlan-port": {
+            maximum: 65536,
+            minimum: 1,
+            optional: true,
+            type: Integer,
+        },
+        zone: {
+            format: &ApiStringFormat::Pattern(&CREATE_ZONE_ZONE_RE),
+            type: String,
+        },
+    },
+)]
+/// Object.
+#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
+pub struct CreateZone {
+    /// Advertise IP prefixes (Type-5 routes) instead of MAC/IP pairs (Type-2
+    /// routes).
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_bool")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "advertise-subnets")]
+    pub advertise_subnets: Option<bool>,
+
+    /// the bridge for which VLANs should be managed
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub bridge: Option<String>,
+
+    /// Disable auto mac learning.
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_bool")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "bridge-disable-mac-learning")]
+    pub bridge_disable_mac_learning: Option<bool>,
+
+    /// Controller for this zone.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub controller: Option<String>,
+
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub dhcp: Option<SdnZoneDhcp>,
+
+    /// Suppress IPv4 ARP && IPv6 Neighbour Discovery messages.
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_bool")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "disable-arp-nd-suppression")]
+    pub disable_arp_nd_suppression: Option<bool>,
+
+    /// dns api server
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub dns: Option<String>,
+
+    /// dns domain zone  ex: mydomain.com
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub dnszone: Option<String>,
+
+    /// Faucet dataplane id
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_i64")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "dp-id")]
+    pub dp_id: Option<i64>,
+
+    /// List of cluster node names.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub exitnodes: Option<String>,
+
+    /// Allow exitnodes to connect to EVPN guests.
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_bool")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "exitnodes-local-routing")]
+    pub exitnodes_local_routing: Option<bool>,
+
+    /// Force traffic through this exitnode first.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "exitnodes-primary")]
+    pub exitnodes_primary: Option<String>,
+
+    /// use a specific ipam
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub ipam: Option<String>,
+
+    /// the secret for unlocking the global SDN configuration
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "lock-secret")]
+    pub lock_secret: Option<String>,
+
+    /// Anycast logical router mac address.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub mac: Option<String>,
+
+    /// MTU of the zone, will be used for the created VNet bridges.
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_i64")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub mtu: Option<i64>,
+
+    /// List of cluster node names.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub nodes: Option<String>,
+
+    /// Comma-separated list of peers, that are part of the VXLAN zone. Usually
+    /// the IPs of the nodes.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub peers: Option<String>,
+
+    /// reverse dns api server
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub reversedns: Option<String>,
+
+    /// List of Route Targets that should be imported into the VRF of the zone
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "rt-import")]
+    pub rt_import: Option<String>,
+
+    /// Service-VLAN Tag (outer VLAN)
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_u64")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub tag: Option<u64>,
+
+    #[serde(rename = "type")]
+    pub ty: ListZonesType,
+
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "vlan-protocol")]
+    pub vlan_protocol: Option<NetworkInterfaceVlanProtocol>,
+
+    /// VNI for the zone VRF.
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_u32")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "vrf-vxlan")]
+    pub vrf_vxlan: Option<u32>,
+
+    /// UDP port that should be used for the VXLAN tunnel (default 4789).
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_u32")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "vxlan-port")]
+    pub vxlan_port: Option<u32>,
+
+    /// The SDN zone object identifier.
+    pub zone: String,
+}
+
 #[api]
 /// A guest's run state.
 #[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
@@ -1334,6 +1590,32 @@ pub enum ListTasksSource {
 serde_plain::derive_display_from_serialize!(ListTasksSource);
 serde_plain::derive_fromstr_from_deserialize!(ListTasksSource);
 
+#[api]
+/// Only list SDN zones of specific type
+#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
+pub enum ListZonesType {
+    #[serde(rename = "evpn")]
+    /// evpn.
+    Evpn,
+    #[serde(rename = "faucet")]
+    /// faucet.
+    Faucet,
+    #[serde(rename = "qinq")]
+    /// qinq.
+    Qinq,
+    #[serde(rename = "simple")]
+    /// simple.
+    Simple,
+    #[serde(rename = "vlan")]
+    /// vlan.
+    Vlan,
+    #[serde(rename = "vxlan")]
+    /// vxlan.
+    Vxlan,
+}
+serde_plain::derive_display_from_serialize!(ListZonesType);
+serde_plain::derive_fromstr_from_deserialize!(ListZonesType);
+
 const_regex! {
 
 LXC_CONFIG_TAGS_RE = r##"^(?i)[a-z0-9_][a-z0-9_\-+.]*$"##;
@@ -8828,6 +9110,513 @@ mod storage_info_content {
     }
 }
 
+#[api]
+/// The state of an SDN object.
+#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
+pub enum SdnObjectState {
+    #[serde(rename = "new")]
+    /// new.
+    New,
+    #[serde(rename = "deleted")]
+    /// deleted.
+    Deleted,
+    #[serde(rename = "changed")]
+    /// changed.
+    Changed,
+}
+serde_plain::derive_display_from_serialize!(SdnObjectState);
+serde_plain::derive_fromstr_from_deserialize!(SdnObjectState);
+
+const_regex! {
+
+SDN_ZONE_EXITNODES_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9])?)$"##;
+SDN_ZONE_EXITNODES_PRIMARY_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9])?)$"##;
+SDN_ZONE_RT_IMPORT_RE = r##"^(\d+):(\d+)$"##;
+
+}
+
+#[api(
+    properties: {
+        "advertise-subnets": {
+            default: false,
+            optional: true,
+        },
+        bridge: {
+            optional: true,
+            type: String,
+        },
+        "bridge-disable-mac-learning": {
+            default: false,
+            optional: true,
+        },
+        controller: {
+            optional: true,
+            type: String,
+        },
+        dhcp: {
+            optional: true,
+            type: SdnZoneDhcp,
+        },
+        digest: {
+            optional: true,
+            type: String,
+        },
+        "disable-arp-nd-suppression": {
+            default: false,
+            optional: true,
+        },
+        dns: {
+            optional: true,
+            type: String,
+        },
+        dnszone: {
+            optional: true,
+            type: String,
+        },
+        exitnodes: {
+            format: &ApiStringFormat::Pattern(&SDN_ZONE_EXITNODES_RE),
+            optional: true,
+            type: String,
+        },
+        "exitnodes-local-routing": {
+            default: false,
+            optional: true,
+        },
+        "exitnodes-primary": {
+            format: &ApiStringFormat::Pattern(&SDN_ZONE_EXITNODES_PRIMARY_RE),
+            optional: true,
+            type: String,
+        },
+        ipam: {
+            optional: true,
+            type: String,
+        },
+        mac: {
+            optional: true,
+            type: String,
+        },
+        mtu: {
+            optional: true,
+            type: Integer,
+        },
+        nodes: {
+            optional: true,
+            type: String,
+        },
+        peers: {
+            format: &ApiStringFormat::VerifyFn(verifiers::verify_ip),
+            optional: true,
+            type: String,
+        },
+        pending: {
+            optional: true,
+            type: SdnZonePending,
+        },
+        reversedns: {
+            optional: true,
+            type: String,
+        },
+        "rt-import": {
+            format: &ApiStringFormat::Pattern(&SDN_ZONE_RT_IMPORT_RE),
+            optional: true,
+            type: String,
+        },
+        state: {
+            optional: true,
+            type: SdnObjectState,
+        },
+        tag: {
+            minimum: 0,
+            optional: true,
+            type: Integer,
+        },
+        type: {
+            type: ListZonesType,
+        },
+        "vlan-protocol": {
+            optional: true,
+            type: NetworkInterfaceVlanProtocol,
+        },
+        "vrf-vxlan": {
+            maximum: 16777215,
+            minimum: 1,
+            optional: true,
+            type: Integer,
+        },
+        "vxlan-port": {
+            maximum: 65536,
+            minimum: 1,
+            optional: true,
+            type: Integer,
+        },
+        zone: {
+            type: String,
+        },
+    },
+)]
+/// Object.
+#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
+pub struct SdnZone {
+    /// Advertise IP prefixes (Type-5 routes) instead of MAC/IP pairs (Type-2
+    /// routes). EVPN zone only.
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_bool")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "advertise-subnets")]
+    pub advertise_subnets: Option<bool>,
+
+    /// the bridge for which VLANs should be managed. VLAN & QinQ zone only.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub bridge: Option<String>,
+
+    /// Disable auto mac learning. VLAN zone only.
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_bool")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "bridge-disable-mac-learning")]
+    pub bridge_disable_mac_learning: Option<bool>,
+
+    /// ID of the controller for this zone. EVPN zone only.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub controller: Option<String>,
+
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub dhcp: Option<SdnZoneDhcp>,
+
+    /// Digest of the controller section.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub digest: Option<String>,
+
+    /// Suppress IPv4 ARP && IPv6 Neighbour Discovery messages. EVPN zone only.
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_bool")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "disable-arp-nd-suppression")]
+    pub disable_arp_nd_suppression: Option<bool>,
+
+    /// ID of the DNS server for this zone.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub dns: Option<String>,
+
+    /// Domain name for this zone.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub dnszone: Option<String>,
+
+    /// List of PVE Nodes that should act as exit node for this zone. EVPN zone
+    /// only.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub exitnodes: Option<String>,
+
+    /// Create routes on the exit nodes, so they can connect to EVPN guests.
+    /// EVPN zone only.
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_bool")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "exitnodes-local-routing")]
+    pub exitnodes_local_routing: Option<bool>,
+
+    /// Force traffic through this exitnode first. EVPN zone only.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "exitnodes-primary")]
+    pub exitnodes_primary: Option<String>,
+
+    /// ID of the IPAM for this zone.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub ipam: Option<String>,
+
+    /// MAC address of the anycast router for this zone.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub mac: Option<String>,
+
+    /// MTU of the zone, will be used for the created VNet bridges.
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_i64")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub mtu: Option<i64>,
+
+    /// Nodes where this zone should be created.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub nodes: Option<String>,
+
+    /// Comma-separated list of peers, that are part of the VXLAN zone. Usually
+    /// the IPs of the nodes. VXLAN zone only.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub peers: Option<String>,
+
+    /// Changes that have not yet been applied to the running configuration.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub pending: Option<SdnZonePending>,
+
+    /// ID of the reverse DNS server for this zone.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub reversedns: Option<String>,
+
+    /// Route-Targets that should be imported into the VRF of this zone via BGP.
+    /// EVPN zone only.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "rt-import")]
+    pub rt_import: Option<String>,
+
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub state: Option<SdnObjectState>,
+
+    /// Service-VLAN Tag (outer VLAN). QinQ zone only
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_u64")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub tag: Option<u64>,
+
+    #[serde(rename = "type")]
+    pub ty: ListZonesType,
+
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "vlan-protocol")]
+    pub vlan_protocol: Option<NetworkInterfaceVlanProtocol>,
+
+    /// VNI for the zone VRF. EVPN zone only.
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_u32")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "vrf-vxlan")]
+    pub vrf_vxlan: Option<u32>,
+
+    /// UDP port that should be used for the VXLAN tunnel (default 4789). VXLAN
+    /// zone only.
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_u32")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "vxlan-port")]
+    pub vxlan_port: Option<u32>,
+
+    /// Name of the zone.
+    pub zone: String,
+}
+
+#[api]
+/// Name of DHCP server backend for this zone.
+#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
+pub enum SdnZoneDhcp {
+    #[serde(rename = "dnsmasq")]
+    /// dnsmasq.
+    Dnsmasq,
+}
+serde_plain::derive_display_from_serialize!(SdnZoneDhcp);
+serde_plain::derive_fromstr_from_deserialize!(SdnZoneDhcp);
+
+const_regex! {
+
+SDN_ZONE_PENDING_EXITNODES_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9])?)$"##;
+SDN_ZONE_PENDING_EXITNODES_PRIMARY_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9])?)$"##;
+SDN_ZONE_PENDING_RT_IMPORT_RE = r##"^(\d+):(\d+)$"##;
+
+}
+
+#[api(
+    properties: {
+        "advertise-subnets": {
+            default: false,
+            optional: true,
+        },
+        bridge: {
+            optional: true,
+            type: String,
+        },
+        "bridge-disable-mac-learning": {
+            default: false,
+            optional: true,
+        },
+        controller: {
+            optional: true,
+            type: String,
+        },
+        dhcp: {
+            optional: true,
+            type: SdnZoneDhcp,
+        },
+        "disable-arp-nd-suppression": {
+            default: false,
+            optional: true,
+        },
+        dns: {
+            optional: true,
+            type: String,
+        },
+        dnszone: {
+            optional: true,
+            type: String,
+        },
+        exitnodes: {
+            format: &ApiStringFormat::Pattern(&SDN_ZONE_PENDING_EXITNODES_RE),
+            optional: true,
+            type: String,
+        },
+        "exitnodes-local-routing": {
+            default: false,
+            optional: true,
+        },
+        "exitnodes-primary": {
+            format: &ApiStringFormat::Pattern(&SDN_ZONE_PENDING_EXITNODES_PRIMARY_RE),
+            optional: true,
+            type: String,
+        },
+        ipam: {
+            optional: true,
+            type: String,
+        },
+        mac: {
+            optional: true,
+            type: String,
+        },
+        mtu: {
+            optional: true,
+            type: Integer,
+        },
+        nodes: {
+            optional: true,
+            type: String,
+        },
+        peers: {
+            format: &ApiStringFormat::VerifyFn(verifiers::verify_ip),
+            optional: true,
+            type: String,
+        },
+        reversedns: {
+            optional: true,
+            type: String,
+        },
+        "rt-import": {
+            format: &ApiStringFormat::Pattern(&SDN_ZONE_PENDING_RT_IMPORT_RE),
+            optional: true,
+            type: String,
+        },
+        tag: {
+            minimum: 0,
+            optional: true,
+            type: Integer,
+        },
+        "vlan-protocol": {
+            optional: true,
+            type: NetworkInterfaceVlanProtocol,
+        },
+        "vrf-vxlan": {
+            maximum: 16777215,
+            minimum: 1,
+            optional: true,
+            type: Integer,
+        },
+        "vxlan-port": {
+            maximum: 65536,
+            minimum: 1,
+            optional: true,
+            type: Integer,
+        },
+    },
+)]
+/// Changes that have not yet been applied to the running configuration.
+#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
+pub struct SdnZonePending {
+    /// Advertise IP prefixes (Type-5 routes) instead of MAC/IP pairs (Type-2
+    /// routes). EVPN zone only.
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_bool")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "advertise-subnets")]
+    pub advertise_subnets: Option<bool>,
+
+    /// the bridge for which VLANs should be managed. VLAN & QinQ zone only.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub bridge: Option<String>,
+
+    /// Disable auto mac learning. VLAN zone only.
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_bool")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "bridge-disable-mac-learning")]
+    pub bridge_disable_mac_learning: Option<bool>,
+
+    /// ID of the controller for this zone. EVPN zone only.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub controller: Option<String>,
+
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub dhcp: Option<SdnZoneDhcp>,
+
+    /// Suppress IPv4 ARP && IPv6 Neighbour Discovery messages. EVPN zone only.
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_bool")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "disable-arp-nd-suppression")]
+    pub disable_arp_nd_suppression: Option<bool>,
+
+    /// ID of the DNS server for this zone.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub dns: Option<String>,
+
+    /// Domain name for this zone.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub dnszone: Option<String>,
+
+    /// List of PVE Nodes that should act as exit node for this zone. EVPN zone
+    /// only.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub exitnodes: Option<String>,
+
+    /// Create routes on the exit nodes, so they can connect to EVPN guests.
+    /// EVPN zone only.
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_bool")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "exitnodes-local-routing")]
+    pub exitnodes_local_routing: Option<bool>,
+
+    /// Force traffic through this exitnode first. EVPN zone only.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "exitnodes-primary")]
+    pub exitnodes_primary: Option<String>,
+
+    /// ID of the IPAM for this zone.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub ipam: Option<String>,
+
+    /// MAC address of the anycast router for this zone.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub mac: Option<String>,
+
+    /// MTU of the zone, will be used for the created VNet bridges.
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_i64")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub mtu: Option<i64>,
+
+    /// Nodes where this zone should be created.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub nodes: Option<String>,
+
+    /// Comma-separated list of peers, that are part of the VXLAN zone. Usually
+    /// the IPs of the nodes. VXLAN zone only.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub peers: Option<String>,
+
+    /// ID of the reverse DNS server for this zone.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub reversedns: Option<String>,
+
+    /// Route-Targets that should be imported into the VRF of this zone via BGP.
+    /// EVPN zone only.
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "rt-import")]
+    pub rt_import: Option<String>,
+
+    /// Service-VLAN Tag (outer VLAN). QinQ zone only
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_u64")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub tag: Option<u64>,
+
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "vlan-protocol")]
+    pub vlan_protocol: Option<NetworkInterfaceVlanProtocol>,
+
+    /// VNI for the zone VRF. EVPN zone only.
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_u32")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "vrf-vxlan")]
+    pub vrf_vxlan: Option<u32>,
+
+    /// UDP port that should be used for the VXLAN tunnel (default 4789). VXLAN
+    /// zone only.
+    #[serde(deserialize_with = "proxmox_login::parse::deserialize_u32")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "vxlan-port")]
+    pub vxlan_port: Option<u32>,
+}
+
 #[api(
     properties: {
         forceStop: {
-- 
2.39.5


_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


  parent reply	other threads:[~2025-02-28 15:19 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-02-28 15:17 [pdm-devel] [RFC proxmox{-api-types, -yew-comp, -datacenter-manager} 00/26] Add initial SDN / EVPN integration Stefan Hanreich
2025-02-28 15:17 ` [pdm-devel] [PATCH proxmox-api-types 01/12] sdn: add list/create zone endpoints Stefan Hanreich
2025-02-28 15:17 ` Stefan Hanreich [this message]
2025-02-28 15:17 ` [pdm-devel] [PATCH proxmox-api-types 03/12] sdn: add list/create vnet endpoints Stefan Hanreich
2025-02-28 15:17 ` [pdm-devel] [PATCH proxmox-api-types 04/12] sdn: generate " Stefan Hanreich
2025-02-28 15:17 ` [pdm-devel] [PATCH proxmox-api-types 05/12] sdn: add list/create controller endpoints Stefan Hanreich
2025-02-28 15:17 ` [pdm-devel] [PATCH proxmox-api-types 06/12] sdn: generate " Stefan Hanreich
2025-02-28 15:17 ` [pdm-devel] [PATCH proxmox-api-types 07/12] sdn: add acquire/release lock endpoints Stefan Hanreich
2025-02-28 15:17 ` [pdm-devel] [PATCH proxmox-api-types 08/12] sdn: generate " Stefan Hanreich
2025-02-28 15:17 ` [pdm-devel] [PATCH proxmox-api-types 09/12] sdn: add apply configuration endpoint Stefan Hanreich
2025-02-28 15:17 ` [pdm-devel] [PATCH proxmox-api-types 10/12] sdn: generate " Stefan Hanreich
2025-02-28 15:17 ` [pdm-devel] [PATCH proxmox-api-types 11/12] tasks: add helper for querying successfully finished tasks Stefan Hanreich
2025-02-28 15:17 ` [pdm-devel] [PATCH proxmox-api-types 12/12] sdn: add helpers for pending values Stefan Hanreich
2025-02-28 15:17 ` [pdm-devel] [PATCH proxmox-yew-comp 1/1] sdn: add descriptions for sdn tasks Stefan Hanreich
2025-02-28 15:17 ` [pdm-devel] [PATCH proxmox-datacenter-manager 01/13] server: add locked sdn client and helper methods Stefan Hanreich
2025-02-28 15:17 ` [pdm-devel] [PATCH proxmox-datacenter-manager 02/13] api: sdn: add list_zones endpoint Stefan Hanreich
2025-02-28 15:17 ` [pdm-devel] [PATCH proxmox-datacenter-manager 03/13] api: sdn: add create_zone endpoint Stefan Hanreich
2025-02-28 15:17 ` [pdm-devel] [PATCH proxmox-datacenter-manager 04/13] api: sdn: add list_vnets endpoint Stefan Hanreich
2025-02-28 15:17 ` [pdm-devel] [PATCH proxmox-datacenter-manager 05/13] api: sdn: add create_vnet endpoint Stefan Hanreich
2025-02-28 15:17 ` [pdm-devel] [PATCH proxmox-datacenter-manager 06/13] api: sdn: add list_controllers endpoint Stefan Hanreich
2025-02-28 15:17 ` [pdm-devel] [PATCH proxmox-datacenter-manager 07/13] ui: add VrfTree component Stefan Hanreich
2025-02-28 15:17 ` [pdm-devel] [PATCH proxmox-datacenter-manager 08/13] ui: sdn: add RouterTable component Stefan Hanreich
2025-02-28 15:17 ` [pdm-devel] [PATCH proxmox-datacenter-manager 09/13] ui: sdn: add AddVnetWindow component Stefan Hanreich
2025-02-28 15:18 ` [pdm-devel] [PATCH proxmox-datacenter-manager 10/13] ui: sdn: add AddZoneWindow component Stefan Hanreich
2025-02-28 15:18 ` [pdm-devel] [PATCH proxmox-datacenter-manager 11/13] ui: sdn: add EvpnPanel Stefan Hanreich
2025-02-28 15:18 ` [pdm-devel] [PATCH proxmox-datacenter-manager 12/13] ui: sdn: add EvpnPanel to main menu Stefan Hanreich
2025-02-28 15:18 ` [pdm-devel] [PATCH proxmox-datacenter-manager 13/13] pve: sdn: add descriptions for sdn tasks 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=20250228151803.158984-3-s.hanreich@proxmox.com \
    --to=s.hanreich@proxmox.com \
    --cc=pdm-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.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal