From db1012b5aa379e0b23e10fe5752b67e9937996d1 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Wed, 8 Sep 2021 12:22:48 +0200 Subject: [PATCH] move network config to pbs_config workspace --- pbs-api-types/src/lib.rs | 3 + pbs-api-types/src/network.rs | 308 +++++++++++++++++++++++++++++++++++ 2 files changed, 311 insertions(+) create mode 100644 pbs-api-types/src/network.rs diff --git a/pbs-api-types/src/lib.rs b/pbs-api-types/src/lib.rs index 055907cb..62ded91d 100644 --- a/pbs-api-types/src/lib.rs +++ b/pbs-api-types/src/lib.rs @@ -40,6 +40,9 @@ pub use jobs::*; mod key_derivation; pub use key_derivation::{Kdf, KeyInfo}; +mod network; +pub use network::*; + #[macro_use] mod userid; pub use userid::Authid; diff --git a/pbs-api-types/src/network.rs b/pbs-api-types/src/network.rs new file mode 100644 index 00000000..d3a8e43c --- /dev/null +++ b/pbs-api-types/src/network.rs @@ -0,0 +1,308 @@ +use serde::{Deserialize, Serialize}; + +use proxmox::api::{api, schema::*}; + +use crate::{ + PROXMOX_SAFE_ID_REGEX, + IP_V4_FORMAT, IP_V6_FORMAT, IP_FORMAT, + CIDR_V4_FORMAT, CIDR_V6_FORMAT, CIDR_FORMAT, +}; + +pub const NETWORK_INTERFACE_FORMAT: ApiStringFormat = + ApiStringFormat::Pattern(&PROXMOX_SAFE_ID_REGEX); + +pub const IP_V4_SCHEMA: Schema = + StringSchema::new("IPv4 address.") + .format(&IP_V4_FORMAT) + .max_length(15) + .schema(); + +pub const IP_V6_SCHEMA: Schema = + StringSchema::new("IPv6 address.") + .format(&IP_V6_FORMAT) + .max_length(39) + .schema(); + +pub const IP_SCHEMA: Schema = + StringSchema::new("IP (IPv4 or IPv6) address.") + .format(&IP_FORMAT) + .max_length(39) + .schema(); + +pub const CIDR_V4_SCHEMA: Schema = + StringSchema::new("IPv4 address with netmask (CIDR notation).") + .format(&CIDR_V4_FORMAT) + .max_length(18) + .schema(); + +pub const CIDR_V6_SCHEMA: Schema = + StringSchema::new("IPv6 address with netmask (CIDR notation).") + .format(&CIDR_V6_FORMAT) + .max_length(43) + .schema(); + +pub const CIDR_SCHEMA: Schema = + StringSchema::new("IP address (IPv4 or IPv6) with netmask (CIDR notation).") + .format(&CIDR_FORMAT) + .max_length(43) + .schema(); + +#[api()] +#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +/// Interface configuration method +pub enum NetworkConfigMethod { + /// Configuration is done manually using other tools + Manual, + /// Define interfaces with statically allocated addresses. + Static, + /// Obtain an address via DHCP + DHCP, + /// Define the loopback interface. + Loopback, +} + +#[api()] +#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +#[allow(non_camel_case_types)] +#[repr(u8)] +/// Linux Bond Mode +pub enum LinuxBondMode { + /// Round-robin policy + balance_rr = 0, + /// Active-backup policy + active_backup = 1, + /// XOR policy + balance_xor = 2, + /// Broadcast policy + broadcast = 3, + /// IEEE 802.3ad Dynamic link aggregation + #[serde(rename = "802.3ad")] + ieee802_3ad = 4, + /// Adaptive transmit load balancing + balance_tlb = 5, + /// Adaptive load balancing + balance_alb = 6, +} + +#[api()] +#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +#[allow(non_camel_case_types)] +#[repr(u8)] +/// Bond Transmit Hash Policy for LACP (802.3ad) +pub enum BondXmitHashPolicy { + /// Layer 2 + layer2 = 0, + /// Layer 2+3 + #[serde(rename = "layer2+3")] + layer2_3 = 1, + /// Layer 3+4 + #[serde(rename = "layer3+4")] + layer3_4 = 2, +} + +#[api()] +#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +/// Network interface type +pub enum NetworkInterfaceType { + /// Loopback + Loopback, + /// Physical Ethernet device + Eth, + /// Linux Bridge + Bridge, + /// Linux Bond + Bond, + /// Linux VLAN (eth.10) + Vlan, + /// Interface Alias (eth:1) + Alias, + /// Unknown interface type + Unknown, +} + +pub const NETWORK_INTERFACE_NAME_SCHEMA: Schema = StringSchema::new("Network interface name.") + .format(&NETWORK_INTERFACE_FORMAT) + .min_length(1) + .max_length(libc::IFNAMSIZ-1) + .schema(); + +pub const NETWORK_INTERFACE_ARRAY_SCHEMA: Schema = ArraySchema::new( + "Network interface list.", &NETWORK_INTERFACE_NAME_SCHEMA) + .schema(); + +pub const NETWORK_INTERFACE_LIST_SCHEMA: Schema = StringSchema::new( + "A list of network devices, comma separated.") + .format(&ApiStringFormat::PropertyString(&NETWORK_INTERFACE_ARRAY_SCHEMA)) + .schema(); + +#[api( + properties: { + name: { + schema: NETWORK_INTERFACE_NAME_SCHEMA, + }, + "type": { + type: NetworkInterfaceType, + }, + method: { + type: NetworkConfigMethod, + optional: true, + }, + method6: { + type: NetworkConfigMethod, + optional: true, + }, + cidr: { + schema: CIDR_V4_SCHEMA, + optional: true, + }, + cidr6: { + schema: CIDR_V6_SCHEMA, + optional: true, + }, + gateway: { + schema: IP_V4_SCHEMA, + optional: true, + }, + gateway6: { + schema: IP_V6_SCHEMA, + optional: true, + }, + options: { + description: "Option list (inet)", + type: Array, + items: { + description: "Optional attribute line.", + type: String, + }, + }, + options6: { + description: "Option list (inet6)", + type: Array, + items: { + description: "Optional attribute line.", + type: String, + }, + }, + comments: { + description: "Comments (inet, may span multiple lines)", + type: String, + optional: true, + }, + comments6: { + description: "Comments (inet6, may span multiple lines)", + type: String, + optional: true, + }, + bridge_ports: { + schema: NETWORK_INTERFACE_ARRAY_SCHEMA, + optional: true, + }, + slaves: { + schema: NETWORK_INTERFACE_ARRAY_SCHEMA, + optional: true, + }, + bond_mode: { + type: LinuxBondMode, + optional: true, + }, + "bond-primary": { + schema: NETWORK_INTERFACE_NAME_SCHEMA, + optional: true, + }, + bond_xmit_hash_policy: { + type: BondXmitHashPolicy, + optional: true, + }, + } +)] +#[derive(Debug, Serialize, Deserialize)] +/// Network Interface configuration +pub struct Interface { + /// Autostart interface + #[serde(rename = "autostart")] + pub autostart: bool, + /// Interface is active (UP) + pub active: bool, + /// Interface name + pub name: String, + /// Interface type + #[serde(rename = "type")] + pub interface_type: NetworkInterfaceType, + #[serde(skip_serializing_if="Option::is_none")] + pub method: Option, + #[serde(skip_serializing_if="Option::is_none")] + pub method6: Option, + #[serde(skip_serializing_if="Option::is_none")] + /// IPv4 address with netmask + pub cidr: Option, + #[serde(skip_serializing_if="Option::is_none")] + /// IPv4 gateway + pub gateway: Option, + #[serde(skip_serializing_if="Option::is_none")] + /// IPv6 address with netmask + pub cidr6: Option, + #[serde(skip_serializing_if="Option::is_none")] + /// IPv6 gateway + pub gateway6: Option, + + #[serde(skip_serializing_if="Vec::is_empty")] + pub options: Vec, + #[serde(skip_serializing_if="Vec::is_empty")] + pub options6: Vec, + + #[serde(skip_serializing_if="Option::is_none")] + pub comments: Option, + #[serde(skip_serializing_if="Option::is_none")] + pub comments6: Option, + + #[serde(skip_serializing_if="Option::is_none")] + /// Maximum Transmission Unit + pub mtu: Option, + + #[serde(skip_serializing_if="Option::is_none")] + pub bridge_ports: Option>, + /// Enable bridge vlan support. + #[serde(skip_serializing_if="Option::is_none")] + pub bridge_vlan_aware: Option, + + #[serde(skip_serializing_if="Option::is_none")] + pub slaves: Option>, + #[serde(skip_serializing_if="Option::is_none")] + pub bond_mode: Option, + #[serde(skip_serializing_if="Option::is_none")] + #[serde(rename = "bond-primary")] + pub bond_primary: Option, + pub bond_xmit_hash_policy: Option, +} + +impl Interface { + pub fn new(name: String) -> Self { + Self { + name, + interface_type: NetworkInterfaceType::Unknown, + autostart: false, + active: false, + method: None, + method6: None, + cidr: None, + gateway: None, + cidr6: None, + gateway6: None, + options: Vec::new(), + options6: Vec::new(), + comments: None, + comments6: None, + mtu: None, + bridge_ports: None, + bridge_vlan_aware: None, + slaves: None, + bond_mode: None, + bond_primary: None, + bond_xmit_hash_policy: None, + } + } +}