mirror of
https://github.com/kata-containers/kata-containers.git
synced 2026-07-01 22:50:54 +00:00
agent: reconcile VFIO netdev MAC before UpdateInterface lookup
When a VFIO cold-plugged network device appears in guest with a different MAC than the runtime request, resolve the netdev by PCI path and apply the requested MAC before the normal by-MAC update flow. This preserves existing behavior while avoiding UpdateInterface mismatches in SR-IOV cold-plug cases. Signed-off-by: Fabiano Fidêncio <ffidencio@nvidia.com> Assisted-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,6 +3,10 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#[cfg(not(target_arch = "s390x"))]
|
||||
use crate::linux_abi::{create_pci_root_bus_path, pcipath_from_dev_tree_path, SYSFS_DIR};
|
||||
#[cfg(not(target_arch = "s390x"))]
|
||||
use crate::{device::pcipath_to_sysfs, pci};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use futures::{future, TryStreamExt};
|
||||
use ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network};
|
||||
@@ -227,6 +231,60 @@ impl Handle {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "s390x"))]
|
||||
pub fn netdev_name_from_pci_path(&self, dev_tree_path: &str) -> Result<Option<String>> {
|
||||
let (root_complex, pcipath) = pcipath_from_dev_tree_path(dev_tree_path)
|
||||
.with_context(|| format!("invalid PCI path for network interface: {dev_tree_path}"))?;
|
||||
let root_bus_sysfs = format!("{}{}", SYSFS_DIR, create_pci_root_bus_path(root_complex));
|
||||
let sysfs_rel_path = pcilib_to_sysfs_path(&root_bus_sysfs, &pcipath)?;
|
||||
let net_dir = format!("{root_bus_sysfs}{sysfs_rel_path}/net");
|
||||
|
||||
let mut entries = match fs::read_dir(&net_dir) {
|
||||
Ok(entries) => entries,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(None),
|
||||
Err(e) => return Err(e).with_context(|| format!("failed to read net dir {net_dir}")),
|
||||
};
|
||||
|
||||
if let Some(entry) = entries.next() {
|
||||
let entry = entry.with_context(|| format!("failed to read entry under {net_dir}"))?;
|
||||
let name = entry.file_name().into_string().map_err(|non_utf8| {
|
||||
anyhow!("non-UTF8 netdev name under {}: {:?}", net_dir, non_utf8)
|
||||
})?;
|
||||
return Ok(Some(name));
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "s390x"))]
|
||||
pub async fn set_link_mac_by_name(&self, ifname: &str, mac: &str) -> Result<String> {
|
||||
let link = self.find_link(LinkFilter::Name(ifname)).await?;
|
||||
let prev_mac = link.address();
|
||||
if prev_mac.eq_ignore_ascii_case(mac) {
|
||||
return Ok(prev_mac);
|
||||
}
|
||||
|
||||
let parsed_mac = parse_mac_address(mac)
|
||||
.with_context(|| format!("failed to parse MAC address: {mac}"))?;
|
||||
if link.is_up() {
|
||||
self.enable_link(link.index(), false).await?;
|
||||
}
|
||||
|
||||
let mut request = self.handle.link().set(link.index());
|
||||
request.message_mut().header = link.header.clone();
|
||||
request
|
||||
.address(parsed_mac.to_vec())
|
||||
.execute()
|
||||
.await
|
||||
.with_context(|| format!("failed to set MAC for interface {} to {}", ifname, mac))?;
|
||||
|
||||
if link.is_up() {
|
||||
self.enable_link(link.index(), true).await?;
|
||||
}
|
||||
|
||||
Ok(prev_mac)
|
||||
}
|
||||
|
||||
/// Retireve available network interfaces.
|
||||
pub async fn list_interfaces(&self) -> Result<Vec<Interface>> {
|
||||
let mut list = Vec::new();
|
||||
@@ -668,6 +726,11 @@ impl Handle {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "s390x"))]
|
||||
fn pcilib_to_sysfs_path(root_bus_sysfs: &str, pcipath: &pci::Path) -> Result<String> {
|
||||
pcipath_to_sysfs(root_bus_sysfs, pcipath)
|
||||
}
|
||||
|
||||
fn format_address(data: &[u8]) -> Result<String> {
|
||||
match data.len() {
|
||||
4 => {
|
||||
|
||||
@@ -1150,9 +1150,51 @@ impl agent_ttrpc::AgentService for AgentService {
|
||||
}
|
||||
}
|
||||
|
||||
self.sandbox
|
||||
.lock()
|
||||
.await
|
||||
let mut sandbox = self.sandbox.lock().await;
|
||||
|
||||
#[cfg(not(target_arch = "s390x"))]
|
||||
if !interface.devicePath.is_empty() && !interface.hwAddr.is_empty() {
|
||||
match sandbox
|
||||
.rtnl
|
||||
.netdev_name_from_pci_path(&interface.devicePath)
|
||||
{
|
||||
Ok(Some(netdev_name)) => {
|
||||
if let Err(err) = sandbox
|
||||
.rtnl
|
||||
.set_link_mac_by_name(&netdev_name, &interface.hwAddr)
|
||||
.await
|
||||
{
|
||||
warn!(
|
||||
sl(),
|
||||
"update_interface: VFIO MAC reconciliation failed, fallback to by-MAC lookup";
|
||||
"device-path" => interface.devicePath.as_str(),
|
||||
"target-mac" => interface.hwAddr.as_str(),
|
||||
"netdev" => netdev_name.as_str(),
|
||||
"error" => format!("{:?}", err),
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(None) => {
|
||||
info!(
|
||||
sl(),
|
||||
"update_interface: no netdev found for PCI path before by-MAC lookup";
|
||||
"device-path" => interface.devicePath.as_str(),
|
||||
"target-mac" => interface.hwAddr.as_str(),
|
||||
);
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(
|
||||
sl(),
|
||||
"update_interface: unable to resolve netdev from PCI path, fallback to by-MAC lookup";
|
||||
"device-path" => interface.devicePath.as_str(),
|
||||
"target-mac" => interface.hwAddr.as_str(),
|
||||
"error" => format!("{:?}", err),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sandbox
|
||||
.rtnl
|
||||
.update_interface(&interface)
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user