]>
Commit | Line | Data |
---|---|---|
a2055c38 WB |
1 | use std::fmt; |
2 | ||
6f422880 DM |
3 | use serde::{Deserialize, Serialize}; |
4 | ||
6ef1b649 | 5 | use proxmox_schema::*; |
6f422880 DM |
6 | |
7 | use crate::{ | |
b22d785c | 8 | CIDR_FORMAT, CIDR_V4_FORMAT, CIDR_V6_FORMAT, IP_FORMAT, IP_V4_FORMAT, IP_V6_FORMAT, |
6f422880 | 9 | PROXMOX_SAFE_ID_REGEX, |
6f422880 DM |
10 | }; |
11 | ||
12 | pub const NETWORK_INTERFACE_FORMAT: ApiStringFormat = | |
13 | ApiStringFormat::Pattern(&PROXMOX_SAFE_ID_REGEX); | |
14 | ||
b22d785c | 15 | pub const IP_V4_SCHEMA: Schema = StringSchema::new("IPv4 address.") |
6f422880 DM |
16 | .format(&IP_V4_FORMAT) |
17 | .max_length(15) | |
18 | .schema(); | |
19 | ||
b22d785c | 20 | pub const IP_V6_SCHEMA: Schema = StringSchema::new("IPv6 address.") |
6f422880 DM |
21 | .format(&IP_V6_FORMAT) |
22 | .max_length(39) | |
23 | .schema(); | |
24 | ||
b22d785c | 25 | pub const IP_SCHEMA: Schema = StringSchema::new("IP (IPv4 or IPv6) address.") |
6f422880 DM |
26 | .format(&IP_FORMAT) |
27 | .max_length(39) | |
28 | .schema(); | |
29 | ||
b22d785c | 30 | pub const CIDR_V4_SCHEMA: Schema = StringSchema::new("IPv4 address with netmask (CIDR notation).") |
6f422880 DM |
31 | .format(&CIDR_V4_FORMAT) |
32 | .max_length(18) | |
33 | .schema(); | |
34 | ||
b22d785c | 35 | pub const CIDR_V6_SCHEMA: Schema = StringSchema::new("IPv6 address with netmask (CIDR notation).") |
6f422880 DM |
36 | .format(&CIDR_V6_FORMAT) |
37 | .max_length(43) | |
38 | .schema(); | |
39 | ||
40 | pub const CIDR_SCHEMA: Schema = | |
41 | StringSchema::new("IP address (IPv4 or IPv6) with netmask (CIDR notation).") | |
b22d785c TL |
42 | .format(&CIDR_FORMAT) |
43 | .max_length(43) | |
44 | .schema(); | |
6f422880 DM |
45 | |
46 | #[api()] | |
f680e72f | 47 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] |
6f422880 DM |
48 | #[serde(rename_all = "lowercase")] |
49 | /// Interface configuration method | |
50 | pub enum NetworkConfigMethod { | |
51 | /// Configuration is done manually using other tools | |
52 | Manual, | |
53 | /// Define interfaces with statically allocated addresses. | |
54 | Static, | |
55 | /// Obtain an address via DHCP | |
56 | DHCP, | |
57 | /// Define the loopback interface. | |
58 | Loopback, | |
59 | } | |
60 | ||
61 | #[api()] | |
f680e72f | 62 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] |
6f422880 | 63 | #[serde(rename_all = "kebab-case")] |
6f422880 DM |
64 | #[repr(u8)] |
65 | /// Linux Bond Mode | |
66 | pub enum LinuxBondMode { | |
67 | /// Round-robin policy | |
a2055c38 | 68 | BalanceRr = 0, |
6f422880 | 69 | /// Active-backup policy |
a2055c38 | 70 | ActiveBackup = 1, |
6f422880 | 71 | /// XOR policy |
a2055c38 | 72 | BalanceXor = 2, |
6f422880 | 73 | /// Broadcast policy |
a2055c38 | 74 | Broadcast = 3, |
6f422880 DM |
75 | /// IEEE 802.3ad Dynamic link aggregation |
76 | #[serde(rename = "802.3ad")] | |
a2055c38 | 77 | Ieee802_3ad = 4, |
6f422880 | 78 | /// Adaptive transmit load balancing |
a2055c38 | 79 | BalanceTlb = 5, |
6f422880 | 80 | /// Adaptive load balancing |
a2055c38 WB |
81 | BalanceAlb = 6, |
82 | } | |
83 | ||
84 | impl fmt::Display for LinuxBondMode { | |
85 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
86 | f.write_str(match self { | |
87 | LinuxBondMode::BalanceRr => "balance-rr", | |
88 | LinuxBondMode::ActiveBackup => "active-backup", | |
89 | LinuxBondMode::BalanceXor => "balance-xor", | |
90 | LinuxBondMode::Broadcast => "broadcast", | |
91 | LinuxBondMode::Ieee802_3ad => "802.3ad", | |
92 | LinuxBondMode::BalanceTlb => "balance-tlb", | |
93 | LinuxBondMode::BalanceAlb => "balance-alb", | |
94 | }) | |
95 | } | |
6f422880 DM |
96 | } |
97 | ||
98 | #[api()] | |
f680e72f | 99 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] |
6f422880 | 100 | #[serde(rename_all = "kebab-case")] |
6f422880 DM |
101 | #[repr(u8)] |
102 | /// Bond Transmit Hash Policy for LACP (802.3ad) | |
103 | pub enum BondXmitHashPolicy { | |
104 | /// Layer 2 | |
a2055c38 | 105 | Layer2 = 0, |
6f422880 DM |
106 | /// Layer 2+3 |
107 | #[serde(rename = "layer2+3")] | |
a2055c38 | 108 | Layer2_3 = 1, |
6f422880 DM |
109 | /// Layer 3+4 |
110 | #[serde(rename = "layer3+4")] | |
a2055c38 WB |
111 | Layer3_4 = 2, |
112 | } | |
113 | ||
114 | impl fmt::Display for BondXmitHashPolicy { | |
115 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
116 | f.write_str(match self { | |
117 | BondXmitHashPolicy::Layer2 => "layer2", | |
118 | BondXmitHashPolicy::Layer2_3 => "layer2+3", | |
119 | BondXmitHashPolicy::Layer3_4 => "layer3+4", | |
120 | }) | |
121 | } | |
6f422880 DM |
122 | } |
123 | ||
124 | #[api()] | |
f680e72f | 125 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] |
6f422880 DM |
126 | #[serde(rename_all = "lowercase")] |
127 | /// Network interface type | |
128 | pub enum NetworkInterfaceType { | |
129 | /// Loopback | |
130 | Loopback, | |
131 | /// Physical Ethernet device | |
132 | Eth, | |
133 | /// Linux Bridge | |
134 | Bridge, | |
135 | /// Linux Bond | |
136 | Bond, | |
137 | /// Linux VLAN (eth.10) | |
138 | Vlan, | |
139 | /// Interface Alias (eth:1) | |
140 | Alias, | |
141 | /// Unknown interface type | |
142 | Unknown, | |
143 | } | |
144 | ||
145 | pub const NETWORK_INTERFACE_NAME_SCHEMA: Schema = StringSchema::new("Network interface name.") | |
146 | .format(&NETWORK_INTERFACE_FORMAT) | |
147 | .min_length(1) | |
f7fde5c8 | 148 | .max_length(15) // libc::IFNAMSIZ-1 |
6f422880 DM |
149 | .schema(); |
150 | ||
b22d785c TL |
151 | pub const NETWORK_INTERFACE_ARRAY_SCHEMA: Schema = |
152 | ArraySchema::new("Network interface list.", &NETWORK_INTERFACE_NAME_SCHEMA).schema(); | |
6f422880 | 153 | |
b22d785c TL |
154 | pub const NETWORK_INTERFACE_LIST_SCHEMA: Schema = |
155 | StringSchema::new("A list of network devices, comma separated.") | |
156 | .format(&ApiStringFormat::PropertyString( | |
157 | &NETWORK_INTERFACE_ARRAY_SCHEMA, | |
158 | )) | |
159 | .schema(); | |
6f422880 DM |
160 | |
161 | #[api( | |
162 | properties: { | |
163 | name: { | |
164 | schema: NETWORK_INTERFACE_NAME_SCHEMA, | |
165 | }, | |
166 | "type": { | |
167 | type: NetworkInterfaceType, | |
168 | }, | |
169 | method: { | |
170 | type: NetworkConfigMethod, | |
171 | optional: true, | |
172 | }, | |
173 | method6: { | |
174 | type: NetworkConfigMethod, | |
175 | optional: true, | |
176 | }, | |
177 | cidr: { | |
178 | schema: CIDR_V4_SCHEMA, | |
179 | optional: true, | |
180 | }, | |
181 | cidr6: { | |
182 | schema: CIDR_V6_SCHEMA, | |
183 | optional: true, | |
184 | }, | |
185 | gateway: { | |
186 | schema: IP_V4_SCHEMA, | |
187 | optional: true, | |
188 | }, | |
189 | gateway6: { | |
190 | schema: IP_V6_SCHEMA, | |
191 | optional: true, | |
192 | }, | |
193 | options: { | |
194 | description: "Option list (inet)", | |
195 | type: Array, | |
196 | items: { | |
197 | description: "Optional attribute line.", | |
198 | type: String, | |
199 | }, | |
200 | }, | |
201 | options6: { | |
202 | description: "Option list (inet6)", | |
203 | type: Array, | |
204 | items: { | |
205 | description: "Optional attribute line.", | |
206 | type: String, | |
207 | }, | |
208 | }, | |
209 | comments: { | |
210 | description: "Comments (inet, may span multiple lines)", | |
211 | type: String, | |
212 | optional: true, | |
213 | }, | |
214 | comments6: { | |
215 | description: "Comments (inet6, may span multiple lines)", | |
216 | type: String, | |
217 | optional: true, | |
218 | }, | |
219 | bridge_ports: { | |
220 | schema: NETWORK_INTERFACE_ARRAY_SCHEMA, | |
221 | optional: true, | |
222 | }, | |
223 | slaves: { | |
224 | schema: NETWORK_INTERFACE_ARRAY_SCHEMA, | |
225 | optional: true, | |
226 | }, | |
227 | bond_mode: { | |
228 | type: LinuxBondMode, | |
229 | optional: true, | |
230 | }, | |
231 | "bond-primary": { | |
232 | schema: NETWORK_INTERFACE_NAME_SCHEMA, | |
233 | optional: true, | |
234 | }, | |
235 | bond_xmit_hash_policy: { | |
236 | type: BondXmitHashPolicy, | |
237 | optional: true, | |
238 | }, | |
239 | } | |
240 | )] | |
241 | #[derive(Debug, Serialize, Deserialize)] | |
242 | /// Network Interface configuration | |
243 | pub struct Interface { | |
244 | /// Autostart interface | |
245 | #[serde(rename = "autostart")] | |
246 | pub autostart: bool, | |
247 | /// Interface is active (UP) | |
248 | pub active: bool, | |
249 | /// Interface name | |
250 | pub name: String, | |
251 | /// Interface type | |
252 | #[serde(rename = "type")] | |
253 | pub interface_type: NetworkInterfaceType, | |
b22d785c | 254 | #[serde(skip_serializing_if = "Option::is_none")] |
6f422880 | 255 | pub method: Option<NetworkConfigMethod>, |
b22d785c | 256 | #[serde(skip_serializing_if = "Option::is_none")] |
6f422880 | 257 | pub method6: Option<NetworkConfigMethod>, |
b22d785c | 258 | #[serde(skip_serializing_if = "Option::is_none")] |
6f422880 DM |
259 | /// IPv4 address with netmask |
260 | pub cidr: Option<String>, | |
b22d785c | 261 | #[serde(skip_serializing_if = "Option::is_none")] |
6f422880 DM |
262 | /// IPv4 gateway |
263 | pub gateway: Option<String>, | |
b22d785c | 264 | #[serde(skip_serializing_if = "Option::is_none")] |
6f422880 DM |
265 | /// IPv6 address with netmask |
266 | pub cidr6: Option<String>, | |
b22d785c | 267 | #[serde(skip_serializing_if = "Option::is_none")] |
6f422880 DM |
268 | /// IPv6 gateway |
269 | pub gateway6: Option<String>, | |
270 | ||
b22d785c | 271 | #[serde(skip_serializing_if = "Vec::is_empty")] |
6f422880 | 272 | pub options: Vec<String>, |
b22d785c | 273 | #[serde(skip_serializing_if = "Vec::is_empty")] |
6f422880 DM |
274 | pub options6: Vec<String>, |
275 | ||
b22d785c | 276 | #[serde(skip_serializing_if = "Option::is_none")] |
6f422880 | 277 | pub comments: Option<String>, |
b22d785c | 278 | #[serde(skip_serializing_if = "Option::is_none")] |
6f422880 DM |
279 | pub comments6: Option<String>, |
280 | ||
b22d785c | 281 | #[serde(skip_serializing_if = "Option::is_none")] |
6f422880 DM |
282 | /// Maximum Transmission Unit |
283 | pub mtu: Option<u64>, | |
284 | ||
b22d785c | 285 | #[serde(skip_serializing_if = "Option::is_none")] |
6f422880 DM |
286 | pub bridge_ports: Option<Vec<String>>, |
287 | /// Enable bridge vlan support. | |
b22d785c | 288 | #[serde(skip_serializing_if = "Option::is_none")] |
6f422880 DM |
289 | pub bridge_vlan_aware: Option<bool>, |
290 | ||
b22d785c | 291 | #[serde(skip_serializing_if = "Option::is_none")] |
6f422880 | 292 | pub slaves: Option<Vec<String>>, |
b22d785c | 293 | #[serde(skip_serializing_if = "Option::is_none")] |
6f422880 | 294 | pub bond_mode: Option<LinuxBondMode>, |
b22d785c | 295 | #[serde(skip_serializing_if = "Option::is_none")] |
6f422880 DM |
296 | #[serde(rename = "bond-primary")] |
297 | pub bond_primary: Option<String>, | |
298 | pub bond_xmit_hash_policy: Option<BondXmitHashPolicy>, | |
299 | } | |
300 | ||
301 | impl Interface { | |
302 | pub fn new(name: String) -> Self { | |
b22d785c | 303 | Self { |
6f422880 DM |
304 | name, |
305 | interface_type: NetworkInterfaceType::Unknown, | |
306 | autostart: false, | |
307 | active: false, | |
308 | method: None, | |
309 | method6: None, | |
310 | cidr: None, | |
311 | gateway: None, | |
312 | cidr6: None, | |
313 | gateway6: None, | |
314 | options: Vec::new(), | |
315 | options6: Vec::new(), | |
316 | comments: None, | |
317 | comments6: None, | |
318 | mtu: None, | |
319 | bridge_ports: None, | |
320 | bridge_vlan_aware: None, | |
321 | slaves: None, | |
322 | bond_mode: None, | |
323 | bond_primary: None, | |
324 | bond_xmit_hash_policy: None, | |
325 | } | |
326 | } | |
327 | } |