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