@@ -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