xref: /cloud-hypervisor/vmm/src/vm_config.rs (revision 07d1208dd53a207a65b649b8952780dfd0ca59d9)
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     #[serde(default)]
222     pub pci_segment: u16,
223 }
224 
225 pub const DEFAULT_DISK_NUM_QUEUES: usize = 1;
226 
227 pub fn default_diskconfig_num_queues() -> usize {
228     DEFAULT_DISK_NUM_QUEUES
229 }
230 
231 pub const DEFAULT_DISK_QUEUE_SIZE: u16 = 128;
232 
233 pub fn default_diskconfig_queue_size() -> u16 {
234     DEFAULT_DISK_QUEUE_SIZE
235 }
236 
237 impl Default for DiskConfig {
238     fn default() -> Self {
239         Self {
240             path: None,
241             readonly: false,
242             direct: false,
243             iommu: false,
244             num_queues: default_diskconfig_num_queues(),
245             queue_size: default_diskconfig_queue_size(),
246             vhost_user: false,
247             vhost_socket: None,
248             id: None,
249             disable_io_uring: false,
250             rate_limiter_config: None,
251             pci_segment: 0,
252         }
253     }
254 }
255 
256 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
257 pub struct NetConfig {
258     #[serde(default = "default_netconfig_tap")]
259     pub tap: Option<String>,
260     #[serde(default = "default_netconfig_ip")]
261     pub ip: Ipv4Addr,
262     #[serde(default = "default_netconfig_mask")]
263     pub mask: Ipv4Addr,
264     #[serde(default = "default_netconfig_mac")]
265     pub mac: MacAddr,
266     #[serde(default)]
267     pub host_mac: Option<MacAddr>,
268     #[serde(default)]
269     pub mtu: Option<u16>,
270     #[serde(default)]
271     pub iommu: bool,
272     #[serde(default = "default_netconfig_num_queues")]
273     pub num_queues: usize,
274     #[serde(default = "default_netconfig_queue_size")]
275     pub queue_size: u16,
276     #[serde(default)]
277     pub vhost_user: bool,
278     pub vhost_socket: Option<String>,
279     #[serde(default)]
280     pub vhost_mode: VhostMode,
281     #[serde(default)]
282     pub id: Option<String>,
283     #[serde(default)]
284     pub fds: Option<Vec<i32>>,
285     #[serde(default)]
286     pub rate_limiter_config: Option<RateLimiterConfig>,
287     #[serde(default)]
288     pub pci_segment: u16,
289     #[serde(default = "default_netconfig_true")]
290     pub offload_tso: bool,
291     #[serde(default = "default_netconfig_true")]
292     pub offload_ufo: bool,
293     #[serde(default = "default_netconfig_true")]
294     pub offload_csum: bool,
295 }
296 
297 pub fn default_netconfig_true() -> bool {
298     true
299 }
300 
301 pub fn default_netconfig_tap() -> Option<String> {
302     None
303 }
304 
305 pub fn default_netconfig_ip() -> Ipv4Addr {
306     Ipv4Addr::new(192, 168, 249, 1)
307 }
308 
309 pub fn default_netconfig_mask() -> Ipv4Addr {
310     Ipv4Addr::new(255, 255, 255, 0)
311 }
312 
313 pub fn default_netconfig_mac() -> MacAddr {
314     MacAddr::local_random()
315 }
316 
317 pub const DEFAULT_NET_NUM_QUEUES: usize = 2;
318 
319 pub fn default_netconfig_num_queues() -> usize {
320     DEFAULT_NET_NUM_QUEUES
321 }
322 
323 pub const DEFAULT_NET_QUEUE_SIZE: u16 = 256;
324 
325 pub fn default_netconfig_queue_size() -> u16 {
326     DEFAULT_NET_QUEUE_SIZE
327 }
328 
329 impl Default for NetConfig {
330     fn default() -> Self {
331         Self {
332             tap: default_netconfig_tap(),
333             ip: default_netconfig_ip(),
334             mask: default_netconfig_mask(),
335             mac: default_netconfig_mac(),
336             host_mac: None,
337             mtu: None,
338             iommu: false,
339             num_queues: default_netconfig_num_queues(),
340             queue_size: default_netconfig_queue_size(),
341             vhost_user: false,
342             vhost_socket: None,
343             vhost_mode: VhostMode::Client,
344             id: None,
345             fds: None,
346             rate_limiter_config: None,
347             pci_segment: 0,
348             offload_tso: true,
349             offload_ufo: true,
350             offload_csum: true,
351         }
352     }
353 }
354 
355 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
356 pub struct RngConfig {
357     pub src: PathBuf,
358     #[serde(default)]
359     pub iommu: bool,
360 }
361 
362 pub const DEFAULT_RNG_SOURCE: &str = "/dev/urandom";
363 
364 impl Default for RngConfig {
365     fn default() -> Self {
366         RngConfig {
367             src: PathBuf::from(DEFAULT_RNG_SOURCE),
368             iommu: false,
369         }
370     }
371 }
372 
373 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
374 pub struct BalloonConfig {
375     pub size: u64,
376     /// Option to deflate the balloon in case the guest is out of memory.
377     #[serde(default)]
378     pub deflate_on_oom: bool,
379     /// Option to enable free page reporting from the guest.
380     #[serde(default)]
381     pub free_page_reporting: bool,
382 }
383 
384 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
385 pub struct FsConfig {
386     pub tag: String,
387     pub socket: PathBuf,
388     #[serde(default = "default_fsconfig_num_queues")]
389     pub num_queues: usize,
390     #[serde(default = "default_fsconfig_queue_size")]
391     pub queue_size: u16,
392     #[serde(default)]
393     pub id: Option<String>,
394     #[serde(default)]
395     pub pci_segment: u16,
396 }
397 
398 pub fn default_fsconfig_num_queues() -> usize {
399     1
400 }
401 
402 pub fn default_fsconfig_queue_size() -> u16 {
403     1024
404 }
405 
406 impl Default for FsConfig {
407     fn default() -> Self {
408         Self {
409             tag: "".to_owned(),
410             socket: PathBuf::new(),
411             num_queues: default_fsconfig_num_queues(),
412             queue_size: default_fsconfig_queue_size(),
413             id: None,
414             pci_segment: 0,
415         }
416     }
417 }
418 
419 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
420 pub struct PmemConfig {
421     pub file: PathBuf,
422     #[serde(default)]
423     pub size: Option<u64>,
424     #[serde(default)]
425     pub iommu: bool,
426     #[serde(default)]
427     pub discard_writes: bool,
428     #[serde(default)]
429     pub id: Option<String>,
430     #[serde(default)]
431     pub pci_segment: u16,
432 }
433 
434 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
435 pub enum ConsoleOutputMode {
436     Off,
437     Pty,
438     Tty,
439     File,
440     Null,
441 }
442 
443 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
444 pub struct ConsoleConfig {
445     #[serde(default = "default_consoleconfig_file")]
446     pub file: Option<PathBuf>,
447     pub mode: ConsoleOutputMode,
448     #[serde(default)]
449     pub iommu: bool,
450 }
451 
452 pub fn default_consoleconfig_file() -> Option<PathBuf> {
453     None
454 }
455 
456 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
457 pub struct DeviceConfig {
458     pub path: PathBuf,
459     #[serde(default)]
460     pub iommu: bool,
461     #[serde(default)]
462     pub id: Option<String>,
463     #[serde(default)]
464     pub pci_segment: u16,
465 }
466 
467 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
468 pub struct UserDeviceConfig {
469     pub socket: PathBuf,
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 VdpaConfig {
478     pub path: PathBuf,
479     #[serde(default = "default_vdpaconfig_num_queues")]
480     pub num_queues: usize,
481     #[serde(default)]
482     pub iommu: bool,
483     #[serde(default)]
484     pub id: Option<String>,
485     #[serde(default)]
486     pub pci_segment: u16,
487 }
488 
489 pub fn default_vdpaconfig_num_queues() -> usize {
490     1
491 }
492 
493 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
494 pub struct VsockConfig {
495     pub cid: u64,
496     pub socket: PathBuf,
497     #[serde(default)]
498     pub iommu: bool,
499     #[serde(default)]
500     pub id: Option<String>,
501     #[serde(default)]
502     pub pci_segment: u16,
503 }
504 
505 #[cfg(target_arch = "x86_64")]
506 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
507 pub struct SgxEpcConfig {
508     pub id: String,
509     #[serde(default)]
510     pub size: u64,
511     #[serde(default)]
512     pub prefault: bool,
513 }
514 
515 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
516 pub struct NumaDistance {
517     #[serde(default)]
518     pub destination: u32,
519     #[serde(default)]
520     pub distance: u8,
521 }
522 
523 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
524 pub struct NumaConfig {
525     #[serde(default)]
526     pub guest_numa_id: u32,
527     #[serde(default)]
528     pub cpus: Option<Vec<u8>>,
529     #[serde(default)]
530     pub distances: Option<Vec<NumaDistance>>,
531     #[serde(default)]
532     pub memory_zones: Option<Vec<String>>,
533     #[cfg(target_arch = "x86_64")]
534     #[serde(default)]
535     pub sgx_epc_sections: Option<Vec<String>>,
536 }
537 
538 #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
539 pub struct PayloadConfig {
540     #[serde(default)]
541     pub firmware: Option<PathBuf>,
542     #[serde(default)]
543     pub kernel: Option<PathBuf>,
544     #[serde(default)]
545     pub cmdline: Option<String>,
546     #[serde(default)]
547     pub initramfs: Option<PathBuf>,
548 }
549 
550 pub fn default_serial() -> ConsoleConfig {
551     ConsoleConfig {
552         file: None,
553         mode: ConsoleOutputMode::Null,
554         iommu: false,
555     }
556 }
557 
558 pub fn default_console() -> ConsoleConfig {
559     ConsoleConfig {
560         file: None,
561         mode: ConsoleOutputMode::Tty,
562         iommu: false,
563     }
564 }
565 
566 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
567 pub struct TpmConfig {
568     pub socket: PathBuf,
569 }
570 
571 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
572 pub struct VmConfig {
573     #[serde(default)]
574     pub cpus: CpusConfig,
575     #[serde(default)]
576     pub memory: MemoryConfig,
577     pub payload: Option<PayloadConfig>,
578     pub disks: Option<Vec<DiskConfig>>,
579     pub net: Option<Vec<NetConfig>>,
580     #[serde(default)]
581     pub rng: RngConfig,
582     pub balloon: Option<BalloonConfig>,
583     pub fs: Option<Vec<FsConfig>>,
584     pub pmem: Option<Vec<PmemConfig>>,
585     #[serde(default = "default_serial")]
586     pub serial: ConsoleConfig,
587     #[serde(default = "default_console")]
588     pub console: ConsoleConfig,
589     pub devices: Option<Vec<DeviceConfig>>,
590     pub user_devices: Option<Vec<UserDeviceConfig>>,
591     pub vdpa: Option<Vec<VdpaConfig>>,
592     pub vsock: Option<VsockConfig>,
593     #[serde(default)]
594     pub pvpanic: bool,
595     #[serde(default)]
596     pub iommu: bool,
597     #[cfg(target_arch = "x86_64")]
598     pub sgx_epc: Option<Vec<SgxEpcConfig>>,
599     pub numa: Option<Vec<NumaConfig>>,
600     #[serde(default)]
601     pub watchdog: bool,
602     #[cfg(feature = "guest_debug")]
603     #[serde(default)]
604     pub gdb: bool,
605     pub platform: Option<PlatformConfig>,
606     pub tpm: Option<TpmConfig>,
607     // Preseved FDs are the ones that share the same life-time as its holding
608     // VmConfig instance, such as FDs for creating TAP devices.
609     // Perserved FDs will stay open as long as the holding VmConfig instance is
610     // valid, and will be closed when the holding VmConfig instance is destroyed.
611     #[serde(skip)]
612     pub preserved_fds: Option<Vec<i32>>,
613 }
614