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