From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 3CF869183C for ; Thu, 4 Apr 2024 12:01:53 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id EC90536787 for ; Thu, 4 Apr 2024 12:00:54 +0200 (CEST) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS for ; Thu, 4 Apr 2024 12:00:53 +0200 (CEST) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id DF14845281 for ; Thu, 4 Apr 2024 12:00:50 +0200 (CEST) From: Stefan Lendl To: pbs-devel@lists.proxmox.com Date: Thu, 4 Apr 2024 12:00:32 +0200 Message-ID: <20240404100036.188225-6-s.lendl@proxmox.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240404100036.188225-1-s.lendl@proxmox.com> References: <20240404100036.188225-1-s.lendl@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.022 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pbs-devel] [PATCH proxmox-backup v3 5/9] config: parse vlan interface from config X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Apr 2024 10:01:53 -0000 Support three types of vlan configurations defined in interfaces, conforming to the PVE configurations: iface nic. inet iface vlan inet vlan-raw-device iface inet vlan-id vlan-raw-device * Add lexer Token enum variants for vlan-id and vlan-raw-device and parse them in parse_iface_attributes. * Add tests to verify this works in the above scenarios Signed-off-by: Stefan Lendl Tested-by: Lukas Wagner Reviewed-by: Lukas Wagner --- pbs-config/src/network/lexer.rs | 6 ++ pbs-config/src/network/parser.rs | 97 +++++++++++++++++++++++++++++++- 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/pbs-config/src/network/lexer.rs b/pbs-config/src/network/lexer.rs index fd23e3d8..d0b7d8cd 100644 --- a/pbs-config/src/network/lexer.rs +++ b/pbs-config/src/network/lexer.rs @@ -24,6 +24,8 @@ pub enum Token { MTU, BridgePorts, BridgeVlanAware, + VlanId, + VlanRawDevice, BondSlaves, BondMode, BondPrimary, @@ -50,6 +52,10 @@ lazy_static! { map.insert("bridge_ports", Token::BridgePorts); map.insert("bridge-vlan-aware", Token::BridgeVlanAware); map.insert("bridge_vlan_aware", Token::BridgeVlanAware); + map.insert("vlan-id", Token::VlanId); + map.insert("vlan_id", Token::VlanId); + map.insert("vlan-raw-device", Token::VlanRawDevice); + map.insert("vlan_raw_device", Token::VlanRawDevice); map.insert("bond-slaves", Token::BondSlaves); map.insert("bond_slaves", Token::BondSlaves); map.insert("bond-mode", Token::BondMode); diff --git a/pbs-config/src/network/parser.rs b/pbs-config/src/network/parser.rs index 1b55569a..796e9308 100644 --- a/pbs-config/src/network/parser.rs +++ b/pbs-config/src/network/parser.rs @@ -361,6 +361,20 @@ impl NetworkParser { interface.bond_xmit_hash_policy = Some(policy); self.eat(Token::Newline)?; } + Token::VlanId => { + self.eat(Token::VlanId)?; + let vlan_id = self.next_text()?.parse()?; + interface.vlan_id = Some(vlan_id); + set_interface_type(interface, NetworkInterfaceType::Vlan)?; + self.eat(Token::Newline)?; + } + Token::VlanRawDevice => { + self.eat(Token::VlanRawDevice)?; + let vlan_raw_device = self.next_text()?; + interface.vlan_raw_device = Some(vlan_raw_device); + set_interface_type(interface, NetworkInterfaceType::Vlan)?; + self.eat(Token::Newline)?; + } _ => { // parse addon attributes let option = self.parse_to_eol()?; @@ -522,7 +536,7 @@ impl NetworkParser { lazy_static! { static ref INTERFACE_ALIAS_REGEX: Regex = Regex::new(r"^\S+:\d+$").unwrap(); - static ref VLAN_INTERFACE_REGEX: Regex = Regex::new(r"^\S+\.\d+$").unwrap(); + static ref VLAN_INTERFACE_REGEX: Regex = Regex::new(r"^\S+\.\d+|vlan\d+$").unwrap(); } if let Some(existing_interfaces) = existing_interfaces { @@ -748,4 +762,85 @@ mod test { Ok(()) } + + #[test] + fn test_network_config_parser_vlan_id_in_name() { + let input = "iface vmbr0.100 inet static manual"; + let mut parser = NetworkParser::new(input.as_bytes()); + let config = parser.parse_interfaces(None).unwrap(); + + let iface = config.interfaces.get("vmbr0.100").unwrap(); + assert_eq!(iface.interface_type, NetworkInterfaceType::Vlan); + assert_eq!(iface.vlan_raw_device, None); + assert_eq!(iface.vlan_id, None); + } + + #[test] + fn test_network_config_parser_vlan_with_raw_device() { + let input = r#" +iface vlan100 inet manual + vlan-raw-device vmbr0"#; + + let mut parser = NetworkParser::new(input.as_bytes()); + let config = parser.parse_interfaces(None).unwrap(); + + let iface = config.interfaces.get("vlan100").unwrap(); + assert_eq!(iface.interface_type, NetworkInterfaceType::Vlan); + assert_eq!(iface.vlan_raw_device, Some(String::from("vmbr0"))); + assert_eq!(iface.vlan_id, None); + } + + #[test] + fn test_network_config_parser_vlan_with_raw_device_static() { + let input = r#" +iface vlan100 inet static + vlan-raw-device vmbr0 + address 10.0.0.100/16"#; + + let mut parser = NetworkParser::new(input.as_bytes()); + let config = parser.parse_interfaces(None).unwrap(); + + let iface = config.interfaces.get("vlan100").unwrap(); + assert_eq!(iface.interface_type, NetworkInterfaceType::Vlan); + assert_eq!(iface.vlan_raw_device, Some(String::from("vmbr0"))); + assert_eq!(iface.vlan_id, None); + assert_eq!(iface.method, Some(NetworkConfigMethod::Static)); + assert_eq!(iface.cidr, Some(String::from("10.0.0.100/16"))); + } + + #[test] + fn test_network_config_parser_vlan_individual_name() { + let input = r#" +iface individual_name inet manual + vlan-id 100 + vlan-raw-device vmbr0"#; + + let mut parser = NetworkParser::new(input.as_bytes()); + let config = parser.parse_interfaces(None).unwrap(); + + let iface = config.interfaces.get("individual_name").unwrap(); + assert_eq!(iface.interface_type, NetworkInterfaceType::Vlan); + assert_eq!(iface.vlan_raw_device, Some(String::from("vmbr0"))); + assert_eq!(iface.vlan_id, Some(100)); + } + + #[test] + fn test_network_config_parser_vlan_individual_name_static() { + let input = r#" +iface individual_name inet static + vlan-id 100 + vlan-raw-device vmbr0 + address 10.0.0.100/16 +"#; + + let mut parser = NetworkParser::new(input.as_bytes()); + let config = parser.parse_interfaces(None).unwrap(); + + let iface = config.interfaces.get("individual_name").unwrap(); + assert_eq!(iface.interface_type, NetworkInterfaceType::Vlan); + assert_eq!(iface.vlan_raw_device, Some(String::from("vmbr0"))); + assert_eq!(iface.vlan_id, Some(100)); + assert_eq!(iface.method, Some(NetworkConfigMethod::Static)); + assert_eq!(iface.cidr, Some(String::from("10.0.0.100/16"))); + } } -- 2.44.0