xref: /cloud-hypervisor/vmm/src/vm_config.rs (revision fa7a000dbe9637eb256af18ae8c3c4a8d5bf9c8f)
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(
272         default,
273         serialize_with = "serialize_netconfig_fds",
274         deserialize_with = "deserialize_netconfig_fds"
275     )]
276     pub fds: Option<Vec<i32>>,
277     #[serde(default)]
278     pub rate_limiter_config: Option<RateLimiterConfig>,
279     #[serde(default)]
280     pub pci_segment: u16,
281     #[serde(default = "default_netconfig_true")]
282     pub offload_tso: bool,
283     #[serde(default = "default_netconfig_true")]
284     pub offload_ufo: bool,
285     #[serde(default = "default_netconfig_true")]
286     pub offload_csum: bool,
287 }
288 
289 pub fn default_netconfig_true() -> bool {
290     true
291 }
292 
293 pub fn default_netconfig_tap() -> Option<String> {
294     None
295 }
296 
297 pub fn default_netconfig_ip() -> Ipv4Addr {
298     Ipv4Addr::new(192, 168, 249, 1)
299 }
300 
301 pub fn default_netconfig_mask() -> Ipv4Addr {
302     Ipv4Addr::new(255, 255, 255, 0)
303 }
304 
305 pub fn default_netconfig_mac() -> MacAddr {
306     MacAddr::local_random()
307 }
308 
309 pub const DEFAULT_NET_NUM_QUEUES: usize = 2;
310 
311 pub fn default_netconfig_num_queues() -> usize {
312     DEFAULT_NET_NUM_QUEUES
313 }
314 
315 pub const DEFAULT_NET_QUEUE_SIZE: u16 = 256;
316 
317 pub fn default_netconfig_queue_size() -> u16 {
318     DEFAULT_NET_QUEUE_SIZE
319 }
320 
321 fn serialize_netconfig_fds<S>(x: &Option<Vec<i32>>, s: S) -> Result<S::Ok, S::Error>
322 where
323     S: serde::Serializer,
324 {
325     if let Some(x) = x {
326         warn!("'NetConfig' contains FDs that can't be serialized correctly. Serializing them as invalid FDs.");
327         let invalid_fds = vec![-1; x.len()];
328         s.serialize_some(&invalid_fds)
329     } else {
330         s.serialize_none()
331     }
332 }
333 
334 fn deserialize_netconfig_fds<'de, D>(d: D) -> Result<Option<Vec<i32>>, D::Error>
335 where
336     D: serde::Deserializer<'de>,
337 {
338     let invalid_fds: Option<Vec<i32>> = Option::deserialize(d)?;
339     if let Some(invalid_fds) = invalid_fds {
340         warn!("'NetConfig' contains FDs that can't be deserialized correctly. Deserializing them as invalid FDs.");
341         Ok(Some(vec![-1; invalid_fds.len()]))
342     } else {
343         Ok(None)
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 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
399 pub struct PmemConfig {
400     pub file: PathBuf,
401     #[serde(default)]
402     pub size: Option<u64>,
403     #[serde(default)]
404     pub iommu: bool,
405     #[serde(default)]
406     pub discard_writes: bool,
407     #[serde(default)]
408     pub id: Option<String>,
409     #[serde(default)]
410     pub pci_segment: u16,
411 }
412 
413 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
414 pub enum ConsoleOutputMode {
415     Off,
416     Pty,
417     Tty,
418     File,
419     Socket,
420     Null,
421 }
422 
423 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
424 pub struct ConsoleConfig {
425     #[serde(default = "default_consoleconfig_file")]
426     pub file: Option<PathBuf>,
427     pub mode: ConsoleOutputMode,
428     #[serde(default)]
429     pub iommu: bool,
430     pub socket: Option<PathBuf>,
431 }
432 
433 pub fn default_consoleconfig_file() -> Option<PathBuf> {
434     None
435 }
436 
437 #[cfg(target_arch = "x86_64")]
438 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
439 pub struct DebugConsoleConfig {
440     #[serde(default)]
441     pub file: Option<PathBuf>,
442     pub mode: ConsoleOutputMode,
443     /// Optionally dedicated I/O-port, if the default port should not be used.
444     pub iobase: Option<u16>,
445 }
446 
447 #[cfg(target_arch = "x86_64")]
448 impl Default for DebugConsoleConfig {
449     fn default() -> Self {
450         Self {
451             file: None,
452             mode: ConsoleOutputMode::Off,
453             iobase: Some(devices::debug_console::DEFAULT_PORT as u16),
454         }
455     }
456 }
457 
458 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
459 pub struct DeviceConfig {
460     pub path: PathBuf,
461     #[serde(default)]
462     pub iommu: bool,
463     #[serde(default)]
464     pub id: Option<String>,
465     #[serde(default)]
466     pub pci_segment: u16,
467     #[serde(default)]
468     pub x_nv_gpudirect_clique: Option<u8>,
469 }
470 
471 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
472 pub struct UserDeviceConfig {
473     pub socket: PathBuf,
474     #[serde(default)]
475     pub id: Option<String>,
476     #[serde(default)]
477     pub pci_segment: u16,
478 }
479 
480 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
481 pub struct VdpaConfig {
482     pub path: PathBuf,
483     #[serde(default = "default_vdpaconfig_num_queues")]
484     pub num_queues: usize,
485     #[serde(default)]
486     pub iommu: bool,
487     #[serde(default)]
488     pub id: Option<String>,
489     #[serde(default)]
490     pub pci_segment: u16,
491 }
492 
493 pub fn default_vdpaconfig_num_queues() -> usize {
494     1
495 }
496 
497 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
498 pub struct VsockConfig {
499     pub cid: u32,
500     pub socket: PathBuf,
501     #[serde(default)]
502     pub iommu: bool,
503     #[serde(default)]
504     pub id: Option<String>,
505     #[serde(default)]
506     pub pci_segment: u16,
507 }
508 
509 #[cfg(target_arch = "x86_64")]
510 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
511 pub struct SgxEpcConfig {
512     pub id: String,
513     #[serde(default)]
514     pub size: u64,
515     #[serde(default)]
516     pub prefault: bool,
517 }
518 
519 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
520 pub struct NumaDistance {
521     #[serde(default)]
522     pub destination: u32,
523     #[serde(default)]
524     pub distance: u8,
525 }
526 
527 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
528 pub struct NumaConfig {
529     #[serde(default)]
530     pub guest_numa_id: u32,
531     #[serde(default)]
532     pub cpus: Option<Vec<u8>>,
533     #[serde(default)]
534     pub distances: Option<Vec<NumaDistance>>,
535     #[serde(default)]
536     pub memory_zones: Option<Vec<String>>,
537     #[cfg(target_arch = "x86_64")]
538     #[serde(default)]
539     pub sgx_epc_sections: Option<Vec<String>>,
540     #[serde(default)]
541     pub pci_segments: Option<Vec<u16>>,
542 }
543 
544 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
545 pub struct PayloadConfig {
546     #[serde(default)]
547     pub firmware: Option<PathBuf>,
548     #[serde(default)]
549     pub kernel: Option<PathBuf>,
550     #[serde(default)]
551     pub cmdline: Option<String>,
552     #[serde(default)]
553     pub initramfs: Option<PathBuf>,
554     #[cfg(feature = "igvm")]
555     #[serde(default)]
556     pub igvm: Option<PathBuf>,
557     #[cfg(feature = "sev_snp")]
558     #[serde(default)]
559     pub host_data: Option<String>,
560 }
561 
562 pub fn default_serial() -> ConsoleConfig {
563     ConsoleConfig {
564         file: None,
565         mode: ConsoleOutputMode::Null,
566         iommu: false,
567         socket: None,
568     }
569 }
570 
571 pub fn default_console() -> ConsoleConfig {
572     ConsoleConfig {
573         file: None,
574         mode: ConsoleOutputMode::Tty,
575         iommu: false,
576         socket: None,
577     }
578 }
579 
580 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
581 pub struct TpmConfig {
582     pub socket: PathBuf,
583 }
584 
585 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
586 pub struct VmConfig {
587     #[serde(default)]
588     pub cpus: CpusConfig,
589     #[serde(default)]
590     pub memory: MemoryConfig,
591     pub payload: Option<PayloadConfig>,
592     pub rate_limit_groups: Option<Vec<RateLimiterGroupConfig>>,
593     pub disks: Option<Vec<DiskConfig>>,
594     pub net: Option<Vec<NetConfig>>,
595     #[serde(default)]
596     pub rng: RngConfig,
597     pub balloon: Option<BalloonConfig>,
598     pub fs: Option<Vec<FsConfig>>,
599     pub pmem: Option<Vec<PmemConfig>>,
600     #[serde(default = "default_serial")]
601     pub serial: ConsoleConfig,
602     #[serde(default = "default_console")]
603     pub console: ConsoleConfig,
604     #[cfg(target_arch = "x86_64")]
605     #[serde(default)]
606     pub debug_console: DebugConsoleConfig,
607     pub devices: Option<Vec<DeviceConfig>>,
608     pub user_devices: Option<Vec<UserDeviceConfig>>,
609     pub vdpa: Option<Vec<VdpaConfig>>,
610     pub vsock: Option<VsockConfig>,
611     #[serde(default)]
612     pub pvpanic: bool,
613     #[serde(default)]
614     pub iommu: bool,
615     #[cfg(target_arch = "x86_64")]
616     pub sgx_epc: Option<Vec<SgxEpcConfig>>,
617     pub numa: Option<Vec<NumaConfig>>,
618     #[serde(default)]
619     pub watchdog: bool,
620     #[cfg(feature = "guest_debug")]
621     #[serde(default)]
622     pub gdb: bool,
623     pub platform: Option<PlatformConfig>,
624     pub tpm: Option<TpmConfig>,
625     // Preserved FDs are the ones that share the same life-time as its holding
626     // VmConfig instance, such as FDs for creating TAP devices.
627     // Preserved FDs will stay open as long as the holding VmConfig instance is
628     // valid, and will be closed when the holding VmConfig instance is destroyed.
629     #[serde(skip)]
630     pub preserved_fds: Option<Vec<i32>>,
631 }
632