xref: /cloud-hypervisor/vmm/src/vm_config.rs (revision 4d7a4c598ac247aaf770b00dfb057cdac891f67d)
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     #[cfg(feature = "sev_snp")]
93     #[serde(default)]
94     pub sev_snp: bool,
95 }
96 
97 impl Default for PlatformConfig {
98     fn default() -> Self {
99         PlatformConfig {
100             num_pci_segments: DEFAULT_NUM_PCI_SEGMENTS,
101             iommu_segments: None,
102             serial_number: None,
103             uuid: None,
104             oem_strings: None,
105             #[cfg(feature = "tdx")]
106             tdx: false,
107             #[cfg(feature = "sev_snp")]
108             sev_snp: false,
109         }
110     }
111 }
112 
113 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
114 pub struct MemoryZoneConfig {
115     pub id: String,
116     pub size: u64,
117     #[serde(default)]
118     pub file: Option<PathBuf>,
119     #[serde(default)]
120     pub shared: bool,
121     #[serde(default)]
122     pub hugepages: bool,
123     #[serde(default)]
124     pub hugepage_size: Option<u64>,
125     #[serde(default)]
126     pub host_numa_node: Option<u32>,
127     #[serde(default)]
128     pub hotplug_size: Option<u64>,
129     #[serde(default)]
130     pub hotplugged_size: Option<u64>,
131     #[serde(default)]
132     pub prefault: bool,
133 }
134 
135 #[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
136 pub enum HotplugMethod {
137     #[default]
138     Acpi,
139     VirtioMem,
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, Default)]
192 pub enum VhostMode {
193     #[default]
194     Client,
195     Server,
196 }
197 
198 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
199 pub struct DiskConfig {
200     pub path: Option<PathBuf>,
201     #[serde(default)]
202     pub readonly: bool,
203     #[serde(default)]
204     pub direct: bool,
205     #[serde(default)]
206     pub iommu: bool,
207     #[serde(default = "default_diskconfig_num_queues")]
208     pub num_queues: usize,
209     #[serde(default = "default_diskconfig_queue_size")]
210     pub queue_size: u16,
211     #[serde(default)]
212     pub vhost_user: bool,
213     pub vhost_socket: Option<String>,
214     #[serde(default)]
215     pub rate_limiter_config: Option<RateLimiterConfig>,
216     #[serde(default)]
217     pub id: Option<String>,
218     // For testing use only. Not exposed in API.
219     #[serde(default)]
220     pub disable_io_uring: bool,
221     // For testing use only. Not exposed in API.
222     #[serde(default)]
223     pub disable_aio: bool,
224     #[serde(default)]
225     pub pci_segment: u16,
226     #[serde(default)]
227     pub serial: Option<String>,
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             disable_aio: false,
256             rate_limiter_config: None,
257             pci_segment: 0,
258             serial: None,
259         }
260     }
261 }
262 
263 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
264 pub struct NetConfig {
265     #[serde(default = "default_netconfig_tap")]
266     pub tap: Option<String>,
267     #[serde(default = "default_netconfig_ip")]
268     pub ip: Ipv4Addr,
269     #[serde(default = "default_netconfig_mask")]
270     pub mask: Ipv4Addr,
271     #[serde(default = "default_netconfig_mac")]
272     pub mac: MacAddr,
273     #[serde(default)]
274     pub host_mac: Option<MacAddr>,
275     #[serde(default)]
276     pub mtu: Option<u16>,
277     #[serde(default)]
278     pub iommu: bool,
279     #[serde(default = "default_netconfig_num_queues")]
280     pub num_queues: usize,
281     #[serde(default = "default_netconfig_queue_size")]
282     pub queue_size: u16,
283     #[serde(default)]
284     pub vhost_user: bool,
285     pub vhost_socket: Option<String>,
286     #[serde(default)]
287     pub vhost_mode: VhostMode,
288     #[serde(default)]
289     pub id: Option<String>,
290     #[serde(default)]
291     pub fds: Option<Vec<i32>>,
292     #[serde(default)]
293     pub rate_limiter_config: Option<RateLimiterConfig>,
294     #[serde(default)]
295     pub pci_segment: u16,
296     #[serde(default = "default_netconfig_true")]
297     pub offload_tso: bool,
298     #[serde(default = "default_netconfig_true")]
299     pub offload_ufo: bool,
300     #[serde(default = "default_netconfig_true")]
301     pub offload_csum: bool,
302 }
303 
304 pub fn default_netconfig_true() -> bool {
305     true
306 }
307 
308 pub fn default_netconfig_tap() -> Option<String> {
309     None
310 }
311 
312 pub fn default_netconfig_ip() -> Ipv4Addr {
313     Ipv4Addr::new(192, 168, 249, 1)
314 }
315 
316 pub fn default_netconfig_mask() -> Ipv4Addr {
317     Ipv4Addr::new(255, 255, 255, 0)
318 }
319 
320 pub fn default_netconfig_mac() -> MacAddr {
321     MacAddr::local_random()
322 }
323 
324 pub const DEFAULT_NET_NUM_QUEUES: usize = 2;
325 
326 pub fn default_netconfig_num_queues() -> usize {
327     DEFAULT_NET_NUM_QUEUES
328 }
329 
330 pub const DEFAULT_NET_QUEUE_SIZE: u16 = 256;
331 
332 pub fn default_netconfig_queue_size() -> u16 {
333     DEFAULT_NET_QUEUE_SIZE
334 }
335 
336 impl Default for NetConfig {
337     fn default() -> Self {
338         Self {
339             tap: default_netconfig_tap(),
340             ip: default_netconfig_ip(),
341             mask: default_netconfig_mask(),
342             mac: default_netconfig_mac(),
343             host_mac: None,
344             mtu: None,
345             iommu: false,
346             num_queues: default_netconfig_num_queues(),
347             queue_size: default_netconfig_queue_size(),
348             vhost_user: false,
349             vhost_socket: None,
350             vhost_mode: VhostMode::Client,
351             id: None,
352             fds: None,
353             rate_limiter_config: None,
354             pci_segment: 0,
355             offload_tso: true,
356             offload_ufo: true,
357             offload_csum: true,
358         }
359     }
360 }
361 
362 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
363 pub struct RngConfig {
364     pub src: PathBuf,
365     #[serde(default)]
366     pub iommu: bool,
367 }
368 
369 pub const DEFAULT_RNG_SOURCE: &str = "/dev/urandom";
370 
371 impl Default for RngConfig {
372     fn default() -> Self {
373         RngConfig {
374             src: PathBuf::from(DEFAULT_RNG_SOURCE),
375             iommu: false,
376         }
377     }
378 }
379 
380 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
381 pub struct BalloonConfig {
382     pub size: u64,
383     /// Option to deflate the balloon in case the guest is out of memory.
384     #[serde(default)]
385     pub deflate_on_oom: bool,
386     /// Option to enable free page reporting from the guest.
387     #[serde(default)]
388     pub free_page_reporting: bool,
389 }
390 
391 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
392 pub struct FsConfig {
393     pub tag: String,
394     pub socket: PathBuf,
395     #[serde(default = "default_fsconfig_num_queues")]
396     pub num_queues: usize,
397     #[serde(default = "default_fsconfig_queue_size")]
398     pub queue_size: u16,
399     #[serde(default)]
400     pub id: Option<String>,
401     #[serde(default)]
402     pub pci_segment: u16,
403 }
404 
405 pub fn default_fsconfig_num_queues() -> usize {
406     1
407 }
408 
409 pub fn default_fsconfig_queue_size() -> u16 {
410     1024
411 }
412 
413 impl Default for FsConfig {
414     fn default() -> Self {
415         Self {
416             tag: "".to_owned(),
417             socket: PathBuf::new(),
418             num_queues: default_fsconfig_num_queues(),
419             queue_size: default_fsconfig_queue_size(),
420             id: None,
421             pci_segment: 0,
422         }
423     }
424 }
425 
426 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
427 pub struct PmemConfig {
428     pub file: PathBuf,
429     #[serde(default)]
430     pub size: Option<u64>,
431     #[serde(default)]
432     pub iommu: bool,
433     #[serde(default)]
434     pub discard_writes: bool,
435     #[serde(default)]
436     pub id: Option<String>,
437     #[serde(default)]
438     pub pci_segment: u16,
439 }
440 
441 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
442 pub enum ConsoleOutputMode {
443     Off,
444     Pty,
445     Tty,
446     File,
447     Socket,
448     Null,
449 }
450 
451 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
452 pub struct ConsoleConfig {
453     #[serde(default = "default_consoleconfig_file")]
454     pub file: Option<PathBuf>,
455     pub mode: ConsoleOutputMode,
456     #[serde(default)]
457     pub iommu: bool,
458     pub socket: Option<PathBuf>,
459 }
460 
461 pub fn default_consoleconfig_file() -> Option<PathBuf> {
462     None
463 }
464 
465 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
466 pub struct DeviceConfig {
467     pub path: PathBuf,
468     #[serde(default)]
469     pub iommu: bool,
470     #[serde(default)]
471     pub id: Option<String>,
472     #[serde(default)]
473     pub pci_segment: u16,
474 }
475 
476 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
477 pub struct UserDeviceConfig {
478     pub socket: PathBuf,
479     #[serde(default)]
480     pub id: Option<String>,
481     #[serde(default)]
482     pub pci_segment: u16,
483 }
484 
485 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
486 pub struct VdpaConfig {
487     pub path: PathBuf,
488     #[serde(default = "default_vdpaconfig_num_queues")]
489     pub num_queues: usize,
490     #[serde(default)]
491     pub iommu: bool,
492     #[serde(default)]
493     pub id: Option<String>,
494     #[serde(default)]
495     pub pci_segment: u16,
496 }
497 
498 pub fn default_vdpaconfig_num_queues() -> usize {
499     1
500 }
501 
502 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
503 pub struct VsockConfig {
504     pub cid: u64,
505     pub socket: PathBuf,
506     #[serde(default)]
507     pub iommu: bool,
508     #[serde(default)]
509     pub id: Option<String>,
510     #[serde(default)]
511     pub pci_segment: u16,
512 }
513 
514 #[cfg(target_arch = "x86_64")]
515 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
516 pub struct SgxEpcConfig {
517     pub id: String,
518     #[serde(default)]
519     pub size: u64,
520     #[serde(default)]
521     pub prefault: bool,
522 }
523 
524 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
525 pub struct NumaDistance {
526     #[serde(default)]
527     pub destination: u32,
528     #[serde(default)]
529     pub distance: u8,
530 }
531 
532 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
533 pub struct NumaConfig {
534     #[serde(default)]
535     pub guest_numa_id: u32,
536     #[serde(default)]
537     pub cpus: Option<Vec<u8>>,
538     #[serde(default)]
539     pub distances: Option<Vec<NumaDistance>>,
540     #[serde(default)]
541     pub memory_zones: Option<Vec<String>>,
542     #[cfg(target_arch = "x86_64")]
543     #[serde(default)]
544     pub sgx_epc_sections: Option<Vec<String>>,
545     #[serde(default)]
546     pub pci_segments: Option<Vec<u16>>,
547 }
548 
549 #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
550 pub struct PayloadConfig {
551     #[serde(default)]
552     pub firmware: Option<PathBuf>,
553     #[serde(default)]
554     pub kernel: Option<PathBuf>,
555     #[serde(default)]
556     pub cmdline: Option<String>,
557     #[serde(default)]
558     pub initramfs: Option<PathBuf>,
559 }
560 
561 pub fn default_serial() -> ConsoleConfig {
562     ConsoleConfig {
563         file: None,
564         mode: ConsoleOutputMode::Null,
565         iommu: false,
566         socket: None,
567     }
568 }
569 
570 pub fn default_console() -> ConsoleConfig {
571     ConsoleConfig {
572         file: None,
573         mode: ConsoleOutputMode::Tty,
574         iommu: false,
575         socket: None,
576     }
577 }
578 
579 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
580 pub struct TpmConfig {
581     pub socket: PathBuf,
582 }
583 
584 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
585 pub struct VmConfig {
586     #[serde(default)]
587     pub cpus: CpusConfig,
588     #[serde(default)]
589     pub memory: MemoryConfig,
590     pub payload: Option<PayloadConfig>,
591     pub disks: Option<Vec<DiskConfig>>,
592     pub net: Option<Vec<NetConfig>>,
593     #[serde(default)]
594     pub rng: RngConfig,
595     pub balloon: Option<BalloonConfig>,
596     pub fs: Option<Vec<FsConfig>>,
597     pub pmem: Option<Vec<PmemConfig>>,
598     #[serde(default = "default_serial")]
599     pub serial: ConsoleConfig,
600     #[serde(default = "default_console")]
601     pub console: ConsoleConfig,
602     pub devices: Option<Vec<DeviceConfig>>,
603     pub user_devices: Option<Vec<UserDeviceConfig>>,
604     pub vdpa: Option<Vec<VdpaConfig>>,
605     pub vsock: Option<VsockConfig>,
606     #[serde(default)]
607     pub pvpanic: bool,
608     #[serde(default)]
609     pub iommu: bool,
610     #[cfg(target_arch = "x86_64")]
611     pub sgx_epc: Option<Vec<SgxEpcConfig>>,
612     pub numa: Option<Vec<NumaConfig>>,
613     #[serde(default)]
614     pub watchdog: bool,
615     #[cfg(feature = "guest_debug")]
616     #[serde(default)]
617     pub gdb: bool,
618     pub platform: Option<PlatformConfig>,
619     pub tpm: Option<TpmConfig>,
620     // Preserved FDs are the ones that share the same life-time as its holding
621     // VmConfig instance, such as FDs for creating TAP devices.
622     // Preserved FDs will stay open as long as the holding VmConfig instance is
623     // valid, and will be closed when the holding VmConfig instance is destroyed.
624     #[serde(skip)]
625     pub preserved_fds: Option<Vec<i32>>,
626 }
627