fix #2942: implement lacp bond mode and bond_xmit_hash_policy
this was not yet implemented, should be compatible with pve and the gui Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
		
				
					committed by
					
						 Dietmar Maurer
						Dietmar Maurer
					
				
			
			
				
	
			
			
			
						parent
						
							85959a99ea
						
					
				
				
					commit
					8f2f3dd710
				
			| @ -202,6 +202,10 @@ pub fn read_interface(iface: String) -> Result<Value, Error> { | ||||
|                 schema: NETWORK_INTERFACE_NAME_SCHEMA, | ||||
|                 optional: true, | ||||
|             }, | ||||
|             bond_xmit_hash_policy: { | ||||
|                 type: BondXmitHashPolicy, | ||||
|                 optional: true, | ||||
|             }, | ||||
|             slaves: { | ||||
|                 schema: NETWORK_INTERFACE_LIST_SCHEMA, | ||||
|                 optional: true, | ||||
| @ -229,6 +233,7 @@ pub fn create_interface( | ||||
|     bridge_vlan_aware: Option<bool>, | ||||
|     bond_mode: Option<LinuxBondMode>, | ||||
|     bond_primary: Option<String>, | ||||
|     bond_xmit_hash_policy: Option<BondXmitHashPolicy>, | ||||
|     slaves: Option<String>, | ||||
|     param: Value, | ||||
| ) -> Result<(), Error> { | ||||
| @ -297,6 +302,14 @@ pub fn create_interface( | ||||
|                     } | ||||
|                     interface.bond_primary = bond_primary; | ||||
|                 } | ||||
|                 if bond_xmit_hash_policy.is_some() { | ||||
|                     if mode != LinuxBondMode::ieee802_3ad && | ||||
|                        mode != LinuxBondMode::balance_xor | ||||
|                     { | ||||
|                         bail!("bond_xmit_hash_policy is only valid with LACP(802.3ad) or balance-xor mode"); | ||||
|                     } | ||||
|                     interface.bond_xmit_hash_policy = bond_xmit_hash_policy; | ||||
|                 } | ||||
|             } | ||||
|             if let Some(slaves) = slaves { | ||||
|                 let slaves = split_interface_list(&slaves)?; | ||||
| @ -359,6 +372,8 @@ pub enum DeletableProperty { | ||||
|     /// Delete bond-primary | ||||
|     #[serde(rename = "bond-primary")] | ||||
|     bond_primary, | ||||
|     /// Delete bond transmit hash policy | ||||
|     bond_xmit_hash_policy, | ||||
| } | ||||
|  | ||||
|  | ||||
| @ -440,6 +455,10 @@ pub enum DeletableProperty { | ||||
|                 schema: NETWORK_INTERFACE_NAME_SCHEMA, | ||||
|                 optional: true, | ||||
|             }, | ||||
|             bond_xmit_hash_policy: { | ||||
|                 type: BondXmitHashPolicy, | ||||
|                 optional: true, | ||||
|             }, | ||||
|             slaves: { | ||||
|                 schema: NETWORK_INTERFACE_LIST_SCHEMA, | ||||
|                 optional: true, | ||||
| @ -479,6 +498,7 @@ pub fn update_interface( | ||||
|     bridge_vlan_aware: Option<bool>, | ||||
|     bond_mode: Option<LinuxBondMode>, | ||||
|     bond_primary: Option<String>, | ||||
|     bond_xmit_hash_policy: Option<BondXmitHashPolicy>, | ||||
|     slaves: Option<String>, | ||||
|     delete: Option<Vec<DeletableProperty>>, | ||||
|     digest: Option<String>, | ||||
| @ -523,6 +543,7 @@ pub fn update_interface( | ||||
|                 DeletableProperty::bridge_vlan_aware => { interface.bridge_vlan_aware = None; } | ||||
|                 DeletableProperty::slaves => { interface.set_bond_slaves(Vec::new())?; } | ||||
|                 DeletableProperty::bond_primary => { interface.bond_primary = None; } | ||||
|                 DeletableProperty::bond_xmit_hash_policy => { interface.bond_xmit_hash_policy = None } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @ -548,6 +569,14 @@ pub fn update_interface( | ||||
|             } | ||||
|             interface.bond_primary = bond_primary; | ||||
|         } | ||||
|         if bond_xmit_hash_policy.is_some() { | ||||
|             if mode != LinuxBondMode::ieee802_3ad && | ||||
|                mode != LinuxBondMode::balance_xor | ||||
|             { | ||||
|                 bail!("bond_xmit_hash_policy is only valid with LACP(802.3ad) or balance-xor mode"); | ||||
|             } | ||||
|             interface.bond_xmit_hash_policy = bond_xmit_hash_policy; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if let Some(cidr) = cidr { | ||||
|  | ||||
| @ -699,7 +699,7 @@ pub enum LinuxBondMode { | ||||
|     /// Broadcast policy | ||||
|     broadcast = 3, | ||||
|     /// IEEE 802.3ad Dynamic link aggregation | ||||
|     //#[serde(rename = "802.3ad")] | ||||
|     #[serde(rename = "802.3ad")] | ||||
|     ieee802_3ad = 4, | ||||
|     /// Adaptive transmit load balancing | ||||
|     balance_tlb = 5, | ||||
| @ -707,6 +707,23 @@ pub enum LinuxBondMode { | ||||
|     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")] | ||||
| @ -817,6 +834,10 @@ pub const NETWORK_INTERFACE_LIST_SCHEMA: Schema = StringSchema::new( | ||||
|             schema: NETWORK_INTERFACE_NAME_SCHEMA, | ||||
|             optional: true, | ||||
|         }, | ||||
|         bond_xmit_hash_policy: { | ||||
|             type: BondXmitHashPolicy, | ||||
|             optional: true, | ||||
|         }, | ||||
|     } | ||||
| )] | ||||
| #[derive(Debug, Serialize, Deserialize)] | ||||
| @ -876,6 +897,7 @@ pub struct Interface { | ||||
|     #[serde(skip_serializing_if="Option::is_none")] | ||||
|     #[serde(rename = "bond-primary")] | ||||
|     pub bond_primary: Option<String>, | ||||
|     pub bond_xmit_hash_policy: Option<BondXmitHashPolicy>, | ||||
| } | ||||
|  | ||||
| // Regression tests | ||||
|  | ||||
| @ -17,7 +17,7 @@ pub use lexer::*; | ||||
| mod parser; | ||||
| pub use parser::*; | ||||
|  | ||||
| use crate::api2::types::{Interface, NetworkConfigMethod, NetworkInterfaceType, LinuxBondMode}; | ||||
| use crate::api2::types::{Interface, NetworkConfigMethod, NetworkInterfaceType, LinuxBondMode, BondXmitHashPolicy}; | ||||
|  | ||||
| lazy_static!{ | ||||
|     static ref PHYSICAL_NIC_REGEX: Regex = Regex::new(r"^(?:eth\d+|en[^:.]+|ib\d+)$").unwrap(); | ||||
| @ -44,6 +44,19 @@ pub fn bond_mode_to_str(mode: LinuxBondMode) -> &'static str { | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub fn bond_xmit_hash_policy_from_str(s: &str) -> Result<BondXmitHashPolicy, Error> { | ||||
|     BondXmitHashPolicy::deserialize(s.into_deserializer()) | ||||
|         .map_err(|_: value::Error| format_err!("invalid bond_xmit_hash_policy '{}'", s)) | ||||
| } | ||||
|  | ||||
| pub fn bond_xmit_hash_policy_to_str(policy: &BondXmitHashPolicy) -> &'static str { | ||||
|     match policy { | ||||
|         BondXmitHashPolicy::layer2 => "layer2", | ||||
|         BondXmitHashPolicy::layer2_3 => "layer2+3", | ||||
|         BondXmitHashPolicy::layer3_4 => "layer3+4", | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Interface { | ||||
|  | ||||
|     pub fn new(name: String) -> Self { | ||||
| @ -68,6 +81,7 @@ impl Interface { | ||||
|             slaves: None, | ||||
|             bond_mode: None, | ||||
|             bond_primary: None, | ||||
|             bond_xmit_hash_policy: None, | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -176,6 +190,14 @@ impl Interface { | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 if let Some(xmit_policy) = &self.bond_xmit_hash_policy { | ||||
|                     if mode == LinuxBondMode::ieee802_3ad || | ||||
|                        mode == LinuxBondMode::balance_xor | ||||
|                     { | ||||
|                         writeln!(w, "\tbond_xmit_hash_policy {}", bond_xmit_hash_policy_to_str(xmit_policy))?; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 let slaves = self.slaves.as_ref().unwrap_or(&EMPTY_LIST); | ||||
|                 if slaves.is_empty() { | ||||
|                     writeln!(w, "\tbond-slaves none")?; | ||||
|  | ||||
| @ -27,6 +27,7 @@ pub enum Token { | ||||
|     BondSlaves, | ||||
|     BondMode, | ||||
|     BondPrimary, | ||||
|     BondXmitHashPolicy, | ||||
|     EOF, | ||||
| } | ||||
|  | ||||
| @ -54,6 +55,8 @@ lazy_static! { | ||||
|         map.insert("bond-mode", Token::BondMode); | ||||
|         map.insert("bond-primary", Token::BondPrimary); | ||||
|         map.insert("bond_primary", Token::BondPrimary); | ||||
|         map.insert("bond_xmit_hash_policy", Token::BondXmitHashPolicy); | ||||
|         map.insert("bond-xmit-hash-policy", Token::BondXmitHashPolicy); | ||||
|         map | ||||
|     }; | ||||
| } | ||||
|  | ||||
| @ -9,7 +9,7 @@ use regex::Regex; | ||||
| use super::helper::*; | ||||
| use super::lexer::*; | ||||
|  | ||||
| use super::{NetworkConfig, NetworkOrderEntry, Interface, NetworkConfigMethod, NetworkInterfaceType, bond_mode_from_str}; | ||||
| use super::{NetworkConfig, NetworkOrderEntry, Interface, NetworkConfigMethod, NetworkInterfaceType, bond_mode_from_str, bond_xmit_hash_policy_from_str}; | ||||
|  | ||||
| pub struct NetworkParser<R: BufRead> { | ||||
|     input: Peekable<Lexer<R>>, | ||||
| @ -249,6 +249,12 @@ impl <R: BufRead> NetworkParser<R> { | ||||
|                     interface.bond_primary = Some(primary); | ||||
|                     self.eat(Token::Newline)?; | ||||
|                 } | ||||
|                 Token::BondXmitHashPolicy => { | ||||
|                     self.eat(Token::BondXmitHashPolicy)?; | ||||
|                     let policy = bond_xmit_hash_policy_from_str(&self.next_text()?)?; | ||||
|                     interface.bond_xmit_hash_policy = Some(policy); | ||||
|                     self.eat(Token::Newline)?; | ||||
|                 } | ||||
|                 Token::Netmask => bail!("netmask is deprecated and no longer supported"), | ||||
|  | ||||
|                 _ => { // parse addon attributes | ||||
|  | ||||
		Reference in New Issue
	
	Block a user