mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-05-07 16:07:37 +00:00
agent: Wait for interface in update_interface
For nerdctl and docker runtimes, network is hot-plugged instead of cold-plugged. While this change was made in the runtime, we did not have the agent waiting for the device to be ready. On some systems, the device hotplug could take some time causing the update_interface rpc call to fail as the interface is not available. Add a watcher for the network interface based on the pci-path of the network interface. Note, waiting on the device based on name is really not reliable especially in case multiple networks are hotplugged. Signed-off-by: Archana Shinde <archana.m.shinde@intel.com>
This commit is contained in:
parent
82a1892d34
commit
49fbae4fb1
src/agent/src
@ -379,6 +379,65 @@ pub async fn wait_for_pci_device(
|
||||
Ok(addr)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct NetPciMatcher {
|
||||
devpath: String,
|
||||
}
|
||||
|
||||
impl NetPciMatcher {
|
||||
fn new(relpath: &str) -> NetPciMatcher {
|
||||
let root_bus = create_pci_root_bus_path();
|
||||
|
||||
NetPciMatcher {
|
||||
devpath: format!("{}{}", root_bus, relpath),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UeventMatcher for NetPciMatcher {
|
||||
fn is_match(&self, uev: &Uevent) -> bool {
|
||||
uev.devpath.starts_with(self.devpath.as_str())
|
||||
&& uev.subsystem == "net"
|
||||
&& !uev.interface.is_empty()
|
||||
&& uev.action == "add"
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn wait_for_net_interface(
|
||||
sandbox: &Arc<Mutex<Sandbox>>,
|
||||
pcipath: &pci::Path,
|
||||
) -> Result<()> {
|
||||
let root_bus_sysfs = format!("{}{}", SYSFS_DIR, create_pci_root_bus_path());
|
||||
let sysfs_rel_path = pcipath_to_sysfs(&root_bus_sysfs, pcipath)?;
|
||||
|
||||
let matcher = NetPciMatcher::new(&sysfs_rel_path);
|
||||
|
||||
// Check if the interface is already added in case network is cold-plugged
|
||||
// or the uevent loop is started before network is added.
|
||||
// We check for the pci deive in the sysfs directory for network devices.
|
||||
let pattern = format!(
|
||||
r"[./]+{}/[a-z0-9/]*net/[a-z0-9/]*",
|
||||
matcher.devpath.as_str()
|
||||
);
|
||||
let re = Regex::new(&pattern).expect("BUG: Failed to compile regex for NetPciMatcher");
|
||||
|
||||
for entry in fs::read_dir(SYSFS_NET_PATH)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
let target_path = fs::read_link(path)?;
|
||||
let target_path_str = target_path
|
||||
.to_str()
|
||||
.ok_or_else(|| anyhow!("Expected symlink in dir {}", SYSFS_NET_PATH))?;
|
||||
|
||||
if re.is_match(target_path_str) {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
let _uev = wait_for_uevent(sandbox, matcher).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct VfioMatcher {
|
||||
syspath: String,
|
||||
@ -1691,6 +1750,41 @@ mod tests {
|
||||
assert!(!matcher_a.is_match(&uev_b));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[allow(clippy::redundant_clone)]
|
||||
async fn test_net_pci_matcher() {
|
||||
let root_bus = create_pci_root_bus_path();
|
||||
let relpath_a = "/0000:00:02.0/0000:01:01.0";
|
||||
|
||||
let mut uev_a = crate::uevent::Uevent::default();
|
||||
uev_a.action = crate::linux_abi::U_EVENT_ACTION_ADD.to_string();
|
||||
uev_a.devpath = format!("{}{}", root_bus, relpath_a);
|
||||
uev_a.subsystem = String::from("net");
|
||||
uev_a.interface = String::from("eth0");
|
||||
let matcher_a = NetPciMatcher::new(relpath_a);
|
||||
println!("Matcher a : {}", matcher_a.devpath);
|
||||
|
||||
let relpath_b = "/0000:00:02.0/0000:01:02.0";
|
||||
let mut uev_b = uev_a.clone();
|
||||
uev_b.devpath = format!("{}{}", root_bus, relpath_b);
|
||||
let matcher_b = NetPciMatcher::new(relpath_b);
|
||||
|
||||
assert!(matcher_a.is_match(&uev_a));
|
||||
assert!(matcher_b.is_match(&uev_b));
|
||||
assert!(!matcher_b.is_match(&uev_a));
|
||||
assert!(!matcher_a.is_match(&uev_b));
|
||||
|
||||
let relpath_c = "/0000:00:02.0/0000:01:03.0";
|
||||
let net_substr = "/net/eth0";
|
||||
let mut uev_c = uev_a.clone();
|
||||
uev_c.devpath = format!("{}{}{}", root_bus, relpath_c, net_substr);
|
||||
let matcher_c = NetPciMatcher::new(relpath_c);
|
||||
|
||||
assert!(matcher_c.is_match(&uev_c));
|
||||
assert!(!matcher_a.is_match(&uev_c));
|
||||
assert!(!matcher_b.is_match(&uev_c));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[allow(clippy::redundant_clone)]
|
||||
async fn test_mmio_block_matcher() {
|
||||
|
@ -89,6 +89,7 @@ pub const SYSFS_MEMORY_HOTPLUG_PROBE_PATH: &str = "/sys/devices/system/memory/pr
|
||||
pub const SYSFS_MEMORY_ONLINE_PATH: &str = "/sys/devices/system/memory";
|
||||
|
||||
pub const SYSFS_SCSI_HOST_PATH: &str = "/sys/class/scsi_host";
|
||||
pub const SYSFS_NET_PATH: &str = "/sys/class/net";
|
||||
|
||||
pub const SYSFS_BUS_PCI_PATH: &str = "/sys/bus/pci";
|
||||
|
||||
|
@ -13,6 +13,7 @@ use std::fmt::Debug;
|
||||
use std::io;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use ttrpc::{
|
||||
self,
|
||||
@ -52,7 +53,9 @@ use nix::sys::{stat, statfs};
|
||||
use nix::unistd::{self, Pid};
|
||||
use rustjail::process::ProcessOperations;
|
||||
|
||||
use crate::device::{add_devices, get_virtio_blk_pci_device_name, update_env_pci};
|
||||
use crate::device::{
|
||||
add_devices, get_virtio_blk_pci_device_name, update_env_pci, wait_for_net_interface,
|
||||
};
|
||||
use crate::features::get_build_features;
|
||||
use crate::linux_abi::*;
|
||||
use crate::metrics::get_metrics;
|
||||
@ -915,6 +918,17 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
"empty update interface request",
|
||||
)?;
|
||||
|
||||
// For network devices passed on the pci bus, check for the network interface
|
||||
// to be available first.
|
||||
if !interface.pciPath.is_empty() {
|
||||
let pcipath = pci::Path::from_str(&interface.pciPath)
|
||||
.map_ttrpc_err(|e| format!("Unexpected pci-path for network interface: {:?}", e))?;
|
||||
|
||||
wait_for_net_interface(&self.sandbox, &pcipath)
|
||||
.await
|
||||
.map_ttrpc_err(|e| format!("interface not available: {:?}", e))?;
|
||||
}
|
||||
|
||||
self.sandbox
|
||||
.lock()
|
||||
.await
|
||||
|
Loading…
Reference in New Issue
Block a user