Skip to content

Commit a0e1523

Browse files
committed
test: VirtIO PCI device create and restoration
Refactor the test code that inserts VirtIO devices in a Vmm object and then add a test which creates a Vmm with PCI devices and then serializes and deserializes the device manager and ensures that everything is as restored as expected. Signed-off-by: Babis Chalios <[email protected]>
1 parent 872521e commit a0e1523

File tree

3 files changed

+224
-12
lines changed

3 files changed

+224
-12
lines changed

src/vmm/src/builder.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,6 @@ pub(crate) mod tests {
848848

849849
assert!(
850850
vmm.device_manager
851-
.mmio_devices
852851
.get_virtio_device(TYPE_VSOCK, &vsock_dev_id)
853852
.is_some()
854853
);
@@ -874,7 +873,6 @@ pub(crate) mod tests {
874873

875874
assert!(
876875
vmm.device_manager
877-
.mmio_devices
878876
.get_virtio_device(TYPE_RNG, ENTROPY_DEV_ID)
879877
.is_some()
880878
);
@@ -909,7 +907,6 @@ pub(crate) mod tests {
909907

910908
assert!(
911909
vmm.device_manager
912-
.mmio_devices
913910
.get_virtio_device(TYPE_BALLOON, BALLOON_DEV_ID)
914911
.is_some()
915912
);
@@ -961,7 +958,6 @@ pub(crate) mod tests {
961958
assert!(cmdline_contains(&cmdline, "root=/dev/vda ro"));
962959
assert!(
963960
vmm.device_manager
964-
.mmio_devices
965961
.get_virtio_device(TYPE_BLOCK, drive_id.as_str())
966962
.is_some()
967963
);
@@ -983,7 +979,6 @@ pub(crate) mod tests {
983979
assert!(cmdline_contains(&cmdline, "root=PARTUUID=0eaa91a0-01 rw"));
984980
assert!(
985981
vmm.device_manager
986-
.mmio_devices
987982
.get_virtio_device(TYPE_BLOCK, drive_id.as_str())
988983
.is_some()
989984
);
@@ -1006,7 +1001,6 @@ pub(crate) mod tests {
10061001
assert!(!cmdline_contains(&cmdline, "root=/dev/vda"));
10071002
assert!(
10081003
vmm.device_manager
1009-
.mmio_devices
10101004
.get_virtio_device(TYPE_BLOCK, drive_id.as_str())
10111005
.is_some()
10121006
);
@@ -1044,19 +1038,16 @@ pub(crate) mod tests {
10441038
assert!(cmdline_contains(&cmdline, "root=PARTUUID=0eaa91a0-01 rw"));
10451039
assert!(
10461040
vmm.device_manager
1047-
.mmio_devices
10481041
.get_virtio_device(TYPE_BLOCK, "root")
10491042
.is_some()
10501043
);
10511044
assert!(
10521045
vmm.device_manager
1053-
.mmio_devices
10541046
.get_virtio_device(TYPE_BLOCK, "secondary")
10551047
.is_some()
10561048
);
10571049
assert!(
10581050
vmm.device_manager
1059-
.mmio_devices
10601051
.get_virtio_device(TYPE_BLOCK, "third")
10611052
.is_some()
10621053
);
@@ -1086,7 +1077,6 @@ pub(crate) mod tests {
10861077
assert!(cmdline_contains(&cmdline, "root=/dev/vda rw"));
10871078
assert!(
10881079
vmm.device_manager
1089-
.mmio_devices
10901080
.get_virtio_device(TYPE_BLOCK, drive_id.as_str())
10911081
.is_some()
10921082
);
@@ -1108,7 +1098,6 @@ pub(crate) mod tests {
11081098
assert!(cmdline_contains(&cmdline, "root=PARTUUID=0eaa91a0-01 ro"));
11091099
assert!(
11101100
vmm.device_manager
1111-
.mmio_devices
11121101
.get_virtio_device(TYPE_BLOCK, drive_id.as_str())
11131102
.is_some()
11141103
);
@@ -1130,7 +1119,6 @@ pub(crate) mod tests {
11301119
assert!(cmdline_contains(&cmdline, "root=/dev/vda rw"));
11311120
assert!(
11321121
vmm.device_manager
1133-
.mmio_devices
11341122
.get_virtio_device(TYPE_BLOCK, drive_id.as_str())
11351123
.is_some()
11361124
);

src/vmm/src/device_manager/mod.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,36 @@ impl DeviceManager {
375375
Self::do_mark_virtio_queue_memory_dirty(virtio_device, mem);
376376
}
377377
}
378+
379+
/// Get a VirtIO device of type `virtio_type` with ID `device_id`
380+
pub fn get_virtio_device(
381+
&self,
382+
virtio_type: u32,
383+
device_id: &str,
384+
) -> Option<Arc<Mutex<dyn VirtioDevice>>> {
385+
if self.pci_devices.pci_segment.is_some() {
386+
let pci_device = self.pci_devices.get_virtio_device(virtio_type, device_id)?;
387+
Some(
388+
pci_device
389+
.lock()
390+
.expect("Poisoned lock")
391+
.virtio_device()
392+
.clone(),
393+
)
394+
} else {
395+
let mmio_device = self
396+
.mmio_devices
397+
.get_virtio_device(virtio_type, device_id)?;
398+
Some(
399+
mmio_device
400+
.inner
401+
.lock()
402+
.expect("Poisoned lock")
403+
.device()
404+
.clone(),
405+
)
406+
}
407+
}
378408
}
379409

380410
#[derive(Debug, Default, Clone, Serialize, Deserialize)]

src/vmm/src/device_manager/pci_mngr.rs

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,16 @@ impl PciDevices {
259259
event_manager.add_subscriber(device);
260260
Ok(())
261261
}
262+
263+
/// Gets the specified device.
264+
pub fn get_virtio_device(
265+
&self,
266+
device_type: u32,
267+
device_id: &str,
268+
) -> Option<&Arc<Mutex<VirtioPciDevice>>> {
269+
self.virtio_devices
270+
.get(&(device_type, device_id.to_string()))
271+
}
262272
}
263273

264274
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -617,3 +627,187 @@ impl<'a> Persist<'a> for PciDevices {
617627
Ok(pci_devices)
618628
}
619629
}
630+
631+
#[cfg(test)]
632+
mod tests {
633+
use vmm_sys_util::tempfile::TempFile;
634+
635+
use super::*;
636+
use crate::builder::tests::*;
637+
use crate::device_manager;
638+
use crate::devices::virtio::block::CacheType;
639+
use crate::mmds::data_store::MmdsVersion;
640+
use crate::resources::VmmConfig;
641+
use crate::snapshot::Snapshot;
642+
use crate::vmm_config::balloon::BalloonDeviceConfig;
643+
use crate::vmm_config::entropy::EntropyDeviceConfig;
644+
use crate::vmm_config::net::NetworkInterfaceConfig;
645+
use crate::vmm_config::vsock::VsockDeviceConfig;
646+
647+
#[test]
648+
fn test_device_manager_persistence() {
649+
let mut buf = vec![0; 65536];
650+
// These need to survive so the restored blocks find them.
651+
let _block_files;
652+
let mut tmp_sock_file = TempFile::new().unwrap();
653+
tmp_sock_file.remove().unwrap();
654+
// Set up a vmm with one of each device, and get the serialized DeviceStates.
655+
{
656+
let mut event_manager = EventManager::new().expect("Unable to create EventManager");
657+
let mut vmm = default_vmm();
658+
vmm.device_manager.enable_pci(&vmm.vm).unwrap();
659+
let mut cmdline = default_kernel_cmdline();
660+
661+
// Add a balloon device.
662+
let balloon_cfg = BalloonDeviceConfig {
663+
amount_mib: 123,
664+
deflate_on_oom: false,
665+
stats_polling_interval_s: 1,
666+
};
667+
insert_balloon_device(&mut vmm, &mut cmdline, &mut event_manager, balloon_cfg);
668+
// Add a block device.
669+
let drive_id = String::from("root");
670+
let block_configs = vec![CustomBlockConfig::new(
671+
drive_id,
672+
true,
673+
None,
674+
true,
675+
CacheType::Unsafe,
676+
)];
677+
_block_files =
678+
insert_block_devices(&mut vmm, &mut cmdline, &mut event_manager, block_configs);
679+
// Add a net device.
680+
let network_interface = NetworkInterfaceConfig {
681+
iface_id: String::from("netif"),
682+
host_dev_name: String::from("hostname"),
683+
guest_mac: None,
684+
rx_rate_limiter: None,
685+
tx_rate_limiter: None,
686+
};
687+
insert_net_device_with_mmds(
688+
&mut vmm,
689+
&mut cmdline,
690+
&mut event_manager,
691+
network_interface,
692+
MmdsVersion::V2,
693+
);
694+
// Add a vsock device.
695+
let vsock_dev_id = "vsock";
696+
let vsock_config = VsockDeviceConfig {
697+
vsock_id: Some(vsock_dev_id.to_string()),
698+
guest_cid: 3,
699+
uds_path: tmp_sock_file.as_path().to_str().unwrap().to_string(),
700+
};
701+
insert_vsock_device(&mut vmm, &mut cmdline, &mut event_manager, vsock_config);
702+
// Add an entropy device.
703+
let entropy_config = EntropyDeviceConfig::default();
704+
insert_entropy_device(&mut vmm, &mut cmdline, &mut event_manager, entropy_config);
705+
706+
Snapshot::serialize(&mut buf.as_mut_slice(), &vmm.device_manager.save()).unwrap();
707+
}
708+
709+
tmp_sock_file.remove().unwrap();
710+
711+
let mut event_manager = EventManager::new().expect("Unable to create EventManager");
712+
// Keep in mind we are re-creating here an empty DeviceManager. Restoring later on
713+
// will create a new PciDevices manager different than vmm.pci_devices. We're doing
714+
// this to avoid restoring the whole Vmm, since what we really need from Vmm is the Vm
715+
// object and calling default_vmm() is the easiest way to create one.
716+
let vmm = default_vmm();
717+
let device_manager_state: device_manager::DevicesState =
718+
Snapshot::deserialize(&mut buf.as_slice()).unwrap();
719+
let vm_resources = &mut VmResources::default();
720+
let restore_args = PciDevicesConstructorArgs {
721+
vm: vmm.vm.clone(),
722+
mem: vmm.vm.guest_memory(),
723+
vm_resources,
724+
instance_id: "microvm-id",
725+
restored_from_file: true,
726+
event_manager: &mut event_manager,
727+
};
728+
let _restored_dev_manager =
729+
PciDevices::restore(restore_args, &device_manager_state.pci_state).unwrap();
730+
731+
let expected_vm_resources = format!(
732+
r#"{{
733+
"balloon": {{
734+
"amount_mib": 123,
735+
"deflate_on_oom": false,
736+
"stats_polling_interval_s": 1
737+
}},
738+
"drives": [
739+
{{
740+
"drive_id": "root",
741+
"partuuid": null,
742+
"is_root_device": true,
743+
"cache_type": "Unsafe",
744+
"is_read_only": true,
745+
"path_on_host": "{}",
746+
"rate_limiter": null,
747+
"io_engine": "Sync",
748+
"socket": null
749+
}}
750+
],
751+
"boot-source": {{
752+
"kernel_image_path": "",
753+
"initrd_path": null,
754+
"boot_args": null
755+
}},
756+
"cpu-config": null,
757+
"logger": null,
758+
"machine-config": {{
759+
"vcpu_count": 1,
760+
"mem_size_mib": 128,
761+
"smt": false,
762+
"track_dirty_pages": false,
763+
"huge_pages": "None"
764+
}},
765+
"metrics": null,
766+
"mmds-config": {{
767+
"version": "V2",
768+
"network_interfaces": [
769+
"netif"
770+
],
771+
"ipv4_address": "169.254.169.254"
772+
}},
773+
"network-interfaces": [
774+
{{
775+
"iface_id": "netif",
776+
"host_dev_name": "hostname",
777+
"guest_mac": null,
778+
"rx_rate_limiter": null,
779+
"tx_rate_limiter": null
780+
}}
781+
],
782+
"vsock": {{
783+
"guest_cid": 3,
784+
"uds_path": "{}"
785+
}},
786+
"entropy": {{
787+
"rate_limiter": null
788+
}}
789+
}}"#,
790+
_block_files.last().unwrap().as_path().to_str().unwrap(),
791+
tmp_sock_file.as_path().to_str().unwrap()
792+
);
793+
794+
assert_eq!(
795+
vm_resources
796+
.mmds
797+
.as_ref()
798+
.unwrap()
799+
.lock()
800+
.unwrap()
801+
.version(),
802+
MmdsVersion::V2
803+
);
804+
assert_eq!(
805+
device_manager_state.pci_state.mmds_version.unwrap(),
806+
MmdsVersion::V2.into()
807+
);
808+
assert_eq!(
809+
expected_vm_resources,
810+
serde_json::to_string_pretty(&VmmConfig::from(&*vm_resources)).unwrap()
811+
);
812+
}
813+
}

0 commit comments

Comments
 (0)