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