runtime-rs: Introduce device type of PordDevice in device manager

PortDevice is for handling root ports or switch ports in PCIe
Topology. It will make it easy pass the root ports/switch ports
information during create VM with requirements of PCIe devices.

Fixes #10361

Signed-off-by: alex.lyn <alex.lyn@antgroup.com>
This commit is contained in:
alex.lyn 2025-04-11 16:58:53 +08:00
parent 694a849eaa
commit f08fdd25d8
4 changed files with 136 additions and 5 deletions

View File

@ -13,7 +13,7 @@ use tokio::sync::{Mutex, RwLock};
use crate::{
vhost_user_blk::VhostUserBlkDevice, BlockConfig, BlockDevice, HybridVsockDevice, Hypervisor,
NetworkDevice, ProtectionDevice, ShareFsDevice, VfioDevice, VhostUserConfig,
NetworkDevice, PCIePortDevice, ProtectionDevice, ShareFsDevice, VfioDevice, VhostUserConfig,
VhostUserNetDevice, VsockDevice, KATA_BLK_DEV_TYPE, KATA_CCW_DEV_TYPE, KATA_MMIO_BLK_DEV_TYPE,
KATA_NVDIMM_DEV_TYPE, VIRTIO_BLOCK_CCW, VIRTIO_BLOCK_MMIO, VIRTIO_BLOCK_PCI, VIRTIO_PMEM,
};
@ -112,6 +112,10 @@ impl DeviceManager {
})
}
pub fn get_pcie_topology(&self) -> Option<PCIeTopology> {
self.pcie_topology.clone()
}
async fn get_block_driver(&self) -> String {
self.hypervisor
.hypervisor_config()
@ -250,7 +254,10 @@ impl DeviceManager {
return Some(device_id.to_string());
}
}
DeviceType::HybridVsock(_) | DeviceType::Vsock(_) | DeviceType::Protection(_) => {
DeviceType::HybridVsock(_)
| DeviceType::Vsock(_)
| DeviceType::Protection(_)
| DeviceType::PortDevice(_) => {
continue;
}
}
@ -393,6 +400,9 @@ impl DeviceManager {
pconfig,
)))
}
DeviceConfig::PortDeviceCfg(config) => {
Arc::new(Mutex::new(PCIePortDevice::new(&device_id, config)))
}
};
// register device to devices

View File

@ -4,6 +4,7 @@
// SPDX-License-Identifier: Apache-2.0
//
mod port_device;
mod protection_device;
mod vfio;
mod vhost_user;
@ -14,6 +15,7 @@ mod virtio_fs;
mod virtio_net;
mod virtio_vsock;
pub use port_device::{PCIePortDevice, PortDeviceConfig};
pub use protection_device::{ProtectionDevice, ProtectionDeviceConfig, SevSnpConfig};
pub use vfio::{
bind_device_to_host, bind_device_to_vfio, get_vfio_device, HostDevice, VfioBusMode, VfioConfig,

View File

@ -0,0 +1,117 @@
// Copyright (c) 2024-2025 Ant Group
//
// SPDX-License-Identifier: Apache-2.0
//
//use std::collections::HashMap;
use std::collections::HashMap;
use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
use crate::device::{
hypervisor,
topology::{PCIePort, PCIeTopology, Strategy, TopologyPortDevice},
Device, DeviceType,
};
#[derive(Debug, Default, Clone)]
pub struct PortDeviceConfig {
pub port_type: PCIePort,
pub total_ports: u32,
pub memsz_reserve: u64,
pub pref64_reserve: u64,
}
impl PortDeviceConfig {
pub fn new(port_type: PCIePort, total_ports: u32) -> Self {
Self {
port_type,
total_ports,
// FIXME:
// A method to automatically determine the maximum memory size
// based on all vfio devices' information on the host is coming soon.
memsz_reserve: 33554432_u64,
pref64_reserve: 536870912_u64,
}
}
}
#[derive(Debug, Default, Clone)]
pub struct PCIePortDevice {
/// device id for sharefs device in device manager
pub device_id: String,
/// config for sharefs device
pub config: PortDeviceConfig,
pub port_devices: HashMap<u32, TopologyPortDevice>,
}
impl PCIePortDevice {
pub fn new(device_id: &str, config: &PortDeviceConfig) -> Self {
Self {
device_id: device_id.to_string(),
config: config.clone(),
port_devices: HashMap::with_capacity(config.total_ports as usize),
}
}
}
#[async_trait]
impl Device for PCIePortDevice {
async fn attach(
&mut self,
pcie_topo: &mut Option<&mut PCIeTopology>,
h: &dyn hypervisor,
) -> Result<()> {
if let Some(topology) = pcie_topo {
match self.config.port_type {
PCIePort::RootPort => {
topology.add_root_ports_on_bus(topology.pcie_root_ports)?;
self.port_devices = topology.pcie_port_devices.clone();
}
PCIePort::SwitchPort => {
topology.add_switch_ports_with_strategy(
topology.pcie_switch_ports,
topology.pcie_switch_ports,
Strategy::SingleRootPort,
)?;
self.port_devices = topology.pcie_port_devices.clone();
}
_ => return Err(anyhow!("unspported pcie port type")),
};
info!(sl!(), "add device for PortDevice: {:?}", self.clone());
h.add_device(DeviceType::PortDevice(self.clone()))
.await
.context("add port devices.")?;
}
Ok(())
}
async fn detach(
&mut self,
_pcie_topo: &mut Option<&mut PCIeTopology>,
_h: &dyn hypervisor,
) -> Result<Option<u64>> {
Ok(None)
}
async fn update(&mut self, _h: &dyn hypervisor) -> Result<()> {
Ok(())
}
async fn get_device_info(&self) -> DeviceType {
DeviceType::PortDevice(self.clone())
}
async fn increase_attach_count(&mut self) -> Result<bool> {
Ok(false)
}
async fn decrease_attach_count(&mut self) -> Result<bool> {
Ok(false)
}
}

View File

@ -9,9 +9,9 @@ use std::fmt;
use crate::device::driver::vhost_user_blk::VhostUserBlkDevice;
use crate::{
BlockConfig, BlockDevice, HybridVsockConfig, HybridVsockDevice, Hypervisor as hypervisor,
NetworkConfig, NetworkDevice, ProtectionDevice, ProtectionDeviceConfig, ShareFsConfig,
ShareFsDevice, VfioConfig, VfioDevice, VhostUserConfig, VhostUserNetDevice, VsockConfig,
VsockDevice,
NetworkConfig, NetworkDevice, PCIePortDevice, PortDeviceConfig, ProtectionDevice,
ProtectionDeviceConfig, ShareFsConfig, ShareFsDevice, VfioConfig, VfioDevice, VhostUserConfig,
VhostUserNetDevice, VsockConfig, VsockDevice,
};
use anyhow::Result;
use async_trait::async_trait;
@ -37,6 +37,7 @@ pub enum DeviceConfig {
VsockCfg(VsockConfig),
HybridVsockCfg(HybridVsockConfig),
ProtectionDevCfg(ProtectionDeviceConfig),
PortDeviceCfg(PortDeviceConfig),
}
#[derive(Debug, Clone)]
@ -50,6 +51,7 @@ pub enum DeviceType {
HybridVsock(HybridVsockDevice),
Vsock(VsockDevice),
Protection(ProtectionDevice),
PortDevice(PCIePortDevice),
}
impl fmt::Display for DeviceType {