From 11c479eb5a1e98456ea3145b18ff60a0ddc02176 Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Wed, 27 Nov 2024 12:20:24 +0100 Subject: [PATCH 1/3] net: support multiple interfaces virtme-run supports multiple --net arguments to setup virtio-net devices, but the init program was only starting the DHCP client for one of them: the first one it discovered, which was not necessarily the first one by alphabetical order. Now, the DHCP client is started for each interface, so each of them can have an assigned IP address. Technically, instead of returning one network device, a vector of devices is returned. Same for the threads to start the DHCP clients. Signed-off-by: Matthieu Baerts (NGI0) --- src/main.rs | 70 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/src/main.rs b/src/main.rs index cec3edc..446bb12 100644 --- a/src/main.rs +++ b/src/main.rs @@ -616,7 +616,9 @@ fn get_guest_tools_dir() -> Option { ) } -fn _get_network_device_from_entries(entries: std::fs::ReadDir) -> Option { +fn _get_network_devices_from_entries(entries: std::fs::ReadDir) -> Vec> { + let mut vec = Vec::new(); + // .flatten() ignores lines with reading errors for entry in entries.flatten() { let path = entry.path(); @@ -626,20 +628,21 @@ fn _get_network_device_from_entries(entries: std::fs::ReadDir) -> Option if let Ok(net_entries) = std::fs::read_dir(path.join("net")) { // .flatten() ignores lines with reading errors if let Some(entry) = net_entries.flatten().next() { - let path = entry.path().file_name()?.to_string_lossy().to_string(); - return Some(path); + if let Some(fname) = entry.path().file_name() { + vec.push(Some(fname.to_string_lossy().to_string())); + } } } } - None + vec } -fn get_network_device() -> Option { +fn get_network_devices() -> Vec> { let virtio_net_dir = "/sys/bus/virtio/drivers/virtio_net"; loop { match std::fs::read_dir(virtio_net_dir) { Ok(entries) => { - return _get_network_device_from_entries(entries); + return _get_network_devices_from_entries(entries); } Err(_) => { // Wait a bit to make sure virtio-net is properly registered in the system. @@ -649,31 +652,43 @@ fn get_network_device() -> Option { } } -fn setup_network() -> Option> { +fn get_network_handle( + network_dev: Option, + guest_tools_dir: Option, +) -> Option> { + let network_dev_str = network_dev.unwrap(); + log!("setting up network device {}", network_dev_str); + return Some(thread::spawn(move || { + let args = [ + "udhcpc", + "-i", + &network_dev_str, + "-n", + "-q", + "-f", + "-s", + &format!("{}/virtme-udhcpc-script", guest_tools_dir.unwrap()), + ]; + utils::run_cmd("busybox", &args); + })); +} + +fn setup_network() -> Vec>> { + let mut vec = Vec::new(); + utils::run_cmd("ip", &["link", "set", "dev", "lo", "up"]); - let cmdline = std::fs::read_to_string("/proc/cmdline").ok()?; + let cmdline = std::fs::read_to_string("/proc/cmdline").unwrap(); if cmdline.contains("virtme.dhcp") { if let Some(guest_tools_dir) = get_guest_tools_dir() { - if let Some(network_dev) = get_network_device() { - log!("setting up network device {}", network_dev); - let handle = thread::spawn(move || { - let args = [ - "udhcpc", - "-i", - &network_dev, - "-n", - "-q", - "-f", - "-s", - &format!("{}/virtme-udhcpc-script", guest_tools_dir), - ]; - utils::run_cmd("busybox", &args); - }); - return Some(handle); - } + get_network_devices().into_iter().for_each(|network_dev| { + vec.push(get_network_handle( + network_dev, + Some(guest_tools_dir.to_owned()), + )); + }); } } - None + vec } fn extract_user_script(virtme_script: &str) -> Option { @@ -1040,7 +1055,8 @@ fn main() { run_systemd_tmpfiles(); // Service initialization (some services can be parallelized here). - let handles = vec![run_udevd(), setup_network(), Some(run_misc_services())]; + let mut handles = vec![run_udevd(), Some(run_misc_services())]; + handles.append(&mut setup_network()); // Wait for the completion of the detached services. for handle in handles.into_iter().flatten() { From 05b4b6c33aae043bd105bca632fd0fd9cf3047b5 Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Wed, 27 Nov 2024 12:35:45 +0100 Subject: [PATCH 2/3] net: setup the loopback iface in a thread Now that setup_network() returns a vector of threads, it is easy to add an extra one. Setting up the loopback interface should be quick. Still, it can be done in parallel if there is nothing else depending on it. Signed-off-by: Matthieu Baerts (NGI0) --- src/main.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 446bb12..0585385 100644 --- a/src/main.rs +++ b/src/main.rs @@ -673,10 +673,15 @@ fn get_network_handle( })); } +fn setup_network_lo() -> Option> { + return Some(thread::spawn(move || { + utils::run_cmd("ip", &["link", "set", "dev", "lo", "up"]); + })); +} + fn setup_network() -> Vec>> { - let mut vec = Vec::new(); + let mut vec = vec![setup_network_lo()]; - utils::run_cmd("ip", &["link", "set", "dev", "lo", "up"]); let cmdline = std::fs::read_to_string("/proc/cmdline").unwrap(); if cmdline.contains("virtme.dhcp") { if let Some(guest_tools_dir) = get_guest_tools_dir() { From 4a5f664d976ed1ad0fa1bb32b1abf56564cca654 Mon Sep 17 00:00:00 2001 From: "Matthieu Baerts (NGI0)" Date: Wed, 27 Nov 2024 12:56:32 +0100 Subject: [PATCH 3/3] poweroff: fix irrefutable 'if let' pattern warning This fixes the following warning: warning: irrefutable `if let` pattern --> src/main.rs:206:8 | 206 | if let Err(err) = reboot::reboot(reboot::RebootMode::RB_POWER_OFF) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this pattern will always match, so the `if let` is useless = help: consider replacing the `if let` with a `let` = note: `#[warn(irrefutable_let_patterns)]` on by default warning: `virtme-ng-init` (bin "virtme-ng-init") generated 1 warning Signed-off-by: Matthieu Baerts (NGI0) --- src/main.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index 0585385..82e3cb6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -203,11 +203,13 @@ fn poweroff() { unsafe { libc::sync(); } - if let Err(err) = reboot::reboot(reboot::RebootMode::RB_POWER_OFF) { - log!("error powering off: {}", err); - exit(1); + match reboot::reboot(reboot::RebootMode::RB_POWER_OFF) { + Ok(_) => exit(0), + Err(err) => { + log!("error powering off: {}", err); + exit(1); + } } - exit(0); } fn configure_environment() {