Skip to content

Commit

Permalink
Avoid using VLAN interfaces for physical interface modifications (#51)
Browse files Browse the repository at this point in the history
* Add interface_type field to host mapping

Signed-off-by: Atanas Dinov <[email protected]>

* Drop mac_address requirement

Signed-off-by: Atanas Dinov <[email protected]>

* Support VLAN interfaces

Signed-off-by: Atanas Dinov <[email protected]>

* Wrap mac_address as an Option

Signed-off-by: Atanas Dinov <[email protected]>

---------

Signed-off-by: Atanas Dinov <[email protected]>
  • Loading branch information
atanasdinov authored Mar 20, 2024
1 parent 2e44eb0 commit 9885d7e
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 35 deletions.
99 changes: 69 additions & 30 deletions src/apply_conf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::path::{Path, PathBuf};
use anyhow::{anyhow, Context};
use log::{debug, info, warn};
use network_interface::{NetworkInterface, NetworkInterfaceConfig};
use nmstate::InterfaceType;

use crate::types::Host;
use crate::HOST_MAPPING_FILE;
Expand Down Expand Up @@ -38,9 +39,10 @@ fn parse_config(source_dir: &str) -> Result<Vec<Host>, anyhow::Error> {

// Ensure lower case formatting.
hosts.iter_mut().for_each(|h| {
h.interfaces
.iter_mut()
.for_each(|i| i.mac_address = i.mac_address.to_lowercase());
h.interfaces.iter_mut().for_each(|i| match &i.mac_address {
None => {}
Some(addr) => i.mac_address = Some(addr.to_lowercase()),
});
});

Ok(hosts)
Expand All @@ -50,11 +52,10 @@ fn parse_config(source_dir: &str) -> Result<Vec<Host>, anyhow::Error> {
fn identify_host(hosts: Vec<Host>, network_interfaces: &[NetworkInterface]) -> Option<Host> {
hosts.into_iter().find(|h| {
h.interfaces.iter().any(|interface| {
network_interfaces.iter().any(|nic| {
nic.mac_addr
.clone()
.is_some_and(|addr| addr == interface.mac_address)
})
network_interfaces
.iter()
.filter(|nic| nic.mac_addr.is_some())
.any(|nic| nic.mac_addr == interface.mac_address)
})
})
}
Expand Down Expand Up @@ -99,20 +100,26 @@ fn copy_connection_files(
if let Some((interface, nic_name)) = host
.interfaces
.iter()
.filter(|interface| interface.mac_address.is_some())
.filter(|interface| interface.interface_type != InterfaceType::Vlan.to_string())
.find(|interface| interface.logical_name == filename)
.and_then(|interface| {
network_interfaces
.iter()
.find(|nic| {
nic.mac_addr
.clone()
.is_some_and(|addr| addr == interface.mac_address)
&& nic.name != interface.logical_name
nic.mac_addr == interface.mac_address && nic.name != interface.logical_name
})
.filter(|nic| {
host.interfaces
.iter()
.find(|i| i.logical_name == nic.name)
.filter(|i| i.interface_type == InterfaceType::Vlan.to_string())
.is_none()
})
.map(|nic| (interface, &nic.name))
})
{
info!("Using name '{}' for interface with MAC address '{}' instead of the preconfigured '{}'",
info!("Using name '{}' for interface with MAC address '{:?}' instead of the preconfigured '{}'",
nic_name, interface.mac_address, interface.logical_name);

contents = contents.replace(&interface.logical_name, nic_name);
Expand Down Expand Up @@ -169,14 +176,16 @@ mod tests {
hostname: "h1".to_string(),
interfaces: vec![Interface {
logical_name: "eth0".to_string(),
mac_address: "00:11:22:33:44:55".to_string(),
mac_address: Option::from("00:11:22:33:44:55".to_string()),
interface_type: "ethernet".to_string(),
}],
},
Host {
hostname: "h2".to_string(),
interfaces: vec![Interface {
logical_name: "".to_string(),
mac_address: "10:10:10:10:10:10".to_string(),
mac_address: Option::from("10:10:10:10:10:10".to_string()),
interface_type: "".to_string(),
}],
},
];
Expand All @@ -201,7 +210,8 @@ mod tests {
host.interfaces,
vec![Interface {
logical_name: "eth0".to_string(),
mac_address: "00:11:22:33:44:55".to_string(),
mac_address: Option::from("00:11:22:33:44:55".to_string()),
interface_type: "ethernet".to_string(),
}]
);
}
Expand All @@ -213,14 +223,16 @@ mod tests {
hostname: "h1".to_string(),
interfaces: vec![Interface {
logical_name: "eth0".to_string(),
mac_address: "10:20:30:40:50:60".to_string(),
mac_address: Option::from("10:20:30:40:50:60".to_string()),
interface_type: "ethernet".to_string(),
}],
},
Host {
hostname: "h2".to_string(),
interfaces: vec![Interface {
logical_name: "".to_string(),
mac_address: "00:10:20:30:40:50".to_string(),
mac_address: Option::from("00:10:20:30:40:50".to_string()),
interface_type: "".to_string(),
}],
},
];
Expand Down Expand Up @@ -251,28 +263,40 @@ mod tests {
interfaces: vec![
Interface {
logical_name: "eth0".to_string(),
mac_address: "00:11:22:33:44:55".to_string(),
mac_address: Option::from("00:11:22:33:44:55".to_string()),
interface_type: "ethernet".to_string(),
},
Interface {
logical_name: "eth1".to_string(),
mac_address: "00:11:22:33:44:58".to_string(),
mac_address: Option::from("00:11:22:33:44:58".to_string()),
interface_type: "ethernet".to_string(),
},
Interface {
logical_name: "eth2".to_string(),
mac_address: "36:5e:6b:a2:ed:80".to_string(),
mac_address: Option::from("36:5e:6b:a2:ed:80".to_string()),
interface_type: "ethernet".to_string(),
},
Interface {
logical_name: "bond0".to_string(),
mac_address: "00:11:22:aa:44:58".to_string(),
mac_address: Option::from("00:11:22:aa:44:58".to_string()),
interface_type: "bond".to_string(),
},
],
},
Host {
hostname: "node2".to_string(),
interfaces: vec![Interface {
logical_name: "eth0".to_string(),
mac_address: "36:5e:6b:a2:ed:81".to_string(),
}],
interfaces: vec![
Interface {
logical_name: "eth0".to_string(),
mac_address: Option::from("36:5e:6b:a2:ed:81".to_string()),
interface_type: "ethernet".to_string(),
},
Interface {
logical_name: "eth0.1365".to_string(),
mac_address: None,
interface_type: "vlan".to_string(),
},
],
},
]
)
Expand All @@ -287,19 +311,28 @@ mod tests {
interfaces: vec![
Interface {
logical_name: "eth0".to_string(),
mac_address: "00:11:22:33:44:55".to_string(),
mac_address: Option::from("00:11:22:33:44:55".to_string()),
interface_type: "ethernet".to_string(),
},
Interface {
logical_name: "eth0.1365".to_string(),
mac_address: None,
interface_type: "vlan".to_string(),
},
Interface {
logical_name: "eth2".to_string(),
mac_address: "00:11:22:33:44:56".to_string(),
mac_address: Option::from("00:11:22:33:44:56".to_string()),
interface_type: "ethernet".to_string(),
},
Interface {
logical_name: "eth1".to_string(),
mac_address: "00:11:22:33:44:57".to_string(),
mac_address: Option::from("00:11:22:33:44:57".to_string()),
interface_type: "ethernet".to_string(),
},
Interface {
logical_name: "bond0".to_string(),
mac_address: "00:11:22:33:44:58".to_string(),
mac_address: Option::from("00:11:22:33:44:58".to_string()),
interface_type: "bond".to_string(),
},
],
};
Expand All @@ -310,6 +343,12 @@ mod tests {
addr: vec![],
index: 0,
},
NetworkInterface {
name: "eth0.1365".to_string(), // VLAN
addr: vec![],
mac_addr: Some("00:11:22:33:44:55".to_string()),
index: 0,
},
NetworkInterface {
name: "eth4".to_string(),
mac_addr: Some("00:11:22:33:44:56".to_string()),
Expand Down
10 changes: 6 additions & 4 deletions src/generate_conf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ fn extract_interfaces(network_state: &NetworkState) -> Vec<Interface> {
.interfaces
.iter()
.filter(|i| i.iface_type() != InterfaceType::Loopback)
.filter(|i| i.base_iface().mac_address.is_some())
.map(|i| Interface {
logical_name: i.name().to_string(),
mac_address: i.base_iface().mac_address.clone().unwrap(),
mac_address: i.base_iface().mac_address.clone(),
interface_type: i.iface_type().to_string(),
})
.collect()
}
Expand Down Expand Up @@ -203,11 +203,13 @@ mod tests {
vec![
Interface {
logical_name: "bridge0".to_string(),
mac_address: "FE:C4:05:42:8B:AB".to_string(),
mac_address: Option::from("FE:C4:05:42:8B:AB".to_string()),
interface_type: "linux-bridge".to_string(),
},
Interface {
logical_name: "eth1".to_string(),
mac_address: "FE:C4:05:42:8B:AA".to_string(),
mac_address: Option::from("FE:C4:05:42:8B:AA".to_string()),
interface_type: "ethernet".to_string(),
},
]
);
Expand Down
5 changes: 4 additions & 1 deletion src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,8 @@ pub struct Host {
#[cfg_attr(test, derive(PartialEq))]
pub struct Interface {
pub(crate) logical_name: String,
pub(crate) mac_address: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub(crate) mac_address: Option<String>,
pub(crate) interface_type: String,
}
7 changes: 7 additions & 0 deletions testdata/apply/config/host_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@
interfaces:
- logical_name: eth0
mac_address: 00:11:22:33:44:55
interface_type: ethernet
- logical_name: eth1
mac_address: 00:11:22:33:44:58
interface_type: ethernet
- logical_name: eth2
mac_address: 36:5e:6b:a2:ed:80
interface_type: ethernet
- logical_name: bond0
mac_address: 00:11:22:AA:44:58
interface_type: bond
- hostname: node2
interfaces:
- logical_name: eth0
mac_address: 36:5E:6B:A2:ED:81
interface_type: ethernet
- logical_name: eth0.1365
interface_type: vlan
25 changes: 25 additions & 0 deletions testdata/apply/node1/eth0.1365.nmconnection
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[connection]
autoconnect=true
autoconnect-slaves=-1
id=eth0.1365
interface-name=eth0.1365
type=vlan
uuid=7544e8b2-96c6-594b-adcb-6f949ef3f9ba

[ipv4]
dhcp-client-id=mac
dhcp-send-hostname=true
dhcp-timeout=2147483647
ignore-auto-dns=false
ignore-auto-routes=false
method=auto
never-default=false

[ipv6]
dhcp-timeout=2147483647
method=disabled

[vlan]
flags=0
id=1365
parent=4fd00f34-9191-481c-b931-caa24dae871a
2 changes: 2 additions & 0 deletions testdata/generate/expected/host_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@
interfaces:
- logical_name: bridge0
mac_address: FE:C4:05:42:8B:AA
interface_type: linux-bridge
- logical_name: eth0
mac_address: 0E:4D:C6:B8:C4:72
interface_type: ethernet

0 comments on commit 9885d7e

Please sign in to comment.