@@ -259,6 +259,16 @@ impl PciDevices {
259
259
event_manager. add_subscriber ( device) ;
260
260
Ok ( ( ) )
261
261
}
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
+ }
262
272
}
263
273
264
274
#[ derive( Debug , Clone , Serialize , Deserialize ) ]
@@ -617,3 +627,187 @@ impl<'a> Persist<'a> for PciDevices {
617
627
Ok ( pci_devices)
618
628
}
619
629
}
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