diff --git a/src/api2/types.rs b/src/api2/types.rs index c53ef967..b5e8ad41 100644 --- a/src/api2/types.rs +++ b/src/api2/types.rs @@ -550,6 +550,10 @@ pub const NETWORK_INTERFACE_NAME_SCHEMA: Schema = StringSchema::new("Network int .max_length(libc::IFNAMSIZ-1) .schema(); +pub const NETWORK_INTERFACE_LIST_SCHEMA: Schema = ArraySchema::new( + "Network interface list.", &NETWORK_INTERFACE_NAME_SCHEMA) + .schema(); + #[api( properties: { name: { @@ -582,6 +586,10 @@ pub const NETWORK_INTERFACE_NAME_SCHEMA: Schema = StringSchema::new("Network int type: String, }, }, + bridge_ports: { + schema: NETWORK_INTERFACE_LIST_SCHEMA, + optional: true, + }, } )] #[derive(Debug, Serialize, Deserialize)] @@ -620,6 +628,9 @@ pub struct Interface { #[serde(skip_serializing_if="Option::is_none")] /// Maximum Transmission Unit pub mtu: Option, + + #[serde(skip_serializing_if="Option::is_none")] + pub bridge_ports: Option>, } // Regression tests diff --git a/src/config/network.rs b/src/config/network.rs index 3e7f349d..0d3490d9 100644 --- a/src/config/network.rs +++ b/src/config/network.rs @@ -33,6 +33,7 @@ impl Interface { options_v4: Vec::new(), options_v6: Vec::new(), mtu: None, + bridge_ports: None, } } @@ -100,9 +101,24 @@ impl Interface { /// Write attributes not dependening on address family fn write_iface_attributes(&self, w: &mut dyn Write) -> Result<(), Error> { + + match self.interface_type { + NetworkInterfaceType::Bridge => { + if let Some(ref ports) = self.bridge_ports { + if ports.is_empty() { + writeln!(w, " bridge-ports none")?; + } else { + writeln!(w, " bridge-ports {}", ports.join(" "))?; + } + } + } + _ => {} + } + if let Some(mtu) = self.mtu { writeln!(w, " mtu {}", mtu)?; } + Ok(()) } @@ -161,6 +177,7 @@ impl Interface { gateway_v4: _gateway_v4, gateway_v6: _gateway_v6, mtu: _mtu, + bridge_ports: _bridge_ports, } => { method_v4 == method_v6 && options_v4.is_empty() diff --git a/src/config/network/lexer.rs b/src/config/network/lexer.rs index 93d3b36f..0ec8fb5a 100644 --- a/src/config/network/lexer.rs +++ b/src/config/network/lexer.rs @@ -22,6 +22,7 @@ pub enum Token { Static, Attribute, MTU, + BridgePorts, EOF, } @@ -40,6 +41,8 @@ lazy_static! { map.insert("netmask", Token::Netmask); map.insert("static", Token::Static); map.insert("mtu", Token::MTU); + map.insert("bridge-ports", Token::BridgePorts); + map.insert("bridge_ports", Token::BridgePorts); map }; } diff --git a/src/config/network/parser.rs b/src/config/network/parser.rs index cf6928c5..0cb47670 100644 --- a/src/config/network/parser.rs +++ b/src/config/network/parser.rs @@ -156,6 +156,24 @@ impl NetworkParser { Ok(()) } + fn parse_iface_list(&mut self) -> Result, Error> { + let mut list = Vec::new(); + + loop { + let (token, text) = self.next()?; + match token { + Token::Newline => break, + Token::Text => { + if &text != "none" { + list.push(text); + } + } + _ => bail!("unable to parse interface list - unexpected token '{:?}'", token), + } + } + + Ok(list) + } fn parse_iface_attributes(&mut self, interface: &mut Interface) -> Result<(), Error> { loop { @@ -172,6 +190,12 @@ impl NetworkParser { let mtu = self.parse_iface_mtu()?; interface.mtu = Some(mtu); } + Token::BridgePorts => { + self.eat(Token::BridgePorts)?; + let ports = self.parse_iface_list()?; + interface.bridge_ports = Some(ports); + interface.interface_type = NetworkInterfaceType::Bridge; + } Token::Netmask => bail!("netmask is deprecated and no longer supported"), _ => { self.parse_iface_addon_attribute(interface)?;