src/config/network.rs: simplify code

This commit is contained in:
Dietmar Maurer 2020-04-20 18:10:15 +02:00
parent f34d4401f7
commit 92310d585c
2 changed files with 82 additions and 103 deletions

View File

@ -4,7 +4,7 @@ use std::collections::{HashSet, HashMap};
use anyhow::{Error, bail}; use anyhow::{Error, bail};
mod helper; mod helper;
//pub use helper::*; pub use helper::*;
mod lexer; mod lexer;
pub use lexer::*; pub use lexer::*;
@ -12,19 +12,19 @@ pub use lexer::*;
mod parser; mod parser;
pub use parser::*; pub use parser::*;
#[derive(Debug, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq)]
pub enum AddressFamily { pub enum ConfigMethod {
Inet4and6, // both v4 and v6 Manual,
Inet, // v4 Static,
Inet6, // v6 DHCP,
Loopback,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Interface { pub struct Interface {
pub name: String, pub name: String,
pub address_family: AddressFamily, pub method_v4: Option<ConfigMethod>,
pub method_v4: Option<Token>, pub method_v6: Option<ConfigMethod>,
pub method_v6: Option<Token>,
pub address_v4: Option<String>, pub address_v4: Option<String>,
pub gateway_v4: Option<String>, pub gateway_v4: Option<String>,
pub netmask_v4: Option<u8>, pub netmask_v4: Option<u8>,
@ -37,25 +37,11 @@ pub struct Interface {
impl Interface { impl Interface {
pub fn new( pub fn new(name: String) -> Self {
name: String, Self {
address_family: AddressFamily,
config_method: Option<Token>,
) -> Self {
let config_method_v4 = match address_family {
AddressFamily::Inet | AddressFamily::Inet4and6 => Some(config_method.unwrap_or(Token::Static)),
_ => None,
};
let config_method_v6 = match address_family {
AddressFamily::Inet6 | AddressFamily::Inet4and6 => Some(config_method.unwrap_or(Token::Static)),
_ => None,
};
Self {
name, name,
address_family, method_v4: None,
method_v4: config_method_v4, method_v6: None,
method_v6: config_method_v6,
address_v4: None, address_v4: None,
gateway_v4: None, gateway_v4: None,
netmask_v4: None, netmask_v4: None,
@ -67,6 +53,24 @@ impl Interface {
} }
} }
fn set_method_v4(&mut self, method: ConfigMethod) -> Result<(), Error> {
if self.method_v4.is_none() {
self.method_v4 = Some(method);
} else {
bail!("inet configuration method already set.");
}
Ok(())
}
fn set_method_v6(&mut self, method: ConfigMethod) -> Result<(), Error> {
if self.method_v6.is_none() {
self.method_v6 = Some(method);
} else {
bail!("inet6 configuration method already set.");
}
Ok(())
}
fn set_address_v4(&mut self, address: String) -> Result<(), Error> { fn set_address_v4(&mut self, address: String) -> Result<(), Error> {
if self.address_v4.is_none() { if self.address_v4.is_none() {
self.address_v4 = Some(address); self.address_v4 = Some(address);
@ -130,12 +134,12 @@ impl Interface {
} }
fn push_addon_option(&mut self, text: String) { fn push_addon_option(&mut self, text: String) {
match self.address_family { if self.method_v4.is_none() && self.method_v6.is_some() {
AddressFamily::Inet | AddressFamily::Inet4and6 => self.options_v4.push(text), self.options_v6.push(text);
AddressFamily::Inet6 => self.options_v6.push(text), } else {
self.options_v4.push(text);
} }
} }
} }
#[derive(Debug)] #[derive(Debug)]
@ -164,18 +168,12 @@ impl NetworkConfig {
pub fn write_config(&self, w: &mut dyn Write) -> Result<(), Error> { pub fn write_config(&self, w: &mut dyn Write) -> Result<(), Error> {
fn method_to_str(method: &Option<Token>) -> &str { fn method_to_str(method: ConfigMethod) -> &'static str {
match method { match method {
None => "static", ConfigMethod::Static => "static",
Some(method) => { ConfigMethod::Loopback => "loopback",
match method { ConfigMethod::Manual => "manual",
Token::Static => "static", ConfigMethod::DHCP => "dhcp",
Token::Loopback => "loopback",
Token::Manual => "manual",
Token::DHCP => "dhcp",
_ => unreachable!(),
}
}
} }
} }
@ -220,28 +218,23 @@ impl NetworkConfig {
writeln!(w, "auto {}", name)?; writeln!(w, "auto {}", name)?;
} }
if interface.address_family == AddressFamily::Inet4and6 && interface.method_v4 == interface.method_v6 { if interface.method_v4 == interface.method_v6 {
writeln!(w, "iface {} {}", name, method_to_str(&interface.method_v4))?; let method = interface.method_v4.unwrap_or(ConfigMethod::Static);
writeln!(w, "iface {} {}", name, method_to_str(method))?;
write_attributes_v4(w, &interface)?; write_attributes_v4(w, &interface)?;
write_attributes_v6(w, &interface)?; write_attributes_v6(w, &interface)?;
writeln!(w)?; writeln!(w)?;
} else if interface.address_family == AddressFamily::Inet4and6 {
writeln!(w, "iface {} inet {}", name, method_to_str(&interface.method_v4))?;
write_attributes_v4(w, &interface)?;
writeln!(w)?;
writeln!(w, "iface {} inet6 {}", name, method_to_str(&interface.method_v6))?;
write_attributes_v6(w, &interface)?;
writeln!(w)?;
} else if interface.address_family == AddressFamily::Inet {
writeln!(w, "iface {} inet {}", name, method_to_str(&interface.method_v4))?;
write_attributes_v4(w, &interface)?;
writeln!(w)?;
} else if interface.address_family == AddressFamily::Inet6 {
writeln!(w, "iface {} inet {}", name, method_to_str(&interface.method_v6))?;
write_attributes_v6(w, &interface)?;
writeln!(w)?;
} else { } else {
unreachable!(); if let Some(method) = interface.method_v4 {
writeln!(w, "iface {} inet {}", name, method_to_str(method))?;
write_attributes_v4(w, &interface)?;
writeln!(w)?;
}
if let Some(method) = interface.method_v6 {
writeln!(w, "iface {} inet6 {}", name, method_to_str(method))?;
write_attributes_v6(w, &interface)?;
writeln!(w)?;
}
} }
Ok(()) Ok(())
} }
@ -286,4 +279,3 @@ impl NetworkConfig {
Ok(()) Ok(())
} }
} }

View File

@ -11,7 +11,7 @@ use proxmox::*; // for IP macros
use super::helper::*; use super::helper::*;
use super::lexer::*; use super::lexer::*;
use super::{NetworkConfig, NetworkOrderEntry, Interface, AddressFamily}; use super::{NetworkConfig, NetworkOrderEntry, Interface, ConfigMethod};
pub struct NetworkParser { pub struct NetworkParser {
input: Peekable<Lexer<BufReader<File>>>, input: Peekable<Lexer<BufReader<File>>>,
@ -206,67 +206,54 @@ impl NetworkParser {
self.eat(Token::Iface)?; self.eat(Token::Iface)?;
let iface = self.next_text()?; let iface = self.next_text()?;
let mut address_family = None; let mut address_family_v4 = false;
let mut address_family_v6 = false;
let mut config_method = None; let mut config_method = None;
loop { loop {
let (token, text) = self.next()?; let (token, text) = self.next()?;
match token { match token {
Token::Newline => break, Token::Newline => break,
Token::Inet => { Token::Inet => address_family_v4 = true,
address_family = Some(match address_family { Token::Inet6 => address_family_v6 = true,
None => AddressFamily::Inet, Token::Loopback => config_method = Some(ConfigMethod::Loopback),
Some(AddressFamily::Inet) => AddressFamily::Inet, Token::Static => config_method = Some(ConfigMethod::Static),
Some(AddressFamily::Inet6) => AddressFamily::Inet4and6, Token::Manual => config_method = Some(ConfigMethod::Manual),
Some(AddressFamily::Inet4and6) => AddressFamily::Inet4and6, Token::DHCP => config_method = Some(ConfigMethod::DHCP),
});
}
Token::Inet6 => {
address_family = Some(match address_family {
None => AddressFamily::Inet6,
Some(AddressFamily::Inet) => AddressFamily::Inet4and6,
Some(AddressFamily::Inet6) => AddressFamily::Inet6,
Some(AddressFamily::Inet4and6) => AddressFamily::Inet4and6,
});
}
Token::Loopback | Token::Static | Token::Manual | Token::DHCP => {
if config_method.is_none() {
config_method = Some(token);
} else {
bail!("multiple configuration method definitions");
}
}
_ => bail!("unknown iface option {}", text), _ => bail!("unknown iface option {}", text),
} }
} }
let address_family = address_family.unwrap_or(AddressFamily::Inet4and6);
let has_attributes = self.peek()? == Token::Attribute; let has_attributes = self.peek()? == Token::Attribute;
let config_method = config_method.unwrap_or(ConfigMethod::Static);
if !(address_family_v4 || address_family_v6) {
address_family_v4 = true;
address_family_v6 = true;
}
if let Some(mut interface) = config.interfaces.get_mut(&iface) { if let Some(mut interface) = config.interfaces.get_mut(&iface) {
let compatible = match interface.address_family { if address_family_v4 {
AddressFamily::Inet => { interface.set_method_v4(config_method)?;
interface.method_v6 = config_method;
address_family == AddressFamily::Inet6
}
AddressFamily::Inet6 => {
interface.method_v4 = config_method;
address_family == AddressFamily::Inet
}
_ => false,
};
if !compatible {
bail!("duplicate config for iface '{}'", iface);
} }
interface.address_family = AddressFamily::Inet4and6; if address_family_v6 {
interface.set_method_v6(config_method)?;
}
if has_attributes { self.parse_iface_attributes(&mut interface)?; } if has_attributes { self.parse_iface_attributes(&mut interface)?; }
} else { } else {
let mut interface = Interface::new(iface.clone(), address_family, config_method); let mut interface = Interface::new(iface.clone());
if address_family_v4 {
interface.set_method_v4(config_method)?;
}
if address_family_v6 {
interface.set_method_v6(config_method)?;
}
if has_attributes { self.parse_iface_attributes(&mut interface)?; } if has_attributes { self.parse_iface_attributes(&mut interface)?; }
config.interfaces.insert(interface.name.clone(), interface); config.interfaces.insert(interface.name.clone(), interface);
config.order.push(NetworkOrderEntry::Iface(iface)); config.order.push(NetworkOrderEntry::Iface(iface));
} }