xref: /cloud-hypervisor/vmm/src/vm_config.rs (revision 2571e59438597f53aa4993cd70d6462fe1364ba7)
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, Default)]
131 pub enum HotplugMethod {
132     #[default]
133     Acpi,
134     VirtioMem,
135 }
136 
137 fn default_memoryconfig_thp() -> bool {
138     true
139 }
140 
141 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
142 pub struct MemoryConfig {
143     pub size: u64,
144     #[serde(default)]
145     pub mergeable: bool,
146     #[serde(default)]
147     pub hotplug_method: HotplugMethod,
148     #[serde(default)]
149     pub hotplug_size: Option<u64>,
150     #[serde(default)]
151     pub hotplugged_size: Option<u64>,
152     #[serde(default)]
153     pub shared: bool,
154     #[serde(default)]
155     pub hugepages: bool,
156     #[serde(default)]
157     pub hugepage_size: Option<u64>,
158     #[serde(default)]
159     pub prefault: bool,
160     #[serde(default)]
161     pub zones: Option<Vec<MemoryZoneConfig>>,
162     #[serde(default = "default_memoryconfig_thp")]
163     pub thp: bool,
164 }
165 
166 pub const DEFAULT_MEMORY_MB: u64 = 512;
167 
168 impl Default for MemoryConfig {
169     fn default() -> Self {
170         MemoryConfig {
171             size: DEFAULT_MEMORY_MB << 20,
172             mergeable: false,
173             hotplug_method: HotplugMethod::Acpi,
174             hotplug_size: None,
175             hotplugged_size: None,
176             shared: false,
177             hugepages: false,
178             hugepage_size: None,
179             prefault: false,
180             zones: None,
181             thp: true,
182         }
183     }
184 }
185 
186 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
187 pub enum VhostMode {
188     #[default]
189     Client,
190     Server,
191 }
192 
193 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
194 pub struct DiskConfig {
195     pub path: Option<PathBuf>,
196     #[serde(default)]
197     pub readonly: bool,
198     #[serde(default)]
199     pub direct: bool,
200     #[serde(default)]
201     pub iommu: bool,
202     #[serde(default = "default_diskconfig_num_queues")]
203     pub num_queues: usize,
204     #[serde(default = "default_diskconfig_queue_size")]
205     pub queue_size: u16,
206     #[serde(default)]
207     pub vhost_user: bool,
208     pub vhost_socket: Option<String>,
209     #[serde(default)]
210     pub rate_limiter_config: Option<RateLimiterConfig>,
211     #[serde(default)]
212     pub id: Option<String>,
213     // For testing use only. Not exposed in API.
214     #[serde(default)]
215     pub disable_io_uring: bool,
216     #[serde(default)]
217     pub pci_segment: u16,
218 }
219 
220 pub const DEFAULT_DISK_NUM_QUEUES: usize = 1;
221 
222 pub fn default_diskconfig_num_queues() -> usize {
223     DEFAULT_DISK_NUM_QUEUES
224 }
225 
226 pub const DEFAULT_DISK_QUEUE_SIZE: u16 = 128;
227 
228 pub fn default_diskconfig_queue_size() -> u16 {
229     DEFAULT_DISK_QUEUE_SIZE
230 }
231 
232 impl Default for DiskConfig {
233     fn default() -> Self {
234         Self {
235             path: None,
236             readonly: false,
237             direct: false,
238             iommu: false,
239             num_queues: default_diskconfig_num_queues(),
240             queue_size: default_diskconfig_queue_size(),
241             vhost_user: false,
242             vhost_socket: None,
243             id: None,
244             disable_io_uring: false,
245             rate_limiter_config: None,
246             pci_segment: 0,
247         }
248     }
249 }
250 
251 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
252 pub struct NetConfig {
253     #[serde(default = "default_netconfig_tap")]
254     pub tap: Option<String>,
255     #[serde(default = "default_netconfig_ip")]
256     pub ip: Ipv4Addr,
257     #[serde(default = "default_netconfig_mask")]
258     pub mask: Ipv4Addr,
259     #[serde(default = "default_netconfig_mac")]
260     pub mac: MacAddr,
261     #[serde(default)]
262     pub host_mac: Option<MacAddr>,
263     #[serde(default)]
264     pub mtu: Option<u16>,
265     #[serde(default)]
266     pub iommu: bool,
267     #[serde(default = "default_netconfig_num_queues")]
268     pub num_queues: usize,
269     #[serde(default = "default_netconfig_queue_size")]
270     pub queue_size: u16,
271     #[serde(default)]
272     pub vhost_user: bool,
273     pub vhost_socket: Option<String>,
274     #[serde(default)]
275     pub vhost_mode: VhostMode,
276     #[serde(default)]
277     pub id: Option<String>,
278     #[serde(default)]
279     pub fds: Option<Vec<i32>>,
280     #[serde(default)]
281     pub rate_limiter_config: Option<RateLimiterConfig>,
282     #[serde(default)]
283     pub pci_segment: u16,
284     #[serde(default = "default_netconfig_true")]
285     pub offload_tso: bool,
286     #[serde(default = "default_netconfig_true")]
287     pub offload_ufo: bool,
288     #[serde(default = "default_netconfig_true")]
289     pub offload_csum: bool,
290 }
291 
292 pub fn default_netconfig_true() -> bool {
293     true
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             offload_tso: true,
344             offload_ufo: true,
345             offload_csum: true,
346         }
347     }
348 }
349 
350 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
351 pub struct RngConfig {
352     pub src: PathBuf,
353     #[serde(default)]
354     pub iommu: bool,
355 }
356 
357 pub const DEFAULT_RNG_SOURCE: &str = "/dev/urandom";
358 
359 impl Default for RngConfig {
360     fn default() -> Self {
361         RngConfig {
362             src: PathBuf::from(DEFAULT_RNG_SOURCE),
363             iommu: false,
364         }
365     }
366 }
367 
368 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
369 pub struct BalloonConfig {
370     pub size: u64,
371     /// Option to deflate the balloon in case the guest is out of memory.
372     #[serde(default)]
373     pub deflate_on_oom: bool,
374     /// Option to enable free page reporting from the guest.
375     #[serde(default)]
376     pub free_page_reporting: bool,
377 }
378 
379 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
380 pub struct FsConfig {
381     pub tag: String,
382     pub socket: PathBuf,
383     #[serde(default = "default_fsconfig_num_queues")]
384     pub num_queues: usize,
385     #[serde(default = "default_fsconfig_queue_size")]
386     pub queue_size: u16,
387     #[serde(default)]
388     pub id: Option<String>,
389     #[serde(default)]
390     pub pci_segment: u16,
391 }
392 
393 pub fn default_fsconfig_num_queues() -> usize {
394     1
395 }
396 
397 pub fn default_fsconfig_queue_size() -> u16 {
398     1024
399 }
400 
401 impl Default for FsConfig {
402     fn default() -> Self {
403         Self {
404             tag: "".to_owned(),
405             socket: PathBuf::new(),
406             num_queues: default_fsconfig_num_queues(),
407             queue_size: default_fsconfig_queue_size(),
408             id: None,
409             pci_segment: 0,
410         }
411     }
412 }
413 
414 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
415 pub struct PmemConfig {
416     pub file: PathBuf,
417     #[serde(default)]
418     pub size: Option<u64>,
419     #[serde(default)]
420     pub iommu: bool,
421     #[serde(default)]
422     pub discard_writes: bool,
423     #[serde(default)]
424     pub id: Option<String>,
425     #[serde(default)]
426     pub pci_segment: u16,
427 }
428 
429 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
430 pub enum ConsoleOutputMode {
431     Off,
432     Pty,
433     Tty,
434     File,
435     Null,
436 }
437 
438 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
439 pub struct ConsoleConfig {
440     #[serde(default = "default_consoleconfig_file")]
441     pub file: Option<PathBuf>,
442     pub mode: ConsoleOutputMode,
443     #[serde(default)]
444     pub iommu: bool,
445 }
446 
447 pub fn default_consoleconfig_file() -> Option<PathBuf> {
448     None
449 }
450 
451 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
452 pub struct DeviceConfig {
453     pub path: PathBuf,
454     #[serde(default)]
455     pub iommu: bool,
456     #[serde(default)]
457     pub id: Option<String>,
458     #[serde(default)]
459     pub pci_segment: u16,
460 }
461 
462 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
463 pub struct UserDeviceConfig {
464     pub socket: PathBuf,
465     #[serde(default)]
466     pub id: Option<String>,
467     #[serde(default)]
468     pub pci_segment: u16,
469 }
470 
471 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
472 pub struct VdpaConfig {
473     pub path: PathBuf,
474     #[serde(default = "default_vdpaconfig_num_queues")]
475     pub num_queues: usize,
476     #[serde(default)]
477     pub iommu: bool,
478     #[serde(default)]
479     pub id: Option<String>,
480     #[serde(default)]
481     pub pci_segment: u16,
482 }
483 
484 pub fn default_vdpaconfig_num_queues() -> usize {
485     1
486 }
487 
488 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
489 pub struct VsockConfig {
490     pub cid: u64,
491     pub socket: PathBuf,
492     #[serde(default)]
493     pub iommu: bool,
494     #[serde(default)]
495     pub id: Option<String>,
496     #[serde(default)]
497     pub pci_segment: u16,
498 }
499 
500 #[cfg(target_arch = "x86_64")]
501 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
502 pub struct SgxEpcConfig {
503     pub id: String,
504     #[serde(default)]
505     pub size: u64,
506     #[serde(default)]
507     pub prefault: bool,
508 }
509 
510 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
511 pub struct NumaDistance {
512     #[serde(default)]
513     pub destination: u32,
514     #[serde(default)]
515     pub distance: u8,
516 }
517 
518 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
519 pub struct NumaConfig {
520     #[serde(default)]
521     pub guest_numa_id: u32,
522     #[serde(default)]
523     pub cpus: Option<Vec<u8>>,
524     #[serde(default)]
525     pub distances: Option<Vec<NumaDistance>>,
526     #[serde(default)]
527     pub memory_zones: Option<Vec<String>>,
528     #[cfg(target_arch = "x86_64")]
529     #[serde(default)]
530     pub sgx_epc_sections: Option<Vec<String>>,
531 }
532 
533 #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
534 pub struct PayloadConfig {
535     #[serde(default)]
536     pub firmware: Option<PathBuf>,
537     #[serde(default)]
538     pub kernel: Option<PathBuf>,
539     #[serde(default)]
540     pub cmdline: Option<String>,
541     #[serde(default)]
542     pub initramfs: Option<PathBuf>,
543 }
544 
545 pub fn default_serial() -> ConsoleConfig {
546     ConsoleConfig {
547         file: None,
548         mode: ConsoleOutputMode::Null,
549         iommu: false,
550     }
551 }
552 
553 pub fn default_console() -> ConsoleConfig {
554     ConsoleConfig {
555         file: None,
556         mode: ConsoleOutputMode::Tty,
557         iommu: false,
558     }
559 }
560 
561 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
562 pub struct TpmConfig {
563     pub socket: PathBuf,
564 }
565 
566 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
567 pub struct VmConfig {
568     #[serde(default)]
569     pub cpus: CpusConfig,
570     #[serde(default)]
571     pub memory: MemoryConfig,
572     pub payload: Option<PayloadConfig>,
573     pub disks: Option<Vec<DiskConfig>>,
574     pub net: Option<Vec<NetConfig>>,
575     #[serde(default)]
576     pub rng: RngConfig,
577     pub balloon: Option<BalloonConfig>,
578     pub fs: Option<Vec<FsConfig>>,
579     pub pmem: Option<Vec<PmemConfig>>,
580     #[serde(default = "default_serial")]
581     pub serial: ConsoleConfig,
582     #[serde(default = "default_console")]
583     pub console: ConsoleConfig,
584     pub devices: Option<Vec<DeviceConfig>>,
585     pub user_devices: Option<Vec<UserDeviceConfig>>,
586     pub vdpa: Option<Vec<VdpaConfig>>,
587     pub vsock: Option<VsockConfig>,
588     #[serde(default)]
589     pub pvpanic: bool,
590     #[serde(default)]
591     pub iommu: bool,
592     #[cfg(target_arch = "x86_64")]
593     pub sgx_epc: Option<Vec<SgxEpcConfig>>,
594     pub numa: Option<Vec<NumaConfig>>,
595     #[serde(default)]
596     pub watchdog: bool,
597     #[cfg(feature = "guest_debug")]
598     #[serde(default)]
599     pub gdb: bool,
600     pub platform: Option<PlatformConfig>,
601     pub tpm: Option<TpmConfig>,
602     // Preseved FDs are the ones that share the same life-time as its holding
603     // VmConfig instance, such as FDs for creating TAP devices.
604     // Perserved FDs will stay open as long as the holding VmConfig instance is
605     // valid, and will be closed when the holding VmConfig instance is destroyed.
606     #[serde(skip)]
607     pub preserved_fds: Option<Vec<i32>>,
608 }
609