mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-04-29 12:14:48 +00:00
runtime-rs: support physical endpoint using device manager
use device manager to attach physical endpoint Fixes: #7103 Signed-off-by: Zhongtao Hu <zhongtaohu.tim@linux.alibaba.com>
This commit is contained in:
parent
ce8e3cc091
commit
bff4672f7d
@ -77,6 +77,7 @@ impl SharedInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Device manager will manage the lifecycle of sandbox device
|
// Device manager will manage the lifecycle of sandbox device
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct DeviceManager {
|
pub struct DeviceManager {
|
||||||
devices: HashMap<String, ArcMutexDevice>,
|
devices: HashMap<String, ArcMutexDevice>,
|
||||||
hypervisor: Arc<dyn Hypervisor>,
|
hypervisor: Arc<dyn Hypervisor>,
|
||||||
|
@ -50,7 +50,7 @@ impl fmt::Display for DeviceType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait Device: Send + Sync {
|
pub trait Device: std::fmt::Debug + Send + Sync {
|
||||||
// attach is to plug device into VM
|
// attach is to plug device into VM
|
||||||
async fn attach(&mut self, h: &dyn hypervisor) -> Result<()>;
|
async fn attach(&mut self, h: &dyn hypervisor) -> Result<()>;
|
||||||
// detach is to unplug device from VM
|
// detach is to unplug device from VM
|
||||||
|
@ -28,6 +28,7 @@ use std::{collections::HashSet, fs::create_dir_all, path::PathBuf};
|
|||||||
const DRAGONBALL_KERNEL: &str = "vmlinux";
|
const DRAGONBALL_KERNEL: &str = "vmlinux";
|
||||||
const DRAGONBALL_ROOT_FS: &str = "rootfs";
|
const DRAGONBALL_ROOT_FS: &str = "rootfs";
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct DragonballInner {
|
pub struct DragonballInner {
|
||||||
/// sandbox id
|
/// sandbox id
|
||||||
pub(crate) id: String,
|
pub(crate) id: String,
|
||||||
|
@ -22,6 +22,7 @@ use tokio::sync::RwLock;
|
|||||||
|
|
||||||
use crate::{DeviceType, Hypervisor, VcpuThreadIds};
|
use crate::{DeviceType, Hypervisor, VcpuThreadIds};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Dragonball {
|
pub struct Dragonball {
|
||||||
inner: Arc<RwLock<DragonballInner>>,
|
inner: Arc<RwLock<DragonballInner>>,
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ const DRAGONBALL_VERSION: &str = env!("CARGO_PKG_VERSION");
|
|||||||
const REQUEST_RETRY: u32 = 500;
|
const REQUEST_RETRY: u32 = 500;
|
||||||
const KVM_DEVICE: &str = "/dev/kvm";
|
const KVM_DEVICE: &str = "/dev/kvm";
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct VmmInstance {
|
pub struct VmmInstance {
|
||||||
/// VMM instance info directly accessible from runtime
|
/// VMM instance info directly accessible from runtime
|
||||||
vmm_shared_info: Arc<RwLock<InstanceInfo>>,
|
vmm_shared_info: Arc<RwLock<InstanceInfo>>,
|
||||||
|
@ -70,7 +70,7 @@ pub struct VcpuThreadIds {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait Hypervisor: Send + Sync {
|
pub trait Hypervisor: std::fmt::Debug + Send + Sync {
|
||||||
// vm manager
|
// vm manager
|
||||||
async fn prepare_vm(&self, id: &str, netns: Option<String>) -> Result<()>;
|
async fn prepare_vm(&self, id: &str, netns: Option<String>) -> Result<()>;
|
||||||
async fn start_vm(&self, timeout: i32) -> Result<()>;
|
async fn start_vm(&self, timeout: i32) -> Result<()>;
|
||||||
|
@ -11,7 +11,7 @@ use kata_types::capabilities::{Capabilities, CapabilityBits};
|
|||||||
const VSOCK_SCHEME: &str = "vsock";
|
const VSOCK_SCHEME: &str = "vsock";
|
||||||
const VSOCK_AGENT_CID: u32 = 3;
|
const VSOCK_AGENT_CID: u32 = 3;
|
||||||
const VSOCK_AGENT_PORT: u32 = 1024;
|
const VSOCK_AGENT_PORT: u32 = 1024;
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct QemuInner {
|
pub struct QemuInner {
|
||||||
config: HypervisorConfig,
|
config: HypervisorConfig,
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ use async_trait::async_trait;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Qemu {
|
pub struct Qemu {
|
||||||
inner: Arc<RwLock<QemuInner>>,
|
inner: Arc<RwLock<QemuInner>>,
|
||||||
}
|
}
|
||||||
|
@ -142,10 +142,11 @@ impl ResourceManagerInner {
|
|||||||
// The solution is to block the future on the current thread, it is enabled by spawn an os thread, create a
|
// The solution is to block the future on the current thread, it is enabled by spawn an os thread, create a
|
||||||
// tokio runtime, and block the task on it.
|
// tokio runtime, and block the task on it.
|
||||||
let hypervisor = self.hypervisor.clone();
|
let hypervisor = self.hypervisor.clone();
|
||||||
|
let device_manager = self.device_manager.clone();
|
||||||
let network = thread::spawn(move || -> Result<Arc<dyn Network>> {
|
let network = thread::spawn(move || -> Result<Arc<dyn Network>> {
|
||||||
let rt = runtime::Builder::new_current_thread().enable_io().build()?;
|
let rt = runtime::Builder::new_current_thread().enable_io().build()?;
|
||||||
let d = rt
|
let d = rt
|
||||||
.block_on(network::new(&network_config))
|
.block_on(network::new(&network_config, device_manager))
|
||||||
.context("new network")?;
|
.context("new network")?;
|
||||||
rt.block_on(d.setup(hypervisor.as_ref()))
|
rt.block_on(d.setup(hypervisor.as_ref()))
|
||||||
.context("setup network")?;
|
.context("setup network")?;
|
||||||
|
@ -5,12 +5,15 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use hypervisor::device::DeviceType;
|
use hypervisor::device::device_manager::{do_handle_device, DeviceManager};
|
||||||
|
use hypervisor::device::DeviceConfig;
|
||||||
use hypervisor::{device::driver, Hypervisor};
|
use hypervisor::{device::driver, Hypervisor};
|
||||||
use hypervisor::{HostDevice, VfioDevice};
|
use hypervisor::{get_vfio_device, VfioConfig};
|
||||||
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
use super::endpoint_persist::{EndpointState, PhysicalEndpointState};
|
use super::endpoint_persist::{EndpointState, PhysicalEndpointState};
|
||||||
use super::Endpoint;
|
use super::Endpoint;
|
||||||
@ -50,10 +53,11 @@ pub struct PhysicalEndpoint {
|
|||||||
bdf: String,
|
bdf: String,
|
||||||
driver: String,
|
driver: String,
|
||||||
vendor_device_id: VendorDevice,
|
vendor_device_id: VendorDevice,
|
||||||
|
d: Arc<RwLock<DeviceManager>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PhysicalEndpoint {
|
impl PhysicalEndpoint {
|
||||||
pub fn new(name: &str, hardware_addr: &[u8]) -> Result<Self> {
|
pub fn new(name: &str, hardware_addr: &[u8], d: Arc<RwLock<DeviceManager>>) -> Result<Self> {
|
||||||
let driver_info = link::get_driver_info(name).context("get driver info")?;
|
let driver_info = link::get_driver_info(name).context("get driver info")?;
|
||||||
let bdf = driver_info.bus_info;
|
let bdf = driver_info.bus_info;
|
||||||
let sys_pci_devices_path = Path::new(SYS_PCI_DEVICES_PATH);
|
let sys_pci_devices_path = Path::new(SYS_PCI_DEVICES_PATH);
|
||||||
@ -80,6 +84,7 @@ impl PhysicalEndpoint {
|
|||||||
.context("new vendor device")?,
|
.context("new vendor device")?,
|
||||||
driver,
|
driver,
|
||||||
bdf,
|
bdf,
|
||||||
|
d,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,7 +99,7 @@ impl Endpoint for PhysicalEndpoint {
|
|||||||
self.hard_addr.clone()
|
self.hard_addr.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn attach(&self, hypervisor: &dyn Hypervisor) -> Result<()> {
|
async fn attach(&self, _hypervisor: &dyn Hypervisor) -> Result<()> {
|
||||||
// bind physical interface from host driver and bind to vfio
|
// bind physical interface from host driver and bind to vfio
|
||||||
driver::bind_device_to_vfio(
|
driver::bind_device_to_vfio(
|
||||||
&self.bdf,
|
&self.bdf,
|
||||||
@ -103,24 +108,19 @@ impl Endpoint for PhysicalEndpoint {
|
|||||||
)
|
)
|
||||||
.with_context(|| format!("bind physical endpoint from {} to vfio", &self.driver))?;
|
.with_context(|| format!("bind physical endpoint from {} to vfio", &self.driver))?;
|
||||||
|
|
||||||
// set vfio's bus type, pci or mmio. Mostly use pci by default.
|
let vfio_device = get_vfio_device(self.bdf.clone()).context("get vfio device failed.")?;
|
||||||
let mode = match self.driver.as_str() {
|
let vfio_dev_config = &mut VfioConfig {
|
||||||
"virtio-pci" => "mmio",
|
host_path: vfio_device.clone(),
|
||||||
_ => "pci",
|
dev_type: "pci".to_string(),
|
||||||
|
hostdev_prefix: "physical_nic_".to_owned(),
|
||||||
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
// add vfio device
|
// create and insert VFIO device into Kata VM
|
||||||
let d = DeviceType::Vfio(VfioDevice {
|
do_handle_device(&self.d, &DeviceConfig::VfioCfg(vfio_dev_config.clone()))
|
||||||
attach_count: 0,
|
.await
|
||||||
bus_mode: driver::VfioBusMode::new(mode),
|
.context("do handle device failed.")?;
|
||||||
devices: vec![HostDevice {
|
|
||||||
hostdev_id: format!("physical_nic_{}", self.name().await),
|
|
||||||
bus_slot_func: self.bdf.clone(),
|
|
||||||
..Default::default()
|
|
||||||
}],
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
hypervisor.add_device(d).await.context("add device")?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
mod endpoint;
|
mod endpoint;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub use endpoint::endpoint_persist::EndpointState;
|
pub use endpoint::endpoint_persist::EndpointState;
|
||||||
pub use endpoint::Endpoint;
|
pub use endpoint::Endpoint;
|
||||||
mod network_entity;
|
mod network_entity;
|
||||||
@ -20,11 +22,11 @@ use network_pair::NetworkPair;
|
|||||||
mod utils;
|
mod utils;
|
||||||
pub use utils::netns::{generate_netns_name, NetnsGuard};
|
pub use utils::netns::{generate_netns_name, NetnsGuard};
|
||||||
|
|
||||||
use std::sync::Arc;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use hypervisor::Hypervisor;
|
use hypervisor::{device::device_manager::DeviceManager, Hypervisor};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum NetworkConfig {
|
pub enum NetworkConfig {
|
||||||
@ -41,10 +43,13 @@ pub trait Network: Send + Sync {
|
|||||||
async fn remove(&self, h: &dyn Hypervisor) -> Result<()>;
|
async fn remove(&self, h: &dyn Hypervisor) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn new(config: &NetworkConfig) -> Result<Arc<dyn Network>> {
|
pub async fn new(
|
||||||
|
config: &NetworkConfig,
|
||||||
|
d: Arc<RwLock<DeviceManager>>,
|
||||||
|
) -> Result<Arc<dyn Network>> {
|
||||||
match config {
|
match config {
|
||||||
NetworkConfig::NetworkResourceWithNetNs(c) => Ok(Arc::new(
|
NetworkConfig::NetworkResourceWithNetNs(c) => Ok(Arc::new(
|
||||||
NetworkWithNetns::new(c)
|
NetworkWithNetns::new(c, d)
|
||||||
.await
|
.await
|
||||||
.context("new network with netns")?,
|
.context("new network with netns")?,
|
||||||
)),
|
)),
|
||||||
|
@ -16,7 +16,7 @@ use super::endpoint::endpoint_persist::EndpointState;
|
|||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::stream::TryStreamExt;
|
use futures::stream::TryStreamExt;
|
||||||
use hypervisor::Hypervisor;
|
use hypervisor::{device::device_manager::DeviceManager, Hypervisor};
|
||||||
use netns_rs::get_from_path;
|
use netns_rs::get_from_path;
|
||||||
use scopeguard::defer;
|
use scopeguard::defer;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
@ -47,13 +47,13 @@ struct NetworkWithNetnsInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NetworkWithNetnsInner {
|
impl NetworkWithNetnsInner {
|
||||||
async fn new(config: &NetworkWithNetNsConfig) -> Result<Self> {
|
async fn new(config: &NetworkWithNetNsConfig, d: Arc<RwLock<DeviceManager>>) -> Result<Self> {
|
||||||
let entity_list = if config.netns_path.is_empty() {
|
let entity_list = if config.netns_path.is_empty() {
|
||||||
warn!(sl!(), "skip to scan for empty netns");
|
warn!(sl!(), "skip to scan for empty netns");
|
||||||
vec![]
|
vec![]
|
||||||
} else {
|
} else {
|
||||||
// get endpoint
|
// get endpoint
|
||||||
get_entity_from_netns(config)
|
get_entity_from_netns(config, d)
|
||||||
.await
|
.await
|
||||||
.context("get entity from netns")?
|
.context("get entity from netns")?
|
||||||
};
|
};
|
||||||
@ -70,9 +70,12 @@ pub(crate) struct NetworkWithNetns {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NetworkWithNetns {
|
impl NetworkWithNetns {
|
||||||
pub(crate) async fn new(config: &NetworkWithNetNsConfig) -> Result<Self> {
|
pub(crate) async fn new(
|
||||||
|
config: &NetworkWithNetNsConfig,
|
||||||
|
d: Arc<RwLock<DeviceManager>>,
|
||||||
|
) -> Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
inner: Arc::new(RwLock::new(NetworkWithNetnsInner::new(config).await?)),
|
inner: Arc::new(RwLock::new(NetworkWithNetnsInner::new(config, d).await?)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,10 +152,13 @@ impl Network for NetworkWithNetns {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_entity_from_netns(config: &NetworkWithNetNsConfig) -> Result<Vec<NetworkEntity>> {
|
async fn get_entity_from_netns(
|
||||||
|
config: &NetworkWithNetNsConfig,
|
||||||
|
d: Arc<RwLock<DeviceManager>>,
|
||||||
|
) -> Result<Vec<NetworkEntity>> {
|
||||||
info!(
|
info!(
|
||||||
sl!(),
|
sl!(),
|
||||||
"get network entity for config {:?} tid {:?}",
|
"get network entity from config {:?} tid {:?}",
|
||||||
config,
|
config,
|
||||||
nix::unistd::gettid()
|
nix::unistd::gettid()
|
||||||
);
|
);
|
||||||
@ -178,9 +184,10 @@ async fn get_entity_from_netns(config: &NetworkWithNetNsConfig) -> Result<Vec<Ne
|
|||||||
}
|
}
|
||||||
|
|
||||||
let idx = idx.fetch_add(1, Ordering::Relaxed);
|
let idx = idx.fetch_add(1, Ordering::Relaxed);
|
||||||
let (endpoint, network_info) = create_endpoint(&handle, link.as_ref(), idx, config)
|
let (endpoint, network_info) =
|
||||||
.await
|
create_endpoint(&handle, link.as_ref(), idx, config, d.clone())
|
||||||
.context("create endpoint")?;
|
.await
|
||||||
|
.context("create endpoint")?;
|
||||||
|
|
||||||
entity_list.push(NetworkEntity::new(endpoint, network_info));
|
entity_list.push(NetworkEntity::new(endpoint, network_info));
|
||||||
}
|
}
|
||||||
@ -193,6 +200,7 @@ async fn create_endpoint(
|
|||||||
link: &dyn link::Link,
|
link: &dyn link::Link,
|
||||||
idx: u32,
|
idx: u32,
|
||||||
config: &NetworkWithNetNsConfig,
|
config: &NetworkWithNetNsConfig,
|
||||||
|
d: Arc<RwLock<DeviceManager>>,
|
||||||
) -> Result<(Arc<dyn Endpoint>, Arc<dyn NetworkInfo>)> {
|
) -> Result<(Arc<dyn Endpoint>, Arc<dyn NetworkInfo>)> {
|
||||||
let _netns_guard = netns::NetnsGuard::new(&config.netns_path)
|
let _netns_guard = netns::NetnsGuard::new(&config.netns_path)
|
||||||
.context("net netns guard")
|
.context("net netns guard")
|
||||||
@ -206,7 +214,7 @@ async fn create_endpoint(
|
|||||||
&attrs.name,
|
&attrs.name,
|
||||||
nix::unistd::gettid()
|
nix::unistd::gettid()
|
||||||
);
|
);
|
||||||
let t = PhysicalEndpoint::new(&attrs.name, &attrs.hardware_addr)
|
let t = PhysicalEndpoint::new(&attrs.name, &attrs.hardware_addr, d)
|
||||||
.context("new physical endpoint")?;
|
.context("new physical endpoint")?;
|
||||||
Arc::new(t)
|
Arc::new(t)
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user