src/config/network.rs: make it compatible with pve

and depend on proxmox 0.1.26
This commit is contained in:
Dietmar Maurer
2020-05-06 07:51:05 +02:00
parent 5751e49566
commit 7b22acd0c2
12 changed files with 333 additions and 204 deletions

View File

@ -22,27 +22,28 @@ impl Interface {
Self {
name,
interface_type: NetworkInterfaceType::Unknown,
auto: false,
autostart: false,
active: false,
method_v4: None,
method_v6: None,
cidr_v4: None,
gateway_v4: None,
cidr_v6: None,
gateway_v6: None,
options_v4: Vec::new(),
options_v6: Vec::new(),
comments_v4: None,
comments_v6: None,
method: None,
method6: None,
cidr: None,
gateway: None,
cidr6: None,
gateway6: None,
options: Vec::new(),
options6: Vec::new(),
comments: None,
comments6: None,
mtu: None,
bridge_ports: None,
bridge_vlan_aware: None,
bond_slaves: None,
}
}
fn set_method_v4(&mut self, method: NetworkConfigMethod) -> Result<(), Error> {
if self.method_v4.is_none() {
self.method_v4 = Some(method);
if self.method.is_none() {
self.method = Some(method);
} else {
bail!("inet configuration method already set.");
}
@ -50,8 +51,8 @@ impl Interface {
}
fn set_method_v6(&mut self, method: NetworkConfigMethod) -> Result<(), Error> {
if self.method_v6.is_none() {
self.method_v6 = Some(method);
if self.method6.is_none() {
self.method6 = Some(method);
} else {
bail!("inet6 configuration method already set.");
}
@ -59,8 +60,8 @@ impl Interface {
}
fn set_cidr_v4(&mut self, address: String) -> Result<(), Error> {
if self.cidr_v4.is_none() {
self.cidr_v4 = Some(address);
if self.cidr.is_none() {
self.cidr = Some(address);
} else {
bail!("duplicate IPv4 address.");
}
@ -68,8 +69,8 @@ impl Interface {
}
fn set_gateway_v4(&mut self, gateway: String) -> Result<(), Error> {
if self.gateway_v4.is_none() {
self.gateway_v4 = Some(gateway);
if self.gateway.is_none() {
self.gateway = Some(gateway);
} else {
bail!("duplicate IPv4 gateway.");
}
@ -77,8 +78,8 @@ impl Interface {
}
fn set_cidr_v6(&mut self, address: String) -> Result<(), Error> {
if self.cidr_v6.is_none() {
self.cidr_v6 = Some(address);
if self.cidr6.is_none() {
self.cidr6 = Some(address);
} else {
bail!("duplicate IPv6 address.");
}
@ -86,8 +87,8 @@ impl Interface {
}
fn set_gateway_v6(&mut self, gateway: String) -> Result<(), Error> {
if self.gateway_v6.is_none() {
self.gateway_v6 = Some(gateway);
if self.gateway6.is_none() {
self.gateway6 = Some(gateway);
} else {
bail!("duplicate IPv4 gateway.");
}
@ -124,20 +125,23 @@ impl Interface {
match self.interface_type {
NetworkInterfaceType::Bridge => {
if let Some(true) = self.bridge_vlan_aware {
writeln!(w, "\tbridge-vlan-aware yes")?;
}
if let Some(ref ports) = self.bridge_ports {
if ports.is_empty() {
writeln!(w, " bridge-ports none")?;
writeln!(w, "\tbridge-ports none")?;
} else {
writeln!(w, " bridge-ports {}", ports.join(" "))?;
writeln!(w, "\tbridge-ports {}", ports.join(" "))?;
}
}
}
NetworkInterfaceType::Bond => {
if let Some(ref slaves) = self.bond_slaves {
if slaves.is_empty() {
writeln!(w, " bond-slaves none")?;
writeln!(w, "\tbond-slaves none")?;
} else {
writeln!(w, " bond-slaves {}", slaves.join(" "))?;
writeln!(w, "\tbond-slaves {}", slaves.join(" "))?;
}
}
}
@ -145,7 +149,7 @@ impl Interface {
}
if let Some(mtu) = self.mtu {
writeln!(w, " mtu {}", mtu)?;
writeln!(w, "\tmtu {}", mtu)?;
}
Ok(())
@ -154,19 +158,19 @@ impl Interface {
/// Write attributes dependening on address family inet (IPv4)
fn write_iface_attributes_v4(&self, w: &mut dyn Write, method: NetworkConfigMethod) -> Result<(), Error> {
if method == NetworkConfigMethod::Static {
if let Some(address) = &self.cidr_v4 {
writeln!(w, " address {}", address)?;
if let Some(address) = &self.cidr {
writeln!(w, "\taddress {}", address)?;
}
if let Some(gateway) = &self.gateway_v4 {
writeln!(w, " gateway {}", gateway)?;
if let Some(gateway) = &self.gateway {
writeln!(w, "\tgateway {}", gateway)?;
}
}
for option in &self.options_v4 {
writeln!(w, " {}", option)?;
for option in &self.options {
writeln!(w, "\t{}", option)?;
}
if let Some(ref comments) = self.comments_v4 {
if let Some(ref comments) = self.comments {
for comment in comments.lines() {
writeln!(w, "#{}", comment)?;
}
@ -178,19 +182,19 @@ impl Interface {
/// Write attributes dependening on address family inet6 (IPv6)
fn write_iface_attributes_v6(&self, w: &mut dyn Write, method: NetworkConfigMethod) -> Result<(), Error> {
if method == NetworkConfigMethod::Static {
if let Some(address) = &self.cidr_v6 {
writeln!(w, " address {}", address)?;
if let Some(address) = &self.cidr6 {
writeln!(w, "\taddress {}", address)?;
}
if let Some(gateway) = &self.gateway_v6 {
writeln!(w, " gateway {}", gateway)?;
if let Some(gateway) = &self.gateway6 {
writeln!(w, "\tgateway {}", gateway)?;
}
}
for option in &self.options_v6 {
writeln!(w, " {}", option)?;
for option in &self.options6 {
writeln!(w, "\t{}", option)?;
}
if let Some(ref comments) = self.comments_v6 {
if let Some(ref comments) = self.comments6 {
for comment in comments.lines() {
writeln!(w, "#{}", comment)?;
}
@ -204,30 +208,31 @@ impl Interface {
// Note: use match to make sure we considered all values at compile time
match self {
Interface {
method_v4,
method_v6,
options_v4,
options_v6,
comments_v4,
comments_v6,
method,
method6,
options,
options6,
comments,
comments6,
// the rest does not matter
name: _name,
interface_type: _interface_type,
auto: _auto,
autostart: _autostart,
active: _active,
cidr_v4: _cidr_v4,
cidr_v6: _cidr_v6,
gateway_v4: _gateway_v4,
gateway_v6: _gateway_v6,
cidr: _cidr,
cidr6: _cidr6,
gateway: _gateway,
gateway6: _gateway6,
mtu: _mtu,
bridge_ports: _bridge_ports,
bridge_vlan_aware: _bridge_vlan_aware,
bond_slaves: _bond_slaves,
} => {
method_v4 == method_v6
&& comments_v4.is_none()
&& comments_v6.is_none()
&& options_v4.is_empty()
&& options_v6.is_empty()
method == method6
&& comments.is_none()
&& comments6.is_none()
&& options.is_empty()
&& options6.is_empty()
}
}
}
@ -243,36 +248,46 @@ impl Interface {
}
}
if self.method_v4.is_none() && self.method_v6.is_none() { return Ok(()); }
if self.method.is_none() && self.method6.is_none() { return Ok(()); }
if self.auto {
if self.autostart {
writeln!(w, "auto {}", self.name)?;
}
if self.combine_entry() {
if let Some(method) = self.method_v4 {
if let Some(method) = self.method {
writeln!(w, "iface {} {}", self.name, method_to_str(method))?;
self.write_iface_attributes_v4(w, method)?;
self.write_iface_attributes_v6(w, method)?;
self.write_iface_attributes(w)?;
writeln!(w)?;
}
} else {
if let Some(method) = self.method_v4 {
writeln!(w, "iface {} inet {}", self.name, method_to_str(method))?;
self.write_iface_attributes_v4(w, method)?;
self.write_iface_attributes(w)?;
writeln!(w)?;
return Ok(());
}
if let Some(method) = self.method {
writeln!(w, "iface {} inet {}", self.name, method_to_str(method))?;
self.write_iface_attributes_v4(w, method)?;
self.write_iface_attributes(w)?;
writeln!(w)?;
}
if let Some(method6) = self.method6 {
let mut skip_v6 = false; // avoid empty inet6 manual entry
if self.method.is_some() && method6 == NetworkConfigMethod::Manual {
if self.comments6.is_none() && self.options6.is_empty() { skip_v6 = true; }
}
if let Some(method) = self.method_v6 {
writeln!(w, "iface {} inet6 {}", self.name, method_to_str(method))?;
self.write_iface_attributes_v6(w, method)?;
if self.method_v4.is_none() { // only write common attributes once
if !skip_v6 {
writeln!(w, "iface {} inet6 {}", self.name, method_to_str(method6))?;
self.write_iface_attributes_v6(w, method6)?;
if self.method.is_none() { // only write common attributes once
self.write_iface_attributes(w)?;
}
writeln!(w)?;
}
}
Ok(())
}
}

View File

@ -23,6 +23,7 @@ pub enum Token {
Attribute,
MTU,
BridgePorts,
BridgeVlanAware,
BondSlaves,
EOF,
}
@ -44,6 +45,8 @@ lazy_static! {
map.insert("mtu", Token::MTU);
map.insert("bridge-ports", Token::BridgePorts);
map.insert("bridge_ports", Token::BridgePorts);
map.insert("bridge-vlan-aware", Token::BridgeVlanAware);
map.insert("bridge_vlan_aware", Token::BridgeVlanAware);
map.insert("bond-slaves", Token::BondSlaves);
map.insert("bond_slaves", Token::BondSlaves);
map

View File

@ -137,6 +137,21 @@ impl <R: BufRead> NetworkParser<R> {
Ok(mtu)
}
fn parse_yes_no(&mut self) -> Result<bool, Error> {
let text = self.next_text()?;
let value = match text.to_lowercase().as_str() {
"yes" => true,
"no" => false,
_ => {
bail!("unable to bool value '{}' - (expected yes/no)", text);
}
};
self.eat(Token::Newline)?;
Ok(value)
}
fn parse_to_eol(&mut self) -> Result<String, Error> {
let mut line = String::new();
loop {
@ -182,15 +197,15 @@ impl <R: BufRead> NetworkParser<R> {
Token::Comment => {
let comment = self.eat(Token::Comment)?;
if !address_family_v4 && address_family_v6 {
let mut comments = interface.comments_v6.take().unwrap_or(String::new());
let mut comments = interface.comments6.take().unwrap_or(String::new());
if !comments.is_empty() { comments.push('\n'); }
comments.push_str(&comment);
interface.comments_v6 = Some(comments);
interface.comments6 = Some(comments);
} else {
let mut comments = interface.comments_v4.take().unwrap_or(String::new());
let mut comments = interface.comments.take().unwrap_or(String::new());
if !comments.is_empty() { comments.push('\n'); }
comments.push_str(&comment);
interface.comments_v4 = Some(comments);
interface.comments = Some(comments);
}
self.eat(Token::Newline)?;
continue;
@ -207,6 +222,11 @@ impl <R: BufRead> NetworkParser<R> {
let mtu = self.parse_iface_mtu()?;
interface.mtu = Some(mtu);
}
Token::BridgeVlanAware => {
self.eat(Token::BridgeVlanAware)?;
let bridge_vlan_aware = self.parse_yes_no()?;
interface.bridge_vlan_aware = Some(bridge_vlan_aware);
}
Token::BridgePorts => {
self.eat(Token::BridgePorts)?;
let ports = self.parse_iface_list()?;
@ -225,9 +245,9 @@ impl <R: BufRead> NetworkParser<R> {
let option = self.parse_to_eol()?;
if !option.is_empty() {
if !address_family_v4 && address_family_v6 {
interface.options_v6.push(option);
interface.options6.push(option);
} else {
interface.options_v4.push(option);
interface.options.push(option);
}
};
},
@ -335,7 +355,7 @@ impl <R: BufRead> NetworkParser<R> {
for iface in auto_flag.iter() {
if let Some(interface) = config.interfaces.get_mut(iface) {
interface.auto = true;
interface.autostart = true;
}
}
@ -349,13 +369,13 @@ impl <R: BufRead> NetworkParser<R> {
for (iface, active) in existing_interfaces.iter() {
if let Some(interface) = config.interfaces.get_mut(iface) {
interface.active = *active;
if interface.interface_type == NetworkInterfaceType::Unknown {
interface.interface_type = NetworkInterfaceType::Ethernet;
if interface.interface_type == NetworkInterfaceType::Unknown && PHYSICAL_NIC_REGEX.is_match(iface) {
interface.interface_type = NetworkInterfaceType::Eth;
}
} else if PHYSICAL_NIC_REGEX.is_match(iface) { // also add all physical NICs
let mut interface = Interface::new(iface.clone());
interface.set_method_v4(NetworkConfigMethod::Manual)?;
interface.interface_type = NetworkInterfaceType::Ethernet;
interface.interface_type = NetworkInterfaceType::Eth;
interface.active = *active;
config.interfaces.insert(interface.name.clone(), interface);
config.order.push(NetworkOrderEntry::Iface(iface.to_string()));
@ -378,7 +398,7 @@ impl <R: BufRead> NetworkParser<R> {
continue;
}
if PHYSICAL_NIC_REGEX.is_match(name) {
interface.interface_type = NetworkInterfaceType::Vanished;
interface.interface_type = NetworkInterfaceType::Eth;
continue;
}
}
@ -387,7 +407,7 @@ impl <R: BufRead> NetworkParser<R> {
let mut interface = Interface::new(String::from("lo"));
interface.set_method_v4(NetworkConfigMethod::Loopback)?;
interface.interface_type = NetworkInterfaceType::Loopback;
interface.auto = true;
interface.autostart = true;
config.interfaces.insert(interface.name.clone(), interface);
// Note: insert 'lo' as first interface after initial comments