xref: /cloud-hypervisor/vmm/src/vm_config.rs (revision 6f8bd27cf7629733582d930519e98d19e90afb16)
1 // Copyright © 2022 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0
4 //
5 use net_util::MacAddr;
6 use serde::{Deserialize, Serialize};
7 use std::{net::Ipv4Addr, path::PathBuf};
8 use virtio_devices::RateLimiterConfig;
9 
10 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
11 pub struct CpuAffinity {
12     pub vcpu: u8,
13     pub host_cpus: Vec<u8>,
14 }
15 
16 #[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
17 pub struct CpuFeatures {
18     #[cfg(target_arch = "x86_64")]
19     #[serde(default)]
20     pub amx: bool,
21 }
22 
23 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
24 pub struct CpuTopology {
25     pub threads_per_core: u8,
26     pub cores_per_die: u8,
27     pub dies_per_package: u8,
28     pub packages: u8,
29 }
30 
31 // When booting with PVH boot the maximum physical addressable size
32 // is a 46 bit address space even when the host supports with 5-level
33 // paging.
34 pub const DEFAULT_MAX_PHYS_BITS: u8 = 46;
35 
36 pub fn default_cpuconfig_max_phys_bits() -> u8 {
37     DEFAULT_MAX_PHYS_BITS
38 }
39 
40 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
41 pub struct CpusConfig {
42     pub boot_vcpus: u8,
43     pub max_vcpus: u8,
44     #[serde(default)]
45     pub topology: Option<CpuTopology>,
46     #[serde(default)]
47     pub kvm_hyperv: bool,
48     #[serde(default = "default_cpuconfig_max_phys_bits")]
49     pub max_phys_bits: u8,
50     #[serde(default)]
51     pub affinity: Option<Vec<CpuAffinity>>,
52     #[serde(default)]
53     pub features: CpuFeatures,
54 }
55 
56 pub const DEFAULT_VCPUS: u8 = 1;
57 
58 impl Default for CpusConfig {
59     fn default() -> Self {
60         CpusConfig {
61             boot_vcpus: DEFAULT_VCPUS,
62             max_vcpus: DEFAULT_VCPUS,
63             topology: None,
64             kvm_hyperv: false,
65             max_phys_bits: DEFAULT_MAX_PHYS_BITS,
66             affinity: None,
67             features: CpuFeatures::default(),
68         }
69     }
70 }
71 
72 pub const DEFAULT_NUM_PCI_SEGMENTS: u16 = 1;
73 pub fn default_platformconfig_num_pci_segments() -> u16 {
74     DEFAULT_NUM_PCI_SEGMENTS
75 }
76 
77 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
78 pub struct PlatformConfig {
79     #[serde(default = "default_platformconfig_num_pci_segments")]
80     pub num_pci_segments: u16,
81     #[serde(default)]
82     pub iommu_segments: Option<Vec<u16>>,
83     #[serde(default)]
84     pub serial_number: Option<String>,
85     #[serde(default)]
86     pub uuid: Option<String>,
87     #[serde(default)]
88     pub oem_strings: Option<Vec<String>>,
89     #[cfg(feature = "tdx")]
90     #[serde(default)]
91     pub tdx: bool,
92 }
93 
94 impl Default for PlatformConfig {
95     fn default() -> Self {
96         PlatformConfig {
97             num_pci_segments: DEFAULT_NUM_PCI_SEGMENTS,
98             iommu_segments: None,
99             serial_number: None,
100             uuid: None,
101             oem_strings: None,
102             #[cfg(feature = "tdx")]
103             tdx: false,
104         }
105     }
106 }
107 
108 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
109 pub struct MemoryZoneConfig {
110     pub id: String,
111     pub size: u64,
112     #[serde(default)]
113     pub file: Option<PathBuf>,
114     #[serde(default)]
115     pub shared: bool,
116     #[serde(default)]
117     pub hugepages: bool,
118     #[serde(default)]
119     pub hugepage_size: Option<u64>,
120     #[serde(default)]
121     pub host_numa_node: Option<u32>,
122     #[serde(default)]
123     pub hotplug_size: Option<u64>,
124     #[serde(default)]
125     pub hotplugged_size: Option<u64>,
126     #[serde(default)]
127     pub prefault: bool,
128 }
129 
130 #[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
131 pub enum HotplugMethod {
132     Acpi,
133     VirtioMem,
134 }
135 
136 impl Default for HotplugMethod {
137     fn default() -> Self {
138         HotplugMethod::Acpi
139     }
140 }
141 
142 fn default_memoryconfig_thp() -> bool {
143     true
144 }
145 
146 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
147 pub struct MemoryConfig {
148     pub size: u64,
149     #[serde(default)]
150     pub mergeable: bool,
151     #[serde(default)]
152     pub hotplug_method: HotplugMethod,
153     #[serde(default)]
154     pub hotplug_size: Option<u64>,
155     #[serde(default)]
156     pub hotplugged_size: Option<u64>,
157     #[serde(default)]
158     pub shared: bool,
159     #[serde(default)]
160     pub hugepages: bool,
161     #[serde(default)]
162     pub hugepage_size: Option<u64>,
163     #[serde(default)]
164     pub prefault: bool,
165     #[serde(default)]
166     pub zones: Option<Vec<MemoryZoneConfig>>,
167     #[serde(default = "default_memoryconfig_thp")]
168     pub thp: bool,
169 }
170 
171 pub const DEFAULT_MEMORY_MB: u64 = 512;
172 
173 impl Default for MemoryConfig {
174     fn default() -> Self {
175         MemoryConfig {
176             size: DEFAULT_MEMORY_MB << 20,
177             mergeable: false,
178             hotplug_method: HotplugMethod::Acpi,
179             hotplug_size: None,
180             hotplugged_size: None,
181             shared: false,
182             hugepages: false,
183             hugepage_size: None,
184             prefault: false,
185             zones: None,
186             thp: true,
187         }
188     }
189 }
190 
191 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
192 pub enum VhostMode {
193     Client,
194     Server,
195 }
196 
197 impl Default for VhostMode {
198     fn default() -> Self {
199         VhostMode::Client
200     }
201 }
202 
203 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
204 pub struct DiskConfig {
205     pub path: Option<PathBuf>,
206     #[serde(default)]
207     pub readonly: bool,
208     #[serde(default)]
209     pub direct: bool,
210     #[serde(default)]
211     pub iommu: bool,
212     #[serde(default = "default_diskconfig_num_queues")]
213     pub num_queues: usize,
214     #[serde(default = "default_diskconfig_queue_size")]
215     pub queue_size: u16,
216     #[serde(default)]
217     pub vhost_user: bool,
218     pub vhost_socket: Option<String>,
219     #[serde(default)]
220     pub rate_limiter_config: Option<RateLimiterConfig>,
221     #[serde(default)]
222     pub id: Option<String>,
223     // For testing use only. Not exposed in API.
224     #[serde(default)]
225     pub disable_io_uring: bool,
226     #[serde(default)]
227     pub pci_segment: u16,
228 }
229 
230 pub const DEFAULT_DISK_NUM_QUEUES: usize = 1;
231 
232 pub fn default_diskconfig_num_queues() -> usize {
233     DEFAULT_DISK_NUM_QUEUES
234 }
235 
236 pub const DEFAULT_DISK_QUEUE_SIZE: u16 = 128;
237 
238 pub fn default_diskconfig_queue_size() -> u16 {
239     DEFAULT_DISK_QUEUE_SIZE
240 }
241 
242 impl Default for DiskConfig {
243     fn default() -> Self {
244         Self {
245             path: None,
246             readonly: false,
247             direct: false,
248             iommu: false,
249             num_queues: default_diskconfig_num_queues(),
250             queue_size: default_diskconfig_queue_size(),
251             vhost_user: false,
252             vhost_socket: None,
253             id: None,
254             disable_io_uring: false,
255             rate_limiter_config: None,
256             pci_segment: 0,
257         }
258     }
259 }
260 
261 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
262 pub struct NetConfig {
263     #[serde(default = "default_netconfig_tap")]
264     pub tap: Option<String>,
265     #[serde(default = "default_netconfig_ip")]
266     pub ip: Ipv4Addr,
267     #[serde(default = "default_netconfig_mask")]
268     pub mask: Ipv4Addr,
269     #[serde(default = "default_netconfig_mac")]
270     pub mac: MacAddr,
271     #[serde(default)]
272     pub host_mac: Option<MacAddr>,
273     #[serde(default)]
274     pub mtu: Option<u16>,
275     #[serde(default)]
276     pub iommu: bool,
277     #[serde(default = "default_netconfig_num_queues")]
278     pub num_queues: usize,
279     #[serde(default = "default_netconfig_queue_size")]
280     pub queue_size: u16,
281     #[serde(default)]
282     pub vhost_user: bool,
283     pub vhost_socket: Option<String>,
284     #[serde(default)]
285     pub vhost_mode: VhostMode,
286     #[serde(default)]
287     pub id: Option<String>,
288     #[serde(default)]
289     pub fds: Option<Vec<i32>>,
290     #[serde(default)]
291     pub rate_limiter_config: Option<RateLimiterConfig>,
292     #[serde(default)]
293     pub pci_segment: u16,
294 }
295 
296 pub fn default_netconfig_tap() -> Option<String> {
297     None
298 }
299 
300 pub fn default_netconfig_ip() -> Ipv4Addr {
301     Ipv4Addr::new(192, 168, 249, 1)
302 }
303 
304 pub fn default_netconfig_mask() -> Ipv4Addr {
305     Ipv4Addr::new(255, 255, 255, 0)
306 }
307 
308 pub fn default_netconfig_mac() -> MacAddr {
309     MacAddr::local_random()
310 }
311 
312 pub const DEFAULT_NET_NUM_QUEUES: usize = 2;
313 
314 pub fn default_netconfig_num_queues() -> usize {
315     DEFAULT_NET_NUM_QUEUES
316 }
317 
318 pub const DEFAULT_NET_QUEUE_SIZE: u16 = 256;
319 
320 pub fn default_netconfig_queue_size() -> u16 {
321     DEFAULT_NET_QUEUE_SIZE
322 }
323 
324 impl Default for NetConfig {
325     fn default() -> Self {
326         Self {
327             tap: default_netconfig_tap(),
328             ip: default_netconfig_ip(),
329             mask: default_netconfig_mask(),
330             mac: default_netconfig_mac(),
331             host_mac: None,
332             mtu: None,
333             iommu: false,
334             num_queues: default_netconfig_num_queues(),
335             queue_size: default_netconfig_queue_size(),
336             vhost_user: false,
337             vhost_socket: None,
338             vhost_mode: VhostMode::Client,
339             id: None,
340             fds: None,
341             rate_limiter_config: None,
342             pci_segment: 0,
343         }
344     }
345 }
346 
347 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
348 pub struct RngConfig {
349     pub src: PathBuf,
350     #[serde(default)]
351     pub iommu: bool,
352 }
353 
354 pub const DEFAULT_RNG_SOURCE: &str = "/dev/urandom";
355 
356 impl Default for RngConfig {
357     fn default() -> Self {
358         RngConfig {
359             src: PathBuf::from(DEFAULT_RNG_SOURCE),
360             iommu: false,
361         }
362     }
363 }
364 
365 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
366 pub struct BalloonConfig {
367     pub size: u64,
368     /// Option to deflate the balloon in case the guest is out of memory.
369     #[serde(default)]
370     pub deflate_on_oom: bool,
371     /// Option to enable free page reporting from the guest.
372     #[serde(default)]
373     pub free_page_reporting: bool,
374 }
375 
376 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
377 pub struct FsConfig {
378     pub tag: String,
379     pub socket: PathBuf,
380     #[serde(default = "default_fsconfig_num_queues")]
381     pub num_queues: usize,
382     #[serde(default = "default_fsconfig_queue_size")]
383     pub queue_size: u16,
384     #[serde(default)]
385     pub id: Option<String>,
386     #[serde(default)]
387     pub pci_segment: u16,
388 }
389 
390 pub fn default_fsconfig_num_queues() -> usize {
391     1
392 }
393 
394 pub fn default_fsconfig_queue_size() -> u16 {
395     1024
396 }
397 
398 impl Default for FsConfig {
399     fn default() -> Self {
400         Self {
401             tag: "".to_owned(),
402             socket: PathBuf::new(),
403             num_queues: default_fsconfig_num_queues(),
404             queue_size: default_fsconfig_queue_size(),
405             id: None,
406             pci_segment: 0,
407         }
408     }
409 }
410 
411 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
412 pub struct PmemConfig {
413     pub file: PathBuf,
414     #[serde(default)]
415     pub size: Option<u64>,
416     #[serde(default)]
417     pub iommu: bool,
418     #[serde(default)]
419     pub discard_writes: bool,
420     #[serde(default)]
421     pub id: Option<String>,
422     #[serde(default)]
423     pub pci_segment: u16,
424 }
425 
426 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
427 pub enum ConsoleOutputMode {
428     Off,
429     Pty,
430     Tty,
431     File,
432     Null,
433 }
434 
435 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
436 pub struct ConsoleConfig {
437     #[serde(default = "default_consoleconfig_file")]
438     pub file: Option<PathBuf>,
439     pub mode: ConsoleOutputMode,
440     #[serde(default)]
441     pub iommu: bool,
442 }
443 
444 pub fn default_consoleconfig_file() -> Option<PathBuf> {
445     None
446 }
447 
448 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
449 pub struct DeviceConfig {
450     pub path: PathBuf,
451     #[serde(default)]
452     pub iommu: bool,
453     #[serde(default)]
454     pub id: Option<String>,
455     #[serde(default)]
456     pub pci_segment: u16,
457 }
458 
459 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
460 pub struct UserDeviceConfig {
461     pub socket: PathBuf,
462     #[serde(default)]
463     pub id: Option<String>,
464     #[serde(default)]
465     pub pci_segment: u16,
466 }
467 
468 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
469 pub struct VdpaConfig {
470     pub path: PathBuf,
471     #[serde(default = "default_vdpaconfig_num_queues")]
472     pub num_queues: usize,
473     #[serde(default)]
474     pub iommu: bool,
475     #[serde(default)]
476     pub id: Option<String>,
477     #[serde(default)]
478     pub pci_segment: u16,
479 }
480 
481 pub fn default_vdpaconfig_num_queues() -> usize {
482     1
483 }
484 
485 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
486 pub struct VsockConfig {
487     pub cid: u64,
488     pub socket: PathBuf,
489     #[serde(default)]
490     pub iommu: bool,
491     #[serde(default)]
492     pub id: Option<String>,
493     #[serde(default)]
494     pub pci_segment: u16,
495 }
496 
497 #[cfg(target_arch = "x86_64")]
498 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
499 pub struct SgxEpcConfig {
500     pub id: String,
501     #[serde(default)]
502     pub size: u64,
503     #[serde(default)]
504     pub prefault: bool,
505 }
506 
507 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
508 pub struct NumaDistance {
509     #[serde(default)]
510     pub destination: u32,
511     #[serde(default)]
512     pub distance: u8,
513 }
514 
515 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
516 pub struct NumaConfig {
517     #[serde(default)]
518     pub guest_numa_id: u32,
519     #[serde(default)]
520     pub cpus: Option<Vec<u8>>,
521     #[serde(default)]
522     pub distances: Option<Vec<NumaDistance>>,
523     #[serde(default)]
524     pub memory_zones: Option<Vec<String>>,
525     #[cfg(target_arch = "x86_64")]
526     #[serde(default)]
527     pub sgx_epc_sections: Option<Vec<String>>,
528 }
529 
530 #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
531 pub struct PayloadConfig {
532     #[serde(default)]
533     pub firmware: Option<PathBuf>,
534     #[serde(default)]
535     pub kernel: Option<PathBuf>,
536     #[serde(default)]
537     pub cmdline: Option<String>,
538     #[serde(default)]
539     pub initramfs: Option<PathBuf>,
540 }
541 
542 pub fn default_serial() -> ConsoleConfig {
543     ConsoleConfig {
544         file: None,
545         mode: ConsoleOutputMode::Null,
546         iommu: false,
547     }
548 }
549 
550 pub fn default_console() -> ConsoleConfig {
551     ConsoleConfig {
552         file: None,
553         mode: ConsoleOutputMode::Tty,
554         iommu: false,
555     }
556 }
557 
558 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
559 pub struct TpmConfig {
560     pub socket: PathBuf,
561 }
562 
563 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
564 pub struct VmConfig {
565     #[serde(default)]
566     pub cpus: CpusConfig,
567     #[serde(default)]
568     pub memory: MemoryConfig,
569     pub payload: Option<PayloadConfig>,
570     pub disks: Option<Vec<DiskConfig>>,
571     pub net: Option<Vec<NetConfig>>,
572     #[serde(default)]
573     pub rng: RngConfig,
574     pub balloon: Option<BalloonConfig>,
575     pub fs: Option<Vec<FsConfig>>,
576     pub pmem: Option<Vec<PmemConfig>>,
577     #[serde(default = "default_serial")]
578     pub serial: ConsoleConfig,
579     #[serde(default = "default_console")]
580     pub console: ConsoleConfig,
581     pub devices: Option<Vec<DeviceConfig>>,
582     pub user_devices: Option<Vec<UserDeviceConfig>>,
583     pub vdpa: Option<Vec<VdpaConfig>>,
584     pub vsock: Option<VsockConfig>,
585     #[serde(default)]
586     pub iommu: bool,
587     #[cfg(target_arch = "x86_64")]
588     pub sgx_epc: Option<Vec<SgxEpcConfig>>,
589     pub numa: Option<Vec<NumaConfig>>,
590     #[serde(default)]
591     pub watchdog: bool,
592     #[cfg(feature = "guest_debug")]
593     pub gdb: bool,
594     pub platform: Option<PlatformConfig>,
595     pub tpm: Option<TpmConfig>,
596 }
597