runtime-rs: Iterates through PCI devices to find a match with qdev_id

The get_pci_path_by_qdev_id function is designed to search for a PCI
device within a given list of devices based on a specified qdev_id.
It tracks the device's path in the PCI topology by recording the slot
values of the devices traversed during the search. If the device is
located behind a PCI bridge, the function recursively explores the
bridge's device list to find the target device. The function returns
the matching device along with its updated path if found, otherwise,
it returns None.

Fixes #11143

Signed-off-by: alex.lyn <alex.lyn@antgroup.com>
This commit is contained in:
alex.lyn
2025-04-12 23:00:53 +08:00
parent 9a03815f18
commit 80bd71bfcc

View File

@@ -3,10 +3,12 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
use crate::device::pci_path::PciPath;
use crate::qemu::cmdline_generator::{DeviceVirtioNet, Netdev}; use crate::qemu::cmdline_generator::{DeviceVirtioNet, Netdev};
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use nix::sys::socket::{sendmsg, ControlMessage, MsgFlags}; use nix::sys::socket::{sendmsg, ControlMessage, MsgFlags};
use std::convert::TryFrom;
use std::fmt::{Debug, Error, Formatter}; use std::fmt::{Debug, Error, Formatter};
use std::io::BufReader; use std::io::BufReader;
use std::os::fd::{AsRawFd, RawFd}; use std::os::fd::{AsRawFd, RawFd};
@@ -14,7 +16,7 @@ use std::os::unix::net::UnixStream;
use std::time::Duration; use std::time::Duration;
use qapi::qmp; use qapi::qmp;
use qapi_qmp; use qapi_qmp::{self, PciDeviceInfo};
use qapi_spec::Dictionary; use qapi_spec::Dictionary;
pub struct Qmp { pub struct Qmp {
@@ -467,8 +469,56 @@ impl Qmp {
Ok(()) Ok(())
} }
pub fn get_device_by_qdev_id(&mut self, qdev_id: &str) -> Result<PciPath> {
let format_str = |vec: &Vec<i64>| -> String {
vec.iter()
.map(|num| format!("{:02x}", num))
.collect::<Vec<String>>()
.join("/")
};
let mut path = vec![];
let pci = self.qmp.execute(&qapi_qmp::query_pci {})?;
for pci_info in pci.iter() {
if let Some(_device) = get_pci_path_by_qdev_id(&pci_info.devices, qdev_id, &mut path) {
let pci_path = format_str(&path);
return PciPath::try_from(pci_path.as_str());
}
}
Err(anyhow!("no target device found"))
}
} }
fn vcpu_id_from_core_id(core_id: i64) -> String { fn vcpu_id_from_core_id(core_id: i64) -> String {
format!("cpu-{}", core_id) format!("cpu-{}", core_id)
} }
// The get_pci_path_by_qdev_id function searches a device list for a device matching a given qdev_id,
// tracking the device's path. It recursively explores bridge devices and returns the found device along
// with its updated path.
pub fn get_pci_path_by_qdev_id(
devices: &[PciDeviceInfo],
qdev_id: &str,
path: &mut Vec<i64>,
) -> Option<PciDeviceInfo> {
for device in devices {
path.push(device.slot);
if device.qdev_id == qdev_id {
return Some(device.clone());
}
if let Some(ref bridge) = device.pci_bridge {
if let Some(ref bridge_devices) = bridge.devices {
if let Some(found_device) = get_pci_path_by_qdev_id(bridge_devices, qdev_id, path) {
return Some(found_device);
}
}
}
// If the device not found, pop the current slot before moving to next device
path.pop();
}
None
}