vmm/test_utils/
mod.rs

1// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4#![allow(missing_docs)]
5
6use std::sync::{Arc, Mutex};
7
8use vm_memory::{GuestAddress, GuestRegionCollection};
9use vmm_sys_util::tempdir::TempDir;
10
11use crate::builder::build_microvm_for_boot;
12use crate::resources::VmResources;
13use crate::seccomp::get_empty_filters;
14use crate::test_utils::mock_resources::{MockBootSourceConfig, MockVmConfig, MockVmResources};
15use crate::vmm_config::boot_source::BootSourceConfig;
16use crate::vmm_config::instance_info::InstanceInfo;
17use crate::vmm_config::machine_config::HugePageConfig;
18use crate::vmm_config::memory_hotplug::MemoryHotplugConfig;
19use crate::vstate::memory::{self, GuestMemoryMmap, GuestRegionMmap, GuestRegionMmapExt};
20use crate::{EventManager, Vmm};
21
22pub mod mock_resources;
23
24/// Creates a [`GuestMemoryMmap`] with a single region of the given size starting at guest
25/// physical address 0 and without dirty tracking.
26pub fn single_region_mem(region_size: usize) -> GuestMemoryMmap {
27    single_region_mem_at(0, region_size)
28}
29
30pub fn single_region_mem_raw(region_size: usize) -> Vec<GuestRegionMmap> {
31    single_region_mem_at_raw(0, region_size)
32}
33
34/// Creates a [`GuestMemoryMmap`] with a single region of the given size starting at the given
35/// guest physical address `at` and without dirty tracking.
36pub fn single_region_mem_at(at: u64, size: usize) -> GuestMemoryMmap {
37    multi_region_mem(&[(GuestAddress(at), size)])
38}
39
40pub fn single_region_mem_at_raw(at: u64, size: usize) -> Vec<GuestRegionMmap> {
41    multi_region_mem_raw(&[(GuestAddress(at), size)])
42}
43
44/// Creates a [`GuestMemoryMmap`] with multiple regions and without dirty page tracking.
45pub fn multi_region_mem(regions: &[(GuestAddress, usize)]) -> GuestMemoryMmap {
46    GuestRegionCollection::from_regions(
47        memory::anonymous(regions.iter().copied(), false, HugePageConfig::None)
48            .expect("Cannot initialize memory")
49            .into_iter()
50            .map(|region| GuestRegionMmapExt::dram_from_mmap_region(region, 0))
51            .collect(),
52    )
53    .unwrap()
54}
55
56pub fn multi_region_mem_raw(regions: &[(GuestAddress, usize)]) -> Vec<GuestRegionMmap> {
57    memory::anonymous(regions.iter().copied(), false, HugePageConfig::None)
58        .expect("Cannot initialize memory")
59}
60
61/// Creates a [`GuestMemoryMmap`] of the given size with the contained regions laid out in
62/// accordance with the requirements of the architecture on which the tests are being run.
63pub fn arch_mem(mem_size_bytes: usize) -> GuestMemoryMmap {
64    multi_region_mem(&crate::arch::arch_memory_regions(mem_size_bytes))
65}
66
67pub fn arch_mem_raw(mem_size_bytes: usize) -> Vec<GuestRegionMmap> {
68    multi_region_mem_raw(&crate::arch::arch_memory_regions(mem_size_bytes))
69}
70
71pub fn create_vmm(
72    _kernel_image: Option<&str>,
73    is_diff: bool,
74    boot_microvm: bool,
75    pci_enabled: bool,
76    memory_hotplug_enabled: bool,
77) -> (Arc<Mutex<Vmm>>, EventManager) {
78    let mut event_manager = EventManager::new().unwrap();
79    let empty_seccomp_filters = get_empty_filters();
80
81    let boot_source_cfg = MockBootSourceConfig::new().with_default_boot_args();
82    #[cfg(target_arch = "aarch64")]
83    let boot_source_cfg: BootSourceConfig = boot_source_cfg.into();
84    #[cfg(target_arch = "x86_64")]
85    let boot_source_cfg: BootSourceConfig = match _kernel_image {
86        Some(kernel) => boot_source_cfg.with_kernel(kernel).into(),
87        None => boot_source_cfg.into(),
88    };
89    let mock_vm_res = MockVmResources::new().with_boot_source(boot_source_cfg);
90    let mut resources: VmResources = if is_diff {
91        mock_vm_res
92            .with_vm_config(MockVmConfig::new().with_dirty_page_tracking().into())
93            .into()
94    } else {
95        mock_vm_res.into()
96    };
97
98    resources.pci_enabled = pci_enabled;
99
100    if memory_hotplug_enabled {
101        resources.memory_hotplug = Some(MemoryHotplugConfig {
102            total_size_mib: 1024,
103            block_size_mib: 2,
104            slot_size_mib: 128,
105        });
106    }
107
108    let vmm = build_microvm_for_boot(
109        &InstanceInfo::default(),
110        &resources,
111        &mut event_manager,
112        &empty_seccomp_filters,
113    )
114    .unwrap();
115
116    if boot_microvm {
117        vmm.lock().unwrap().resume_vm().unwrap();
118    }
119
120    (vmm, event_manager)
121}
122
123pub fn default_vmm(kernel_image: Option<&str>) -> (Arc<Mutex<Vmm>>, EventManager) {
124    create_vmm(kernel_image, false, true, false, false)
125}
126
127pub fn default_vmm_no_boot(kernel_image: Option<&str>) -> (Arc<Mutex<Vmm>>, EventManager) {
128    create_vmm(kernel_image, false, false, false, false)
129}
130
131pub fn dirty_tracking_vmm(kernel_image: Option<&str>) -> (Arc<Mutex<Vmm>>, EventManager) {
132    create_vmm(kernel_image, true, true, false, false)
133}
134
135#[allow(clippy::undocumented_unsafe_blocks)]
136#[allow(clippy::cast_possible_truncation)]
137pub fn create_tmp_socket() -> (TempDir, String) {
138    let tmp_dir = TempDir::new().unwrap();
139    let tmp_dir_path_str = tmp_dir.as_path().to_str().unwrap();
140    let tmp_socket_path = format!("{tmp_dir_path_str}/tmp_socket");
141
142    unsafe {
143        let socketfd = libc::socket(libc::AF_UNIX, libc::SOCK_STREAM, 0);
144        if socketfd < 0 {
145            panic!("Cannot create socket");
146        }
147        let mut socket_addr = libc::sockaddr_un {
148            sun_family: libc::AF_UNIX as u16,
149            sun_path: [0; 108],
150        };
151
152        std::ptr::copy(
153            tmp_socket_path.as_ptr().cast(),
154            socket_addr.sun_path.as_mut_ptr(),
155            tmp_socket_path.len(),
156        );
157
158        let bind = libc::bind(
159            socketfd,
160            (&socket_addr as *const libc::sockaddr_un).cast(),
161            std::mem::size_of::<libc::sockaddr_un>() as u32,
162        );
163        if bind < 0 {
164            panic!("Cannot bind socket");
165        }
166
167        let listen = libc::listen(socketfd, 1);
168        if listen < 0 {
169            panic!("Cannot listen on socket");
170        }
171    }
172
173    (tmp_dir, tmp_socket_path)
174}