mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: Add support for hotplugging a vDPA device
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
@@ -18,7 +18,7 @@ use crate::api::{
|
||||
};
|
||||
use crate::config::{
|
||||
add_to_config, DeviceConfig, DiskConfig, FsConfig, NetConfig, PmemConfig, RestoreConfig,
|
||||
UserDeviceConfig, VmConfig, VsockConfig,
|
||||
UserDeviceConfig, VdpaConfig, VmConfig, VsockConfig,
|
||||
};
|
||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||
use crate::migration::get_vm_snapshot;
|
||||
@@ -925,6 +925,32 @@ impl Vmm {
|
||||
}
|
||||
}
|
||||
|
||||
fn vm_add_vdpa(&mut self, vdpa_cfg: VdpaConfig) -> result::Result<Option<Vec<u8>>, VmError> {
|
||||
self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
|
||||
|
||||
{
|
||||
// Validate the configuration change in a cloned configuration
|
||||
let mut config = self.vm_config.as_ref().unwrap().lock().unwrap().clone();
|
||||
add_to_config(&mut config.vdpa, vdpa_cfg.clone());
|
||||
config.validate().map_err(VmError::ConfigValidation)?;
|
||||
}
|
||||
|
||||
if let Some(ref mut vm) = self.vm {
|
||||
let info = vm.add_vdpa(vdpa_cfg).map_err(|e| {
|
||||
error!("Error when adding new vDPA device to the VM: {:?}", e);
|
||||
e
|
||||
})?;
|
||||
serde_json::to_vec(&info)
|
||||
.map(Some)
|
||||
.map_err(VmError::SerializeJson)
|
||||
} else {
|
||||
// Update VmConfig by adding the new device.
|
||||
let mut config = self.vm_config.as_ref().unwrap().lock().unwrap();
|
||||
add_to_config(&mut config.vdpa, vdpa_cfg);
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn vm_add_vsock(&mut self, vsock_cfg: VsockConfig) -> result::Result<Option<Vec<u8>>, VmError> {
|
||||
self.vm_config.as_ref().ok_or(VmError::VmNotCreated)?;
|
||||
|
||||
@@ -1742,6 +1768,13 @@ impl Vmm {
|
||||
.map(ApiResponsePayload::VmAction);
|
||||
sender.send(response).map_err(Error::ApiResponseSend)?;
|
||||
}
|
||||
ApiRequest::VmAddVdpa(add_vdpa_data, sender) => {
|
||||
let response = self
|
||||
.vm_add_vdpa(add_vdpa_data.as_ref().clone())
|
||||
.map_err(ApiError::VmAddVdpa)
|
||||
.map(ApiResponsePayload::VmAction);
|
||||
sender.send(response).map_err(Error::ApiResponseSend)?;
|
||||
}
|
||||
ApiRequest::VmAddVsock(add_vsock_data, sender) => {
|
||||
let response = self
|
||||
.vm_add_vsock(add_vsock_data.as_ref().clone())
|
||||
@@ -2199,6 +2232,54 @@ mod unit_tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vmm_vm_cold_add_vdpa() {
|
||||
let mut vmm = create_dummy_vmm();
|
||||
let vdpa_config = VdpaConfig::parse("path=/dev/vhost-vdpa,num_queues=2").unwrap();
|
||||
|
||||
assert!(matches!(
|
||||
vmm.vm_add_vdpa(vdpa_config.clone()),
|
||||
Err(VmError::VmNotCreated)
|
||||
));
|
||||
|
||||
let _ = vmm.vm_create(create_dummy_vm_config());
|
||||
assert!(vmm
|
||||
.vm_config
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.vdpa
|
||||
.is_none());
|
||||
|
||||
let result = vmm.vm_add_vdpa(vdpa_config.clone());
|
||||
assert!(result.is_ok());
|
||||
assert!(result.unwrap().is_none());
|
||||
assert_eq!(
|
||||
vmm.vm_config
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.vdpa
|
||||
.clone()
|
||||
.unwrap()
|
||||
.len(),
|
||||
1
|
||||
);
|
||||
assert_eq!(
|
||||
vmm.vm_config
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.vdpa
|
||||
.clone()
|
||||
.unwrap()[0],
|
||||
vdpa_config
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vmm_vm_cold_add_vsock() {
|
||||
let mut vmm = create_dummy_vmm();
|
||||
|
||||
Reference in New Issue
Block a user