mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-05-10 01:16:42 +00:00
agent: Handle virtio-net-ccw devices separately
On s390x, a virtio-net device will use the CCW bus instead of PCI, which impacts how its uevent should be handled. Take the respective path accordingly. Signed-off-by: Jakob Naucke <jakob.naucke@ibm.com>
This commit is contained in:
parent
a084b99324
commit
c146980bcd
src/agent/src
@ -3,35 +3,23 @@
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
use crate::device::pcipath_to_sysfs;
|
||||
#[cfg(target_arch = "s390x")]
|
||||
use crate::ccw;
|
||||
use crate::linux_abi::*;
|
||||
use crate::pci;
|
||||
use crate::sandbox::Sandbox;
|
||||
use crate::uevent::{wait_for_uevent, Uevent, UeventMatcher};
|
||||
#[cfg(not(target_arch = "s390x"))]
|
||||
use crate::{device::pcipath_to_sysfs, pci};
|
||||
use anyhow::{anyhow, Result};
|
||||
use regex::Regex;
|
||||
use std::fs;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
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);
|
||||
|
||||
fn check_existing(re: Regex) -> Result<bool> {
|
||||
// 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");
|
||||
|
||||
// We check for the device in the sysfs directory for network devices.
|
||||
for entry in fs::read_dir(SYSFS_NET_PATH)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
@ -41,19 +29,41 @@ pub async fn wait_for_net_interface(
|
||||
.ok_or_else(|| anyhow!("Expected symlink in dir {}", SYSFS_NET_PATH))?;
|
||||
|
||||
if re.is_match(target_path_str) {
|
||||
return Ok(());
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "s390x"))]
|
||||
pub async fn wait_for_pci_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);
|
||||
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");
|
||||
if check_existing(re)? {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let _uev = wait_for_uevent(sandbox, matcher).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "s390x"))]
|
||||
#[derive(Debug)]
|
||||
pub struct NetPciMatcher {
|
||||
devpath: String,
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "s390x"))]
|
||||
impl NetPciMatcher {
|
||||
pub fn new(relpath: &str) -> NetPciMatcher {
|
||||
let root_bus = create_pci_root_bus_path();
|
||||
@ -64,6 +74,7 @@ impl NetPciMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "s390x"))]
|
||||
impl UeventMatcher for NetPciMatcher {
|
||||
fn is_match(&self, uev: &Uevent) -> bool {
|
||||
uev.devpath.starts_with(self.devpath.as_str())
|
||||
@ -73,10 +84,53 @@ impl UeventMatcher for NetPciMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "s390x")]
|
||||
pub async fn wait_for_ccw_net_interface(
|
||||
sandbox: &Arc<Mutex<Sandbox>>,
|
||||
device: &ccw::Device,
|
||||
) -> Result<()> {
|
||||
let matcher = NetCcwMatcher::new(CCW_ROOT_BUS_PATH, device);
|
||||
if check_existing(matcher.re.clone())? {
|
||||
return Ok(());
|
||||
}
|
||||
let _uev = wait_for_uevent(sandbox, matcher).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "s390x")]
|
||||
#[derive(Debug)]
|
||||
struct NetCcwMatcher {
|
||||
re: Regex,
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "s390x")]
|
||||
impl NetCcwMatcher {
|
||||
pub fn new(root_bus_path: &str, device: &ccw::Device) -> Self {
|
||||
let re = format!(
|
||||
r"{}/0\.[0-3]\.[0-9a-f]{{1,4}}/{}/virtio[0-9]+/net/",
|
||||
root_bus_path, device
|
||||
);
|
||||
NetCcwMatcher {
|
||||
re: Regex::new(&re).expect("BUG: failed to compile NetCCWMatcher regex"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "s390x")]
|
||||
impl UeventMatcher for NetCcwMatcher {
|
||||
fn is_match(&self, uev: &Uevent) -> bool {
|
||||
self.re.is_match(&uev.devpath)
|
||||
&& uev.subsystem == "net"
|
||||
&& !uev.interface.is_empty()
|
||||
&& uev.action == "add"
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[cfg(not(target_arch = "s390x"))]
|
||||
#[tokio::test]
|
||||
#[allow(clippy::redundant_clone)]
|
||||
async fn test_net_pci_matcher() {
|
||||
@ -111,4 +165,34 @@ mod tests {
|
||||
assert!(!matcher_a.is_match(&uev_c));
|
||||
assert!(!matcher_b.is_match(&uev_c));
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "s390x")]
|
||||
#[tokio::test]
|
||||
async fn test_net_ccw_matcher() {
|
||||
let dev_a = ccw::Device::new(0, 1).unwrap();
|
||||
let dev_b = ccw::Device::new(1, 2).unwrap();
|
||||
|
||||
let mut uev_a = crate::uevent::Uevent::default();
|
||||
uev_a.action = crate::linux_abi::U_EVENT_ACTION_ADD.to_string();
|
||||
uev_a.subsystem = String::from("net");
|
||||
uev_a.interface = String::from("eth0");
|
||||
uev_a.devpath = format!(
|
||||
"{}/0.0.0001/{}/virtio1/{}/{}",
|
||||
CCW_ROOT_BUS_PATH, dev_a, uev_a.subsystem, uev_a.interface
|
||||
);
|
||||
|
||||
let mut uev_b = uev_a.clone();
|
||||
uev_b.devpath = format!(
|
||||
"{}/0.0.0001/{}/virtio1/{}/{}",
|
||||
CCW_ROOT_BUS_PATH, dev_b, uev_b.subsystem, uev_b.interface
|
||||
);
|
||||
|
||||
let matcher_a = NetCcwMatcher::new(CCW_ROOT_BUS_PATH, &dev_a);
|
||||
let matcher_b = NetCcwMatcher::new(CCW_ROOT_BUS_PATH, &dev_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));
|
||||
}
|
||||
}
|
||||
|
@ -55,9 +55,14 @@ use nix::sys::{stat, statfs};
|
||||
use nix::unistd::{self, Pid};
|
||||
use rustjail::process::ProcessOperations;
|
||||
|
||||
#[cfg(target_arch = "s390x")]
|
||||
use crate::ccw;
|
||||
use crate::cdh;
|
||||
use crate::device::block_device_handler::get_virtio_blk_pci_device_name;
|
||||
use crate::device::network_device_handler::wait_for_net_interface;
|
||||
#[cfg(target_arch = "s390x")]
|
||||
use crate::device::network_device_handler::wait_for_ccw_net_interface;
|
||||
#[cfg(not(target_arch = "s390x"))]
|
||||
use crate::device::network_device_handler::wait_for_pci_net_interface;
|
||||
use crate::device::{add_devices, handle_cdi_devices, update_env_pci};
|
||||
use crate::features::get_build_features;
|
||||
#[cfg(feature = "guest-pull")]
|
||||
@ -1000,15 +1005,27 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
"empty update interface request",
|
||||
)?;
|
||||
|
||||
// For network devices passed on the pci bus, check for the network interface
|
||||
// For network devices passed, check for the network interface
|
||||
// to be available first.
|
||||
if !interface.devicePath.is_empty() {
|
||||
let pcipath = pci::Path::from_str(&interface.devicePath)
|
||||
.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))?;
|
||||
#[cfg(not(target_arch = "s390x"))]
|
||||
{
|
||||
let pcipath = pci::Path::from_str(&interface.devicePath).map_ttrpc_err(|e| {
|
||||
format!("Unexpected pci-path for network interface: {:?}", e)
|
||||
})?;
|
||||
wait_for_pci_net_interface(&self.sandbox, &pcipath)
|
||||
.await
|
||||
.map_ttrpc_err(|e| format!("interface not available: {:?}", e))?;
|
||||
}
|
||||
#[cfg(target_arch = "s390x")]
|
||||
{
|
||||
let ccw_dev = ccw::Device::from_str(&interface.devicePath).map_ttrpc_err(|e| {
|
||||
format!("Unexpected CCW path for network interface: {:?}", e)
|
||||
})?;
|
||||
wait_for_ccw_net_interface(&self.sandbox, &ccw_dev)
|
||||
.await
|
||||
.map_ttrpc_err(|e| format!("interface not available: {:?}", e))?;
|
||||
}
|
||||
}
|
||||
|
||||
self.sandbox
|
||||
|
Loading…
Reference in New Issue
Block a user