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 pub const DEFAULT_PCI_SEGMENT_APERTURE_WEIGHT: u32 = 1; 98 99 fn default_pci_segment_aperture_weight() -> u32 { 100 DEFAULT_PCI_SEGMENT_APERTURE_WEIGHT 101 } 102 103 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 104 pub struct PciSegmentConfig { 105 #[serde(default)] 106 pub pci_segment: u16, 107 #[serde(default = "default_pci_segment_aperture_weight")] 108 pub mmio32_aperture_weight: u32, 109 #[serde(default = "default_pci_segment_aperture_weight")] 110 pub mmio64_aperture_weight: u32, 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 RateLimiterGroupConfig { 200 #[serde(default)] 201 pub id: String, 202 #[serde(default)] 203 pub rate_limiter_config: RateLimiterConfig, 204 } 205 206 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 207 pub struct VirtQueueAffinity { 208 pub queue_index: u16, 209 pub host_cpus: Vec<usize>, 210 } 211 212 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 213 pub struct DiskConfig { 214 pub path: Option<PathBuf>, 215 #[serde(default)] 216 pub readonly: bool, 217 #[serde(default)] 218 pub direct: bool, 219 #[serde(default)] 220 pub iommu: bool, 221 #[serde(default = "default_diskconfig_num_queues")] 222 pub num_queues: usize, 223 #[serde(default = "default_diskconfig_queue_size")] 224 pub queue_size: u16, 225 #[serde(default)] 226 pub vhost_user: bool, 227 pub vhost_socket: Option<String>, 228 #[serde(default)] 229 pub rate_limit_group: Option<String>, 230 #[serde(default)] 231 pub rate_limiter_config: Option<RateLimiterConfig>, 232 #[serde(default)] 233 pub id: Option<String>, 234 // For testing use only. Not exposed in API. 235 #[serde(default)] 236 pub disable_io_uring: bool, 237 // For testing use only. Not exposed in API. 238 #[serde(default)] 239 pub disable_aio: bool, 240 #[serde(default)] 241 pub pci_segment: u16, 242 #[serde(default)] 243 pub serial: Option<String>, 244 #[serde(default)] 245 pub queue_affinity: Option<Vec<VirtQueueAffinity>>, 246 } 247 248 pub const DEFAULT_DISK_NUM_QUEUES: usize = 1; 249 250 pub fn default_diskconfig_num_queues() -> usize { 251 DEFAULT_DISK_NUM_QUEUES 252 } 253 254 pub const DEFAULT_DISK_QUEUE_SIZE: u16 = 128; 255 256 pub fn default_diskconfig_queue_size() -> u16 { 257 DEFAULT_DISK_QUEUE_SIZE 258 } 259 260 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 261 pub struct NetConfig { 262 #[serde(default = "default_netconfig_tap")] 263 pub tap: Option<String>, 264 #[serde(default = "default_netconfig_ip")] 265 pub ip: Ipv4Addr, 266 #[serde(default = "default_netconfig_mask")] 267 pub mask: Ipv4Addr, 268 #[serde(default = "default_netconfig_mac")] 269 pub mac: MacAddr, 270 #[serde(default)] 271 pub host_mac: Option<MacAddr>, 272 #[serde(default)] 273 pub mtu: Option<u16>, 274 #[serde(default)] 275 pub iommu: bool, 276 #[serde(default = "default_netconfig_num_queues")] 277 pub num_queues: usize, 278 #[serde(default = "default_netconfig_queue_size")] 279 pub queue_size: u16, 280 #[serde(default)] 281 pub vhost_user: bool, 282 pub vhost_socket: Option<String>, 283 #[serde(default)] 284 pub vhost_mode: VhostMode, 285 #[serde(default)] 286 pub id: Option<String>, 287 #[serde( 288 default, 289 serialize_with = "serialize_netconfig_fds", 290 deserialize_with = "deserialize_netconfig_fds" 291 )] 292 pub fds: Option<Vec<i32>>, 293 #[serde(default)] 294 pub rate_limiter_config: Option<RateLimiterConfig>, 295 #[serde(default)] 296 pub pci_segment: u16, 297 #[serde(default = "default_netconfig_true")] 298 pub offload_tso: bool, 299 #[serde(default = "default_netconfig_true")] 300 pub offload_ufo: bool, 301 #[serde(default = "default_netconfig_true")] 302 pub offload_csum: bool, 303 } 304 305 pub fn default_netconfig_true() -> bool { 306 true 307 } 308 309 pub fn default_netconfig_tap() -> Option<String> { 310 None 311 } 312 313 pub fn default_netconfig_ip() -> Ipv4Addr { 314 Ipv4Addr::new(192, 168, 249, 1) 315 } 316 317 pub fn default_netconfig_mask() -> Ipv4Addr { 318 Ipv4Addr::new(255, 255, 255, 0) 319 } 320 321 pub fn default_netconfig_mac() -> MacAddr { 322 MacAddr::local_random() 323 } 324 325 pub const DEFAULT_NET_NUM_QUEUES: usize = 2; 326 327 pub fn default_netconfig_num_queues() -> usize { 328 DEFAULT_NET_NUM_QUEUES 329 } 330 331 pub const DEFAULT_NET_QUEUE_SIZE: u16 = 256; 332 333 pub fn default_netconfig_queue_size() -> u16 { 334 DEFAULT_NET_QUEUE_SIZE 335 } 336 337 fn serialize_netconfig_fds<S>(x: &Option<Vec<i32>>, s: S) -> Result<S::Ok, S::Error> 338 where 339 S: serde::Serializer, 340 { 341 if let Some(x) = x { 342 warn!("'NetConfig' contains FDs that can't be serialized correctly. Serializing them as invalid FDs."); 343 let invalid_fds = vec![-1; x.len()]; 344 s.serialize_some(&invalid_fds) 345 } else { 346 s.serialize_none() 347 } 348 } 349 350 fn deserialize_netconfig_fds<'de, D>(d: D) -> Result<Option<Vec<i32>>, D::Error> 351 where 352 D: serde::Deserializer<'de>, 353 { 354 let invalid_fds: Option<Vec<i32>> = Option::deserialize(d)?; 355 if let Some(invalid_fds) = invalid_fds { 356 warn!("'NetConfig' contains FDs that can't be deserialized correctly. Deserializing them as invalid FDs."); 357 Ok(Some(vec![-1; invalid_fds.len()])) 358 } else { 359 Ok(None) 360 } 361 } 362 363 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 364 pub struct RngConfig { 365 pub src: PathBuf, 366 #[serde(default)] 367 pub iommu: bool, 368 } 369 370 pub const DEFAULT_RNG_SOURCE: &str = "/dev/urandom"; 371 372 impl Default for RngConfig { 373 fn default() -> Self { 374 RngConfig { 375 src: PathBuf::from(DEFAULT_RNG_SOURCE), 376 iommu: false, 377 } 378 } 379 } 380 381 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 382 pub struct BalloonConfig { 383 pub size: u64, 384 /// Option to deflate the balloon in case the guest is out of memory. 385 #[serde(default)] 386 pub deflate_on_oom: bool, 387 /// Option to enable free page reporting from the guest. 388 #[serde(default)] 389 pub free_page_reporting: bool, 390 } 391 392 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 393 pub struct FsConfig { 394 pub tag: String, 395 pub socket: PathBuf, 396 #[serde(default = "default_fsconfig_num_queues")] 397 pub num_queues: usize, 398 #[serde(default = "default_fsconfig_queue_size")] 399 pub queue_size: u16, 400 #[serde(default)] 401 pub id: Option<String>, 402 #[serde(default)] 403 pub pci_segment: u16, 404 } 405 406 pub fn default_fsconfig_num_queues() -> usize { 407 1 408 } 409 410 pub fn default_fsconfig_queue_size() -> u16 { 411 1024 412 } 413 414 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 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 Socket, 436 Null, 437 } 438 439 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 440 pub struct ConsoleConfig { 441 #[serde(default = "default_consoleconfig_file")] 442 pub file: Option<PathBuf>, 443 pub mode: ConsoleOutputMode, 444 #[serde(default)] 445 pub iommu: bool, 446 pub socket: Option<PathBuf>, 447 } 448 449 pub fn default_consoleconfig_file() -> Option<PathBuf> { 450 None 451 } 452 453 #[cfg(target_arch = "x86_64")] 454 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 455 pub struct DebugConsoleConfig { 456 #[serde(default)] 457 pub file: Option<PathBuf>, 458 pub mode: ConsoleOutputMode, 459 /// Optionally dedicated I/O-port, if the default port should not be used. 460 pub iobase: Option<u16>, 461 } 462 463 #[cfg(target_arch = "x86_64")] 464 impl Default for DebugConsoleConfig { 465 fn default() -> Self { 466 Self { 467 file: None, 468 mode: ConsoleOutputMode::Off, 469 iobase: Some(devices::debug_console::DEFAULT_PORT as u16), 470 } 471 } 472 } 473 474 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 475 pub struct DeviceConfig { 476 pub path: PathBuf, 477 #[serde(default)] 478 pub iommu: bool, 479 #[serde(default)] 480 pub id: Option<String>, 481 #[serde(default)] 482 pub pci_segment: u16, 483 #[serde(default)] 484 pub x_nv_gpudirect_clique: Option<u8>, 485 } 486 487 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 488 pub struct UserDeviceConfig { 489 pub socket: PathBuf, 490 #[serde(default)] 491 pub id: Option<String>, 492 #[serde(default)] 493 pub pci_segment: u16, 494 } 495 496 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 497 pub struct VdpaConfig { 498 pub path: PathBuf, 499 #[serde(default = "default_vdpaconfig_num_queues")] 500 pub num_queues: usize, 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 pub fn default_vdpaconfig_num_queues() -> usize { 510 1 511 } 512 513 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 514 pub struct VsockConfig { 515 pub cid: u32, 516 pub socket: PathBuf, 517 #[serde(default)] 518 pub iommu: bool, 519 #[serde(default)] 520 pub id: Option<String>, 521 #[serde(default)] 522 pub pci_segment: u16, 523 } 524 525 #[cfg(target_arch = "x86_64")] 526 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 527 pub struct SgxEpcConfig { 528 pub id: String, 529 #[serde(default)] 530 pub size: u64, 531 #[serde(default)] 532 pub prefault: bool, 533 } 534 535 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 536 pub struct NumaDistance { 537 #[serde(default)] 538 pub destination: u32, 539 #[serde(default)] 540 pub distance: u8, 541 } 542 543 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 544 pub struct NumaConfig { 545 #[serde(default)] 546 pub guest_numa_id: u32, 547 #[serde(default)] 548 pub cpus: Option<Vec<u8>>, 549 #[serde(default)] 550 pub distances: Option<Vec<NumaDistance>>, 551 #[serde(default)] 552 pub memory_zones: Option<Vec<String>>, 553 #[cfg(target_arch = "x86_64")] 554 #[serde(default)] 555 pub sgx_epc_sections: Option<Vec<String>>, 556 #[serde(default)] 557 pub pci_segments: Option<Vec<u16>>, 558 } 559 560 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 561 pub struct PayloadConfig { 562 #[serde(default)] 563 pub firmware: Option<PathBuf>, 564 #[serde(default)] 565 pub kernel: Option<PathBuf>, 566 #[serde(default)] 567 pub cmdline: Option<String>, 568 #[serde(default)] 569 pub initramfs: Option<PathBuf>, 570 #[cfg(feature = "igvm")] 571 #[serde(default)] 572 pub igvm: Option<PathBuf>, 573 #[cfg(feature = "sev_snp")] 574 #[serde(default)] 575 pub host_data: Option<String>, 576 } 577 578 pub fn default_serial() -> ConsoleConfig { 579 ConsoleConfig { 580 file: None, 581 mode: ConsoleOutputMode::Null, 582 iommu: false, 583 socket: None, 584 } 585 } 586 587 pub fn default_console() -> ConsoleConfig { 588 ConsoleConfig { 589 file: None, 590 mode: ConsoleOutputMode::Tty, 591 iommu: false, 592 socket: None, 593 } 594 } 595 596 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 597 pub struct TpmConfig { 598 pub socket: PathBuf, 599 } 600 601 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)] 602 pub struct VmConfig { 603 #[serde(default)] 604 pub cpus: CpusConfig, 605 #[serde(default)] 606 pub memory: MemoryConfig, 607 pub payload: Option<PayloadConfig>, 608 pub rate_limit_groups: Option<Vec<RateLimiterGroupConfig>>, 609 pub disks: Option<Vec<DiskConfig>>, 610 pub net: Option<Vec<NetConfig>>, 611 #[serde(default)] 612 pub rng: RngConfig, 613 pub balloon: Option<BalloonConfig>, 614 pub fs: Option<Vec<FsConfig>>, 615 pub pmem: Option<Vec<PmemConfig>>, 616 #[serde(default = "default_serial")] 617 pub serial: ConsoleConfig, 618 #[serde(default = "default_console")] 619 pub console: ConsoleConfig, 620 #[cfg(target_arch = "x86_64")] 621 #[serde(default)] 622 pub debug_console: DebugConsoleConfig, 623 pub devices: Option<Vec<DeviceConfig>>, 624 pub user_devices: Option<Vec<UserDeviceConfig>>, 625 pub vdpa: Option<Vec<VdpaConfig>>, 626 pub vsock: Option<VsockConfig>, 627 #[serde(default)] 628 pub pvpanic: bool, 629 #[serde(default)] 630 pub iommu: bool, 631 #[cfg(target_arch = "x86_64")] 632 pub sgx_epc: Option<Vec<SgxEpcConfig>>, 633 pub numa: Option<Vec<NumaConfig>>, 634 #[serde(default)] 635 pub watchdog: bool, 636 #[cfg(feature = "guest_debug")] 637 #[serde(default)] 638 pub gdb: bool, 639 pub pci_segments: Option<Vec<PciSegmentConfig>>, 640 pub platform: Option<PlatformConfig>, 641 pub tpm: Option<TpmConfig>, 642 // Preserved FDs are the ones that share the same life-time as its holding 643 // VmConfig instance, such as FDs for creating TAP devices. 644 // Preserved FDs will stay open as long as the holding VmConfig instance is 645 // valid, and will be closed when the holding VmConfig instance is destroyed. 646 #[serde(skip)] 647 pub preserved_fds: Option<Vec<i32>>, 648 } 649