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