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 } 93 94 impl Default for PlatformConfig { 95 fn default() -> Self { 96 PlatformConfig { 97 num_pci_segments: DEFAULT_NUM_PCI_SEGMENTS, 98 iommu_segments: None, 99 serial_number: None, 100 uuid: None, 101 oem_strings: None, 102 #[cfg(feature = "tdx")] 103 tdx: false, 104 } 105 } 106 } 107 108 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 109 pub struct MemoryZoneConfig { 110 pub id: String, 111 pub size: u64, 112 #[serde(default)] 113 pub file: Option<PathBuf>, 114 #[serde(default)] 115 pub shared: bool, 116 #[serde(default)] 117 pub hugepages: bool, 118 #[serde(default)] 119 pub hugepage_size: Option<u64>, 120 #[serde(default)] 121 pub host_numa_node: Option<u32>, 122 #[serde(default)] 123 pub hotplug_size: Option<u64>, 124 #[serde(default)] 125 pub hotplugged_size: Option<u64>, 126 #[serde(default)] 127 pub prefault: bool, 128 } 129 130 #[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize, Default)] 131 pub enum HotplugMethod { 132 #[default] 133 Acpi, 134 VirtioMem, 135 } 136 137 fn default_memoryconfig_thp() -> bool { 138 true 139 } 140 141 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 142 pub struct MemoryConfig { 143 pub size: u64, 144 #[serde(default)] 145 pub mergeable: bool, 146 #[serde(default)] 147 pub hotplug_method: HotplugMethod, 148 #[serde(default)] 149 pub hotplug_size: Option<u64>, 150 #[serde(default)] 151 pub hotplugged_size: Option<u64>, 152 #[serde(default)] 153 pub shared: bool, 154 #[serde(default)] 155 pub hugepages: bool, 156 #[serde(default)] 157 pub hugepage_size: Option<u64>, 158 #[serde(default)] 159 pub prefault: bool, 160 #[serde(default)] 161 pub zones: Option<Vec<MemoryZoneConfig>>, 162 #[serde(default = "default_memoryconfig_thp")] 163 pub thp: bool, 164 } 165 166 pub const DEFAULT_MEMORY_MB: u64 = 512; 167 168 impl Default for MemoryConfig { 169 fn default() -> Self { 170 MemoryConfig { 171 size: DEFAULT_MEMORY_MB << 20, 172 mergeable: false, 173 hotplug_method: HotplugMethod::Acpi, 174 hotplug_size: None, 175 hotplugged_size: None, 176 shared: false, 177 hugepages: false, 178 hugepage_size: None, 179 prefault: false, 180 zones: None, 181 thp: true, 182 } 183 } 184 } 185 186 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)] 187 pub enum VhostMode { 188 #[default] 189 Client, 190 Server, 191 } 192 193 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 194 pub struct DiskConfig { 195 pub path: Option<PathBuf>, 196 #[serde(default)] 197 pub readonly: bool, 198 #[serde(default)] 199 pub direct: bool, 200 #[serde(default)] 201 pub iommu: bool, 202 #[serde(default = "default_diskconfig_num_queues")] 203 pub num_queues: usize, 204 #[serde(default = "default_diskconfig_queue_size")] 205 pub queue_size: u16, 206 #[serde(default)] 207 pub vhost_user: bool, 208 pub vhost_socket: Option<String>, 209 #[serde(default)] 210 pub rate_limiter_config: Option<RateLimiterConfig>, 211 #[serde(default)] 212 pub id: Option<String>, 213 // For testing use only. Not exposed in API. 214 #[serde(default)] 215 pub disable_io_uring: bool, 216 #[serde(default)] 217 pub pci_segment: u16, 218 } 219 220 pub const DEFAULT_DISK_NUM_QUEUES: usize = 1; 221 222 pub fn default_diskconfig_num_queues() -> usize { 223 DEFAULT_DISK_NUM_QUEUES 224 } 225 226 pub const DEFAULT_DISK_QUEUE_SIZE: u16 = 128; 227 228 pub fn default_diskconfig_queue_size() -> u16 { 229 DEFAULT_DISK_QUEUE_SIZE 230 } 231 232 impl Default for DiskConfig { 233 fn default() -> Self { 234 Self { 235 path: None, 236 readonly: false, 237 direct: false, 238 iommu: false, 239 num_queues: default_diskconfig_num_queues(), 240 queue_size: default_diskconfig_queue_size(), 241 vhost_user: false, 242 vhost_socket: None, 243 id: None, 244 disable_io_uring: false, 245 rate_limiter_config: None, 246 pci_segment: 0, 247 } 248 } 249 } 250 251 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 252 pub struct NetConfig { 253 #[serde(default = "default_netconfig_tap")] 254 pub tap: Option<String>, 255 #[serde(default = "default_netconfig_ip")] 256 pub ip: Ipv4Addr, 257 #[serde(default = "default_netconfig_mask")] 258 pub mask: Ipv4Addr, 259 #[serde(default = "default_netconfig_mac")] 260 pub mac: MacAddr, 261 #[serde(default)] 262 pub host_mac: Option<MacAddr>, 263 #[serde(default)] 264 pub mtu: Option<u16>, 265 #[serde(default)] 266 pub iommu: bool, 267 #[serde(default = "default_netconfig_num_queues")] 268 pub num_queues: usize, 269 #[serde(default = "default_netconfig_queue_size")] 270 pub queue_size: u16, 271 #[serde(default)] 272 pub vhost_user: bool, 273 pub vhost_socket: Option<String>, 274 #[serde(default)] 275 pub vhost_mode: VhostMode, 276 #[serde(default)] 277 pub id: Option<String>, 278 #[serde(default)] 279 pub fds: Option<Vec<i32>>, 280 #[serde(default)] 281 pub rate_limiter_config: Option<RateLimiterConfig>, 282 #[serde(default)] 283 pub pci_segment: u16, 284 #[serde(default = "default_netconfig_true")] 285 pub offload_tso: bool, 286 #[serde(default = "default_netconfig_true")] 287 pub offload_ufo: bool, 288 #[serde(default = "default_netconfig_true")] 289 pub offload_csum: bool, 290 } 291 292 pub fn default_netconfig_true() -> bool { 293 true 294 } 295 296 pub fn default_netconfig_tap() -> Option<String> { 297 None 298 } 299 300 pub fn default_netconfig_ip() -> Ipv4Addr { 301 Ipv4Addr::new(192, 168, 249, 1) 302 } 303 304 pub fn default_netconfig_mask() -> Ipv4Addr { 305 Ipv4Addr::new(255, 255, 255, 0) 306 } 307 308 pub fn default_netconfig_mac() -> MacAddr { 309 MacAddr::local_random() 310 } 311 312 pub const DEFAULT_NET_NUM_QUEUES: usize = 2; 313 314 pub fn default_netconfig_num_queues() -> usize { 315 DEFAULT_NET_NUM_QUEUES 316 } 317 318 pub const DEFAULT_NET_QUEUE_SIZE: u16 = 256; 319 320 pub fn default_netconfig_queue_size() -> u16 { 321 DEFAULT_NET_QUEUE_SIZE 322 } 323 324 impl Default for NetConfig { 325 fn default() -> Self { 326 Self { 327 tap: default_netconfig_tap(), 328 ip: default_netconfig_ip(), 329 mask: default_netconfig_mask(), 330 mac: default_netconfig_mac(), 331 host_mac: None, 332 mtu: None, 333 iommu: false, 334 num_queues: default_netconfig_num_queues(), 335 queue_size: default_netconfig_queue_size(), 336 vhost_user: false, 337 vhost_socket: None, 338 vhost_mode: VhostMode::Client, 339 id: None, 340 fds: None, 341 rate_limiter_config: None, 342 pci_segment: 0, 343 offload_tso: true, 344 offload_ufo: true, 345 offload_csum: true, 346 } 347 } 348 } 349 350 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 351 pub struct RngConfig { 352 pub src: PathBuf, 353 #[serde(default)] 354 pub iommu: bool, 355 } 356 357 pub const DEFAULT_RNG_SOURCE: &str = "/dev/urandom"; 358 359 impl Default for RngConfig { 360 fn default() -> Self { 361 RngConfig { 362 src: PathBuf::from(DEFAULT_RNG_SOURCE), 363 iommu: false, 364 } 365 } 366 } 367 368 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 369 pub struct BalloonConfig { 370 pub size: u64, 371 /// Option to deflate the balloon in case the guest is out of memory. 372 #[serde(default)] 373 pub deflate_on_oom: bool, 374 /// Option to enable free page reporting from the guest. 375 #[serde(default)] 376 pub free_page_reporting: bool, 377 } 378 379 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 380 pub struct FsConfig { 381 pub tag: String, 382 pub socket: PathBuf, 383 #[serde(default = "default_fsconfig_num_queues")] 384 pub num_queues: usize, 385 #[serde(default = "default_fsconfig_queue_size")] 386 pub queue_size: u16, 387 #[serde(default)] 388 pub id: Option<String>, 389 #[serde(default)] 390 pub pci_segment: u16, 391 } 392 393 pub fn default_fsconfig_num_queues() -> usize { 394 1 395 } 396 397 pub fn default_fsconfig_queue_size() -> u16 { 398 1024 399 } 400 401 impl Default for FsConfig { 402 fn default() -> Self { 403 Self { 404 tag: "".to_owned(), 405 socket: PathBuf::new(), 406 num_queues: default_fsconfig_num_queues(), 407 queue_size: default_fsconfig_queue_size(), 408 id: None, 409 pci_segment: 0, 410 } 411 } 412 } 413 414 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)] 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 Null, 436 } 437 438 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 439 pub struct ConsoleConfig { 440 #[serde(default = "default_consoleconfig_file")] 441 pub file: Option<PathBuf>, 442 pub mode: ConsoleOutputMode, 443 #[serde(default)] 444 pub iommu: bool, 445 } 446 447 pub fn default_consoleconfig_file() -> Option<PathBuf> { 448 None 449 } 450 451 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)] 452 pub struct DeviceConfig { 453 pub path: PathBuf, 454 #[serde(default)] 455 pub iommu: bool, 456 #[serde(default)] 457 pub id: Option<String>, 458 #[serde(default)] 459 pub pci_segment: u16, 460 } 461 462 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)] 463 pub struct UserDeviceConfig { 464 pub socket: PathBuf, 465 #[serde(default)] 466 pub id: Option<String>, 467 #[serde(default)] 468 pub pci_segment: u16, 469 } 470 471 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)] 472 pub struct VdpaConfig { 473 pub path: PathBuf, 474 #[serde(default = "default_vdpaconfig_num_queues")] 475 pub num_queues: usize, 476 #[serde(default)] 477 pub iommu: bool, 478 #[serde(default)] 479 pub id: Option<String>, 480 #[serde(default)] 481 pub pci_segment: u16, 482 } 483 484 pub fn default_vdpaconfig_num_queues() -> usize { 485 1 486 } 487 488 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)] 489 pub struct VsockConfig { 490 pub cid: u64, 491 pub socket: PathBuf, 492 #[serde(default)] 493 pub iommu: bool, 494 #[serde(default)] 495 pub id: Option<String>, 496 #[serde(default)] 497 pub pci_segment: u16, 498 } 499 500 #[cfg(target_arch = "x86_64")] 501 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)] 502 pub struct SgxEpcConfig { 503 pub id: String, 504 #[serde(default)] 505 pub size: u64, 506 #[serde(default)] 507 pub prefault: bool, 508 } 509 510 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)] 511 pub struct NumaDistance { 512 #[serde(default)] 513 pub destination: u32, 514 #[serde(default)] 515 pub distance: u8, 516 } 517 518 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)] 519 pub struct NumaConfig { 520 #[serde(default)] 521 pub guest_numa_id: u32, 522 #[serde(default)] 523 pub cpus: Option<Vec<u8>>, 524 #[serde(default)] 525 pub distances: Option<Vec<NumaDistance>>, 526 #[serde(default)] 527 pub memory_zones: Option<Vec<String>>, 528 #[cfg(target_arch = "x86_64")] 529 #[serde(default)] 530 pub sgx_epc_sections: Option<Vec<String>>, 531 } 532 533 #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] 534 pub struct PayloadConfig { 535 #[serde(default)] 536 pub firmware: Option<PathBuf>, 537 #[serde(default)] 538 pub kernel: Option<PathBuf>, 539 #[serde(default)] 540 pub cmdline: Option<String>, 541 #[serde(default)] 542 pub initramfs: Option<PathBuf>, 543 } 544 545 pub fn default_serial() -> ConsoleConfig { 546 ConsoleConfig { 547 file: None, 548 mode: ConsoleOutputMode::Null, 549 iommu: false, 550 } 551 } 552 553 pub fn default_console() -> ConsoleConfig { 554 ConsoleConfig { 555 file: None, 556 mode: ConsoleOutputMode::Tty, 557 iommu: false, 558 } 559 } 560 561 #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 562 pub struct TpmConfig { 563 pub socket: PathBuf, 564 } 565 566 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)] 567 pub struct VmConfig { 568 #[serde(default)] 569 pub cpus: CpusConfig, 570 #[serde(default)] 571 pub memory: MemoryConfig, 572 pub payload: Option<PayloadConfig>, 573 pub disks: Option<Vec<DiskConfig>>, 574 pub net: Option<Vec<NetConfig>>, 575 #[serde(default)] 576 pub rng: RngConfig, 577 pub balloon: Option<BalloonConfig>, 578 pub fs: Option<Vec<FsConfig>>, 579 pub pmem: Option<Vec<PmemConfig>>, 580 #[serde(default = "default_serial")] 581 pub serial: ConsoleConfig, 582 #[serde(default = "default_console")] 583 pub console: ConsoleConfig, 584 pub devices: Option<Vec<DeviceConfig>>, 585 pub user_devices: Option<Vec<UserDeviceConfig>>, 586 pub vdpa: Option<Vec<VdpaConfig>>, 587 pub vsock: Option<VsockConfig>, 588 #[serde(default)] 589 pub pvpanic: bool, 590 #[serde(default)] 591 pub iommu: bool, 592 #[cfg(target_arch = "x86_64")] 593 pub sgx_epc: Option<Vec<SgxEpcConfig>>, 594 pub numa: Option<Vec<NumaConfig>>, 595 #[serde(default)] 596 pub watchdog: bool, 597 #[cfg(feature = "guest_debug")] 598 #[serde(default)] 599 pub gdb: bool, 600 pub platform: Option<PlatformConfig>, 601 pub tpm: Option<TpmConfig>, 602 // Preseved FDs are the ones that share the same life-time as its holding 603 // VmConfig instance, such as FDs for creating TAP devices. 604 // Perserved FDs will stay open as long as the holding VmConfig instance is 605 // valid, and will be closed when the holding VmConfig instance is destroyed. 606 #[serde(skip)] 607 pub preserved_fds: Option<Vec<i32>>, 608 } 609