[pbs-devel] [PATCH proxmox-backup 04/10] config: parse vlan interface from config
Stefan Lendl
s.lendl at proxmox.com
Thu Jan 11 16:53:01 CET 2024
Support three types of vlan configurations defined in interfaces
conforming to the PVE configurations:
iface nic.<vlan-id> inet
iface vlan<vlan-id> inet
vlan-raw-device <nic>
iface <arbitraty-name> inet
vlan-id <vlan-id>
vlan-raw-device <nic>
* 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 <s.lendl at proxmox.com>
---
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 d31e5c2e..5a83e192 100644
--- a/pbs-config/src/network/parser.rs
+++ b/pbs-config/src/network/parser.rs
@@ -361,6 +361,20 @@ impl<R: BufRead> NetworkParser<R> {
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<R: BufRead> NetworkParser<R> {
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.42.0
More information about the pbs-devel
mailing list