]> git.proxmox.com Git - proxmox-backup.git/commitdiff
src/config/network.rs: implement bond_mode
authorDietmar Maurer <dietmar@proxmox.com>
Thu, 7 May 2020 12:07:45 +0000 (14:07 +0200)
committerDietmar Maurer <dietmar@proxmox.com>
Thu, 7 May 2020 12:07:45 +0000 (14:07 +0200)
and rename bond_slaves to slaves to make it compatible with pve.

src/api2/node/network.rs
src/api2/types.rs
src/config/network.rs
src/config/network/lexer.rs
src/config/network/parser.rs

index a4c82f878ba5d2870e77b3780991c4c912f47203..796e52e8021fdfdece3fea60a334c966392c86dc 100644 (file)
@@ -187,7 +187,11 @@ pub fn read_interface(iface: String) -> Result<Value, Error> {
                type: bool,
                optional: true,
             },
-            bond_slaves: {
+            bond_mode: {
+                type: LinuxBondMode,
+                optional: true,
+            },
+            slaves: {
                 schema: NETWORK_INTERFACE_LIST_SCHEMA,
                 optional: true,
             },
@@ -212,7 +216,8 @@ pub fn create_interface(
     mtu: Option<u64>,
     bridge_ports: Option<Vec<String>>,
     bridge_vlan_aware: Option<bool>,
-    bond_slaves: Option<Vec<String>>,
+    bond_mode: Option<LinuxBondMode>,
+    slaves: Option<Vec<String>>,
     param: Value,
 ) -> Result<(), Error> {
 
@@ -269,7 +274,8 @@ pub fn create_interface(
             if bridge_vlan_aware.is_some() { interface.bridge_vlan_aware = bridge_vlan_aware; }
         }
         NetworkInterfaceType::Bond => {
-            if let Some(slaves) = bond_slaves { interface.set_bond_slaves(slaves)?; }
+            if bond_mode.is_some() { interface.bond_mode = bond_mode; }
+            if let Some(slaves) = slaves { interface.set_bond_slaves(slaves)?; }
         }
         _ => bail!("creating network interface type '{:?}' is not supported", interface_type),
     }
@@ -323,7 +329,7 @@ pub enum DeletableProperty {
     /// Delet bridge-vlan-aware flag
     bridge_vlan_aware,
     /// Delete bond-slaves (set to 'none')
-    bond_slaves,
+    slaves,
 }
 
 
@@ -397,7 +403,11 @@ pub enum DeletableProperty {
                type: bool,
                optional: true,
             },
-            bond_slaves: {
+            bond_mode: {
+                type: LinuxBondMode,
+                optional: true,
+            },
+            slaves: {
                 schema: NETWORK_INTERFACE_LIST_SCHEMA,
                 optional: true,
             },
@@ -434,7 +444,8 @@ pub fn update_interface(
     mtu: Option<u64>,
     bridge_ports: Option<Vec<String>>,
     bridge_vlan_aware: Option<bool>,
-    bond_slaves: Option<Vec<String>>,
+    bond_mode: Option<LinuxBondMode>,
+    slaves: Option<Vec<String>>,
     delete: Option<Vec<DeletableProperty>>,
     digest: Option<String>,
     param: Value,
@@ -476,7 +487,7 @@ pub fn update_interface(
                 DeletableProperty::autostart => { interface.autostart = false; },
                 DeletableProperty::bridge_ports => { interface.set_bridge_ports(Vec::new())?; }
                 DeletableProperty::bridge_vlan_aware => { interface.bridge_vlan_aware = None; }
-                DeletableProperty::bond_slaves => { interface.set_bond_slaves(Vec::new())?; }
+                DeletableProperty::slaves => { interface.set_bond_slaves(Vec::new())?; }
             }
         }
     }
@@ -487,7 +498,8 @@ pub fn update_interface(
     if mtu.is_some() { interface.mtu = mtu; }
     if let Some(ports) = bridge_ports { interface.set_bridge_ports(ports)?; }
     if bridge_vlan_aware.is_some() { interface.bridge_vlan_aware = bridge_vlan_aware; }
-    if let Some(slaves) = bond_slaves { interface.set_bond_slaves(slaves)?; }
+    if let Some(slaves) = slaves { interface.set_bond_slaves(slaves)?; }
+    if bond_mode.is_some() { interface.bond_mode = bond_mode; }
 
     if let Some(cidr) = cidr {
         let (_, _, is_v6) = network::parse_cidr(&cidr)?;
index 9278d9467b1b0a16c4672ac4641e97656425e8d9..f79e714d719b937b4fe2a420cf2af8cfd0a0c0a1 100644 (file)
@@ -549,6 +549,30 @@ pub enum NetworkConfigMethod {
     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 = "lowercase")]
@@ -642,10 +666,14 @@ pub const NETWORK_INTERFACE_LIST_SCHEMA: Schema = ArraySchema::new(
             schema: NETWORK_INTERFACE_LIST_SCHEMA,
             optional: true,
         },
-        bond_slaves: {
+        slaves: {
             schema: NETWORK_INTERFACE_LIST_SCHEMA,
             optional: true,
         },
+        bond_mode: {
+            type: LinuxBondMode,
+            optional: true,
+        }
     }
 )]
 #[derive(Debug, Serialize, Deserialize)]
@@ -699,7 +727,9 @@ pub struct Interface {
     pub bridge_vlan_aware: Option<bool>,
 
     #[serde(skip_serializing_if="Option::is_none")]
-    pub bond_slaves: Option<Vec<String>>,
+    pub slaves: Option<Vec<String>>,
+    #[serde(skip_serializing_if="Option::is_none")]
+    pub bond_mode: Option<LinuxBondMode>,
 }
 
 // Regression tests
index ef8bf73abf021752eaa357efb37ffe864dba1657..bba7ee660ef3ac7a358d6668695b094288c5f16c 100644 (file)
@@ -2,6 +2,7 @@ use std::io::{Write};
 use std::collections::{HashSet, HashMap};
 
 use anyhow::{Error, format_err, bail};
+use serde::de::{value, IntoDeserializer, Deserialize};
 
 use proxmox::tools::{fs::replace_file, fs::CreateOptions};
 
@@ -14,7 +15,24 @@ pub use lexer::*;
 mod parser;
 pub use parser::*;
 
-use crate::api2::types::{Interface, NetworkConfigMethod, NetworkInterfaceType};
+use crate::api2::types::{Interface, NetworkConfigMethod, NetworkInterfaceType, LinuxBondMode};
+
+pub fn bond_mode_from_str(s: &str) -> Result<LinuxBondMode, Error> {
+    LinuxBondMode::deserialize(s.into_deserializer())
+        .map_err(|_: value::Error| format_err!("invalid bond_mode '{}'", s))
+}
+
+pub fn bond_mode_to_str(mode: LinuxBondMode) -> &'static str {
+    match mode {
+        LinuxBondMode::balance_rr => "balance-rr",
+        LinuxBondMode::active_backup => "active-backup",
+        LinuxBondMode::balance_xor => "balance-xor",
+        LinuxBondMode::broadcast => "broadcast",
+        LinuxBondMode::ieee802_3ad => "802.3ad",
+        LinuxBondMode::balance_tlb => "balance-tlb",
+        LinuxBondMode::balance_alb => "balance-alb",
+    }
+}
 
 impl Interface {
 
@@ -37,7 +55,8 @@ impl Interface {
             mtu: None,
             bridge_ports: None,
             bridge_vlan_aware: None,
-            bond_slaves: None,
+            slaves: None,
+            bond_mode: None,
         }
     }
 
@@ -116,7 +135,7 @@ impl Interface {
         if self.interface_type != NetworkInterfaceType::Bond {
             bail!("interface '{}' is no bond (type is {:?})", self.name, self.interface_type);
         }
-        self.bond_slaves = Some(slaves);
+        self.slaves = Some(slaves);
         Ok(())
     }
 
@@ -137,7 +156,10 @@ impl Interface {
                 }
             }
             NetworkInterfaceType::Bond => {
-                if let Some(ref slaves) = self.bond_slaves {
+                let mode = self.bond_mode.unwrap_or(LinuxBondMode::balance_rr);
+                writeln!(w, "\tbond-mode {}", bond_mode_to_str(mode))?;
+
+                if let Some(ref slaves) = self.slaves {
                     if slaves.is_empty() {
                         writeln!(w, "\tbond-slaves none")?;
                     } else {
@@ -226,7 +248,8 @@ impl Interface {
                 mtu: _mtu,
                 bridge_ports: _bridge_ports,
                 bridge_vlan_aware: _bridge_vlan_aware,
-                bond_slaves: _bond_slaves,
+                slaves: _slaves,
+                bond_mode: _bond_mode,
             } => {
                 method == method6
                     && comments.is_none()
@@ -264,20 +287,20 @@ impl Interface {
             }
             return Ok(());
         }
-                    
+
         if let Some(method) = self.method {
             writeln!(w, "iface {} inet {}", self.name, method_to_str(method))?;
             self.write_iface_attributes_v4(w, method)?;
             self.write_iface_attributes(w)?;
             writeln!(w)?;
         }
-        
+
         if let Some(method6) = self.method6 {
             let mut skip_v6 = false; // avoid empty inet6 manual entry
             if self.method.is_some() && method6 == NetworkConfigMethod::Manual {
                 if self.comments6.is_none() && self.options6.is_empty() { skip_v6 = true; }
             }
-       
+
             if !skip_v6 {
                 writeln!(w, "iface {} inet6 {}", self.name, method_to_str(method6))?;
                 self.write_iface_attributes_v6(w, method6)?;
index d8a769b240d11da0326d13890e507ba3986ede1d..c050745f8c2c1989c640ca2820e47af62ad91ba8 100644 (file)
@@ -25,6 +25,7 @@ pub enum Token {
     BridgePorts,
     BridgeVlanAware,
     BondSlaves,
+    BondMode,
     EOF,
 }
 
@@ -49,6 +50,8 @@ lazy_static! {
         map.insert("bridge_vlan_aware", Token::BridgeVlanAware);
         map.insert("bond-slaves", Token::BondSlaves);
         map.insert("bond_slaves", Token::BondSlaves);
+        map.insert("bond-mode", Token::BondMode);
+        map.insert("bond_mode", Token::BondMode);
         map
     };
 }
index f9f950b47bad3c5763bef62989506e465e10c8a7..7684d7bc27a26315b237e02dd7d098d3d29188bf 100644 (file)
@@ -9,7 +9,7 @@ use regex::Regex;
 use super::helper::*;
 use super::lexer::*;
 
-use super::{NetworkConfig, NetworkOrderEntry, Interface, NetworkConfigMethod, NetworkInterfaceType};
+use super::{NetworkConfig, NetworkOrderEntry, Interface, NetworkConfigMethod, NetworkInterfaceType, bond_mode_from_str};
 
 pub struct NetworkParser<R: BufRead> {
     input: Peekable<Lexer<R>>,
@@ -236,9 +236,15 @@ impl <R: BufRead> NetworkParser<R> {
                 Token::BondSlaves => {
                     self.eat(Token::BondSlaves)?;
                     let slaves = self.parse_iface_list()?;
-                    interface.bond_slaves = Some(slaves);
+                    interface.slaves = Some(slaves);
                     interface.set_interface_type(NetworkInterfaceType::Bond)?;
                 }
+                Token::BondMode => {
+                    self.eat(Token::BondMode)?;
+                    let mode = self.next_text()?;
+                    interface.bond_mode = Some(bond_mode_from_str(&mode)?);
+                    self.eat(Token::Newline)?;
+                }
                 Token::Netmask => bail!("netmask is deprecated and no longer supported"),
 
                 _ => { // parse addon attributes