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