1#[cfg(feature = "tee")]
7use std::fs::File;
8#[cfg(feature = "tee")]
9use std::io::BufReader;
10#[cfg(not(target_os = "windows"))]
11use std::os::fd::RawFd;
12use std::path::PathBuf;
13use std::time::Duration;
14
15#[cfg(feature = "tee")]
16use serde::{Deserialize, Serialize};
17
18#[cfg(feature = "blk")]
19use crate::vmm_config::block::{BlockBuilder, BlockConfigError, BlockDeviceConfig};
20use crate::vmm_config::external_kernel::ExternalKernel;
21use crate::vmm_config::firmware::FirmwareConfig;
22#[cfg(not(feature = "tee"))]
23use crate::vmm_config::fs::*;
24use crate::vmm_config::kernel_bundle::InitrdBundle;
25use crate::vmm_config::kernel_bundle::{KernelBundle, KernelBundleError};
26#[cfg(feature = "tee")]
27use crate::vmm_config::kernel_bundle::{QbootBundle, QbootBundleError};
28use crate::vmm_config::kernel_cmdline::{KernelCmdlineConfig, KernelCmdlineConfigError};
29use crate::vmm_config::machine_config::HostCpuId;
30use crate::vmm_config::machine_config::{VmConfig, VmConfigError};
31#[cfg(feature = "net")]
32use crate::vmm_config::net::{NetBuilder, NetworkInterfaceConfig, NetworkInterfaceError};
33use crate::vmm_config::vsock::*;
34use crate::vstate::VcpuConfig;
35#[cfg(feature = "gpu")]
36use devices::virtio::display::DisplayInfo;
37#[cfg(feature = "tee")]
38use kbs_types::Tee;
39#[cfg(feature = "gpu")]
40use krun_display::DisplayBackend;
41use utils::metrics::MetricsWriter;
42
43type Result<E> = std::result::Result<(), E>;
44
45#[cfg(target_os = "windows")]
46pub use crate::vmm_config::vsock::TsiFlags;
47#[cfg(not(target_os = "windows"))]
48pub use devices::virtio::TsiFlags;
49
50#[derive(Debug)]
52pub enum Error {
53 InvalidJson,
55 KernelCmdline(KernelCmdlineConfigError),
57 #[cfg(feature = "tee")]
59 OpenTeeConfig(std::io::Error),
60 #[cfg(feature = "tee")]
62 ParseTeeConfig(serde_json::Error),
63 VmConfig(VmConfigError),
65 VsockDevice(VsockConfigError),
67}
68
69#[cfg(feature = "tee")]
70#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct TeeConfig {
72 pub workload_id: String,
73 pub cpus: u8,
74 pub ram_mib: usize,
75 pub tee: Tee,
76 pub tee_data: String,
77 pub attestation_url: String,
78}
79
80#[cfg(feature = "tee")]
81impl Default for TeeConfig {
82 fn default() -> Self {
83 Self {
84 workload_id: "".to_string(),
85 cpus: 0,
86 ram_mib: 0,
87 tee: Tee::Sev,
88 tee_data: "".to_string(),
89 attestation_url: "".to_string(),
90 }
91 }
92}
93
94#[cfg(not(target_os = "windows"))]
95pub struct SerialConsoleConfig {
96 pub input_fd: RawFd,
97 pub output_fd: RawFd,
98}
99
100#[cfg(not(target_os = "windows"))]
101pub struct DefaultVirtioConsoleConfig {
102 pub input_fd: RawFd,
103 pub output_fd: RawFd,
104 pub err_fd: RawFd,
105}
106
107#[cfg(not(target_os = "windows"))]
108pub enum VirtioConsoleConfigMode {
109 Autoconfigure(DefaultVirtioConsoleConfig),
110 Explicit(Vec<PortConfig>),
111}
112
113#[cfg(target_os = "windows")]
114pub enum VirtioConsoleConfigMode {
115 Explicit(Vec<PortConfig>),
116}
117
118#[cfg(not(target_os = "windows"))]
119pub enum PortConfig {
120 Tty {
121 name: String,
122 tty_fd: RawFd,
123 },
124 InOut {
125 name: String,
126 input_fd: RawFd,
127 output_fd: RawFd,
128 },
129 Custom {
130 name: String,
131 input: Box<dyn devices::virtio::port_io::PortInput + Send>,
132 output: Box<dyn devices::virtio::port_io::PortOutput + Send>,
133 },
134}
135
136#[cfg(target_os = "windows")]
137pub enum PortConfig {
138 ConsoleOutputFile { path: PathBuf },
139 NamedPipe { name: String, pipe_name: String },
140}
141
142#[derive(Debug, Default, Clone, Eq, PartialEq)]
144pub enum VsockConfig {
145 #[default]
147 Implicit,
148 Explicit { tsi_flags: TsiFlags },
150 Disabled,
152}
153
154#[derive(Clone, Debug, PartialEq, Eq)]
159pub struct NumaTopology {
160 pub nodes: Vec<NumaNodeConfig>,
162 pub distances: Vec<NumaDistance>,
164}
165
166#[derive(Clone, Debug, PartialEq, Eq)]
168pub struct NumaNodeConfig {
169 pub guest_node_id: u16,
171 pub vcpu_indices: Vec<u8>,
173 pub memory_mib: usize,
175 pub max_memory_mib: usize,
177 pub host_memory: HostMemoryPolicy,
179}
180
181#[derive(Clone, Copy, Debug, PartialEq, Eq)]
183pub struct NumaDistance {
184 pub from: u16,
186 pub to: u16,
188 pub value: u8,
190}
191
192#[derive(Clone, Debug, PartialEq, Eq)]
194pub enum HostMemoryPolicy {
195 Inherit,
197 Bind {
199 host_nodes: Vec<u32>,
201 },
202 PreferredMany {
205 host_nodes: Vec<u32>,
207 },
208 Preferred {
210 host_node: u32,
212 },
213}
214
215#[derive(Clone, Debug, PartialEq, Eq)]
217pub struct PlacementReport {
218 pub vcpus: Vec<VcpuPlacementResult>,
220 pub memory: MemoryPlacementResult,
222}
223
224#[derive(Clone, Debug, PartialEq, Eq)]
226pub enum VcpuPlacementResult {
227 Pinned {
229 vcpu_index: u8,
231 host_cpu: HostCpuId,
233 },
234 Inherited {
236 vcpu_index: u8,
238 requested_host_cpu: Option<HostCpuId>,
240 reason: Option<String>,
242 },
243}
244
245#[derive(Clone, Debug, PartialEq, Eq)]
247pub enum MemoryPlacementResult {
248 Inherited,
250 Applied,
252 Fallback {
254 reason: String,
256 },
257 Partial {
259 reason: String,
261 },
262}
263
264pub struct VmResources {
267 vm_config: VmConfig,
269 #[cfg(any(target_os = "linux", target_os = "windows"))]
271 pub vcpu_affinity: Option<Vec<HostCpuId>>,
272 #[cfg(any(target_os = "linux", target_os = "windows"))]
274 pub vcpu_affinity_required: bool,
275 pub numa_topology: Option<NumaTopology>,
277 pub firmware_config: Option<FirmwareConfig>,
279 pub kernel_cmdline: KernelCmdlineConfig,
281 pub kernel_bundle: Option<KernelBundle>,
283 pub external_kernel: Option<ExternalKernel>,
285 #[cfg(feature = "tee")]
287 pub qboot_bundle: Option<QbootBundle>,
288 pub initrd_bundle: Option<InitrdBundle>,
290 #[cfg(not(feature = "tee"))]
292 pub fs: Vec<FsDeviceConfig>,
293 #[cfg(not(any(feature = "tee", feature = "aws-nitro")))]
295 pub custom_fs: Vec<CustomFsDeviceConfig>,
296 pub vsock: VsockBuilder,
298 #[cfg(feature = "blk")]
300 pub block: BlockBuilder,
301 #[cfg(feature = "net")]
303 pub net: NetBuilder,
304 #[cfg(feature = "tee")]
306 pub tee_config: TeeConfig,
307 pub gpu_virgl_flags: Option<u32>,
309 pub gpu_shm_size: Option<usize>,
310 #[cfg(feature = "gpu")]
311 pub display_backend: Option<DisplayBackend<'static>>,
312 #[cfg(feature = "gpu")]
313 pub displays: Vec<DisplayInfo>,
314 #[cfg(feature = "input")]
315 pub input_backends: Vec<(
316 krun_input::InputConfigBackend<'static>,
317 krun_input::InputEventProviderBackend<'static>,
318 )>,
319 #[cfg(feature = "snd")]
320 pub snd_device: bool,
322 pub console_output: Option<PathBuf>,
324 pub smbios_oem_strings: Option<Vec<String>>,
326 pub nested_enabled: bool,
328 pub split_irqchip: bool,
330 pub metrics: MetricsWriter,
332 pub enable_balloon: bool,
334 #[cfg(not(feature = "tee"))]
339 pub mem_device: Option<std::sync::Arc<std::sync::Mutex<devices::virtio::Mem>>>,
340 #[cfg(not(feature = "tee"))]
344 pub cpu_device: Option<std::sync::Arc<std::sync::Mutex<devices::virtio::Cpu>>>,
345 pub balloon_stats_interval: Option<Duration>,
347 pub enable_rng: bool,
349 pub enable_msb_metrics: bool,
351 pub disable_implicit_console: bool,
353 pub kernel_console: Option<String>,
355 #[cfg(not(target_os = "windows"))]
357 pub serial_consoles: Vec<SerialConsoleConfig>,
358 pub virtio_consoles: Vec<VirtioConsoleConfigMode>,
360}
361
362impl Default for VmResources {
363 fn default() -> Self {
364 Self {
365 vm_config: VmConfig::default(),
366 #[cfg(any(target_os = "linux", target_os = "windows"))]
367 vcpu_affinity: None,
368 #[cfg(any(target_os = "linux", target_os = "windows"))]
369 vcpu_affinity_required: true,
370 numa_topology: None,
371 firmware_config: None,
372 kernel_cmdline: KernelCmdlineConfig::default(),
373 kernel_bundle: None,
374 external_kernel: None,
375 #[cfg(feature = "tee")]
376 qboot_bundle: None,
377 initrd_bundle: None,
378 #[cfg(not(feature = "tee"))]
379 fs: Vec::new(),
380 #[cfg(not(any(feature = "tee", feature = "aws-nitro")))]
381 custom_fs: Vec::new(),
382 vsock: VsockBuilder::default(),
383 #[cfg(feature = "blk")]
384 block: BlockBuilder::default(),
385 #[cfg(feature = "net")]
386 net: NetBuilder::default(),
387 #[cfg(feature = "tee")]
388 tee_config: TeeConfig::default(),
389 gpu_virgl_flags: None,
390 gpu_shm_size: None,
391 #[cfg(feature = "gpu")]
392 display_backend: None,
393 #[cfg(feature = "gpu")]
394 displays: Vec::new(),
395 #[cfg(feature = "input")]
396 input_backends: Vec::new(),
397 #[cfg(feature = "snd")]
398 snd_device: false,
399 console_output: None,
400 smbios_oem_strings: None,
401 nested_enabled: false,
402 split_irqchip: false,
403 metrics: MetricsWriter::default(),
404 enable_balloon: true,
405 #[cfg(not(feature = "tee"))]
406 mem_device: None,
407 #[cfg(not(feature = "tee"))]
408 cpu_device: None,
409 balloon_stats_interval: Some(Duration::from_secs(1)),
410 enable_rng: true,
411 enable_msb_metrics: true,
412 disable_implicit_console: false,
413 kernel_console: None,
414 #[cfg(not(target_os = "windows"))]
415 serial_consoles: Vec::new(),
416 virtio_consoles: Vec::new(),
417 }
418 }
419}
420
421impl VmResources {
422 pub fn vcpu_config(&self) -> VcpuConfig {
424 let vcpu_count = self.vm_config().vcpu_count.unwrap();
427 VcpuConfig {
428 vcpu_count,
429 max_vcpu_count: self.vm_config().max_vcpu_count.unwrap_or(vcpu_count),
430 ht_enabled: self.vm_config().ht_enabled.unwrap(),
431 cpu_template: self.vm_config().cpu_template,
432 }
433 }
434
435 pub fn vm_config(&self) -> &VmConfig {
437 &self.vm_config
438 }
439
440 pub fn set_vm_config(&mut self, machine_config: &VmConfig) -> Result<VmConfigError> {
442 if machine_config.vcpu_count == Some(0) {
443 return Err(VmConfigError::InvalidVcpuCount);
444 }
445
446 if machine_config.mem_size_mib == Some(0) {
447 return Err(VmConfigError::InvalidMemorySize);
448 }
449
450 let ht_enabled = machine_config
451 .ht_enabled
452 .unwrap_or_else(|| self.vm_config.ht_enabled.unwrap());
453
454 let vcpu_count_value = machine_config
455 .vcpu_count
456 .unwrap_or_else(|| self.vm_config.vcpu_count.unwrap());
457
458 if ht_enabled && vcpu_count_value > 1 && vcpu_count_value % 2 == 1 {
461 return Err(VmConfigError::InvalidVcpuCount);
462 }
463
464 if let Some(max_vcpu_count) = machine_config.max_vcpu_count {
465 if max_vcpu_count < vcpu_count_value
466 || max_vcpu_count > crate::vmm_config::machine_config::MAX_SUPPORTED_VCPUS
467 {
468 return Err(VmConfigError::InvalidMaxVcpuCount);
469 }
470 if ht_enabled && max_vcpu_count > 1 && max_vcpu_count % 2 == 1 {
471 return Err(VmConfigError::InvalidMaxVcpuCount);
472 }
473 #[cfg(any(target_arch = "riscv64", feature = "tee"))]
479 if max_vcpu_count > vcpu_count_value {
480 return Err(VmConfigError::MaxCapacityUnsupported);
481 }
482 }
483
484 if let Some(max_mem_size_mib) = machine_config.max_mem_size_mib {
485 let mem_size_mib = machine_config
486 .mem_size_mib
487 .unwrap_or_else(|| self.vm_config.mem_size_mib.unwrap());
488 if max_mem_size_mib < mem_size_mib {
489 return Err(VmConfigError::InvalidMaxMemorySize);
490 }
491 }
492
493 self.vm_config.vcpu_count = Some(vcpu_count_value);
495 self.vm_config.ht_enabled = Some(ht_enabled);
496 self.vm_config.max_vcpu_count = machine_config.max_vcpu_count;
497 self.vm_config.max_mem_size_mib = machine_config.max_mem_size_mib;
498
499 if machine_config.mem_size_mib.is_some() {
500 self.vm_config.mem_size_mib = machine_config.mem_size_mib;
501 }
502 let memory_total_bytes = self
503 .vm_config
504 .mem_size_mib
505 .unwrap_or(128)
506 .saturating_mul(1024)
507 .saturating_mul(1024) as u64;
508 self.metrics.set_memory_total_bytes(memory_total_bytes);
509
510 if machine_config.cpu_template.is_some() {
511 self.vm_config.cpu_template = machine_config.cpu_template;
512 }
513
514 Ok(())
515 }
516
517 pub fn set_kernel_cmdline(
519 &mut self,
520 kernel_cmdline_cfg: KernelCmdlineConfig,
521 ) -> Result<KernelCmdlineConfigError> {
522 self.kernel_cmdline = kernel_cmdline_cfg;
523 Ok(())
524 }
525
526 pub fn kernel_bundle(&self) -> Option<&KernelBundle> {
527 self.kernel_bundle.as_ref()
528 }
529
530 pub fn set_kernel_bundle(&mut self, kernel_bundle: KernelBundle) -> Result<KernelBundleError> {
531 let page_size = utils::page_size();
533
534 if kernel_bundle.host_addr == 0 || (kernel_bundle.host_addr as usize) & (page_size - 1) != 0
535 {
536 return Err(KernelBundleError::InvalidHostAddress);
537 }
538
539 if (kernel_bundle.guest_addr as usize) & (page_size - 1) != 0 {
540 return Err(KernelBundleError::InvalidGuestAddress);
541 }
542
543 self.kernel_bundle = Some(kernel_bundle);
544 Ok(())
545 }
546
547 pub fn external_kernel(&self) -> Option<&ExternalKernel> {
548 self.external_kernel.as_ref()
549 }
550
551 pub fn set_external_kernel(&mut self, external_kernel: ExternalKernel) {
552 self.external_kernel = Some(external_kernel);
553 }
554
555 pub fn set_firmware_config(&mut self, firmware_config: FirmwareConfig) {
556 self.firmware_config = Some(firmware_config);
557 }
558
559 #[cfg(feature = "tee")]
560 pub fn qboot_bundle(&self) -> Option<&QbootBundle> {
561 self.qboot_bundle.as_ref()
562 }
563
564 #[cfg(feature = "tee")]
565 pub fn set_qboot_bundle(&mut self, qboot_bundle: QbootBundle) -> Result<QbootBundleError> {
566 if qboot_bundle.size != 0x10000 {
567 return Err(QbootBundleError::InvalidSize);
568 }
569
570 self.qboot_bundle = Some(qboot_bundle);
571 Ok(())
572 }
573
574 pub fn initrd_bundle(&self) -> Option<&InitrdBundle> {
575 self.initrd_bundle.as_ref()
576 }
577
578 pub fn set_initrd_bundle(&mut self, initrd_bundle: InitrdBundle) -> Result<KernelBundleError> {
579 self.initrd_bundle = Some(initrd_bundle);
580 Ok(())
581 }
582
583 #[cfg(not(feature = "tee"))]
584 pub fn add_fs_device(&mut self, config: FsDeviceConfig) {
585 self.fs.push(config)
586 }
587
588 #[cfg(feature = "blk")]
589 pub fn add_block_device(&mut self, config: BlockDeviceConfig) -> Result<BlockConfigError> {
590 self.block.insert(config, self.metrics.clone())
591 }
592
593 #[cfg(feature = "blk")]
595 pub fn add_block_device_with_writeback_limit(
596 &mut self,
597 config: BlockDeviceConfig,
598 writeback_limit_bytes: Option<u64>,
599 ) -> Result<BlockConfigError> {
600 self.block
601 .insert_with_writeback_limit(config, writeback_limit_bytes, self.metrics.clone())
602 }
603
604 #[cfg(feature = "blk")]
606 pub fn add_block_device_with_writeback_limit_handle(
607 &mut self,
608 config: BlockDeviceConfig,
609 writeback_limit: Option<devices::virtio::block::WritebackLimit>,
610 ) -> Result<BlockConfigError> {
611 self.block
612 .insert_with_writeback_limit_handle(config, writeback_limit, self.metrics.clone())
613 }
614
615 pub fn set_vsock_device(&mut self, config: VsockDeviceConfig) -> Result<VsockConfigError> {
617 self.vsock.insert(config)
618 }
619
620 pub fn set_gpu_virgl_flags(&mut self, virgl_flags: u32) {
621 self.gpu_virgl_flags = Some(virgl_flags);
622 }
623
624 pub fn set_gpu_shm_size(&mut self, shm_size: usize) {
625 self.gpu_shm_size = Some(shm_size);
626 }
627
628 #[cfg(feature = "snd")]
629 pub fn set_snd_device(&mut self, enabled: bool) {
630 self.snd_device = enabled;
631 }
632
633 pub fn set_console_output(&mut self, console_output: PathBuf) {
634 self.console_output = Some(console_output);
635 }
636
637 #[cfg(feature = "net")]
639 pub fn add_network_interface(
640 &mut self,
641 config: NetworkInterfaceConfig,
642 ) -> Result<NetworkInterfaceError> {
643 self.net.insert(config)
644 }
645
646 #[cfg(feature = "tee")]
647 pub fn tee_config(&self) -> &TeeConfig {
648 &self.tee_config
649 }
650
651 #[cfg(feature = "tee")]
652 pub fn set_tee_config(&mut self, filepath: PathBuf) -> Result<Error> {
653 let file = File::open(filepath.as_path()).map_err(Error::OpenTeeConfig)?;
654 let reader = BufReader::new(file);
655 let tee_config: TeeConfig =
656 serde_json::from_reader(reader).map_err(Error::ParseTeeConfig)?;
657
658 self.set_vm_config(&VmConfig {
660 vcpu_count: Some(tee_config.cpus),
661 mem_size_mib: Some(tee_config.ram_mib),
662 max_vcpu_count: None,
663 max_mem_size_mib: None,
664 ht_enabled: Some(false),
665 cpu_template: None,
666 })
667 .map_err(Error::VmConfig)?;
668
669 self.tee_config = tee_config;
670
671 Ok(())
672 }
673}
674
675#[cfg(all(test, not(target_os = "windows")))]
676mod tests {
677 #[cfg(feature = "gpu")]
678 use crate::resources::DisplayBackendConfig;
679 use crate::resources::VmResources;
680 use crate::vmm_config::machine_config::{CpuFeaturesTemplate, VmConfig, VmConfigError};
681 use crate::vmm_config::vsock::tests::{default_config, TempSockFile};
682 use crate::vstate::VcpuConfig;
683 use utils::tempfile::TempFile;
684
685 fn default_vm_resources() -> VmResources {
686 VmResources::default()
687 }
688
689 #[test]
690 fn test_vcpu_config() {
691 let vm_resources = default_vm_resources();
692 let expected_vcpu_config = VcpuConfig {
693 vcpu_count: vm_resources.vm_config().vcpu_count.unwrap(),
694 max_vcpu_count: vm_resources.vm_config().vcpu_count.unwrap(),
695 ht_enabled: vm_resources.vm_config().ht_enabled.unwrap(),
696 cpu_template: vm_resources.vm_config().cpu_template,
697 };
698
699 let vcpu_config = vm_resources.vcpu_config();
700 assert_eq!(vcpu_config, expected_vcpu_config);
701 }
702
703 #[test]
704 fn test_vm_config() {
705 let vm_resources = default_vm_resources();
706 let expected_vm_cfg = VmConfig::default();
707
708 assert_eq!(vm_resources.vm_config(), &expected_vm_cfg);
709 }
710
711 #[test]
712 fn test_set_vm_config() {
713 let mut vm_resources = default_vm_resources();
714 let mut aux_vm_config = VmConfig {
715 vcpu_count: Some(32),
716 mem_size_mib: Some(512),
717 max_vcpu_count: None,
718 max_mem_size_mib: None,
719 ht_enabled: Some(true),
720 cpu_template: Some(CpuFeaturesTemplate::T2),
721 };
722
723 assert_ne!(vm_resources.vm_config, aux_vm_config);
724 vm_resources.set_vm_config(&aux_vm_config).unwrap();
725 assert_eq!(vm_resources.vm_config, aux_vm_config);
726
727 aux_vm_config.vcpu_count = Some(0);
729 assert_eq!(
730 vm_resources.set_vm_config(&aux_vm_config),
731 Err(VmConfigError::InvalidVcpuCount)
732 );
733 aux_vm_config.vcpu_count = Some(33);
734 assert_eq!(
735 vm_resources.set_vm_config(&aux_vm_config),
736 Err(VmConfigError::InvalidVcpuCount)
737 );
738 aux_vm_config.vcpu_count = Some(32);
739
740 aux_vm_config.mem_size_mib = Some(0);
742 assert_eq!(
743 vm_resources.set_vm_config(&aux_vm_config),
744 Err(VmConfigError::InvalidMemorySize)
745 );
746 }
747
748 #[test]
749 fn test_set_vm_config_max_capacity() {
750 let mut vm_resources = default_vm_resources();
751 let mut vm_config = VmConfig {
752 vcpu_count: Some(2),
753 mem_size_mib: Some(1024),
754 max_vcpu_count: Some(8),
755 max_mem_size_mib: Some(8192),
756 ht_enabled: Some(false),
757 cpu_template: None,
758 };
759
760 vm_resources.set_vm_config(&vm_config).unwrap();
761 let vcpu_config = vm_resources.vcpu_config();
762 assert_eq!(vcpu_config.vcpu_count, 2);
763 assert_eq!(vcpu_config.max_vcpu_count, 8);
764
765 vm_config.max_vcpu_count = None;
767 vm_config.max_mem_size_mib = None;
768 vm_resources.set_vm_config(&vm_config).unwrap();
769 assert_eq!(vm_resources.vcpu_config().max_vcpu_count, 2);
770
771 vm_config.max_vcpu_count = Some(1);
773 assert_eq!(
774 vm_resources.set_vm_config(&vm_config),
775 Err(VmConfigError::InvalidMaxVcpuCount)
776 );
777
778 vm_config.max_vcpu_count = Some(65);
780 assert_eq!(
781 vm_resources.set_vm_config(&vm_config),
782 Err(VmConfigError::InvalidMaxVcpuCount)
783 );
784
785 vm_config.max_vcpu_count = Some(3);
787 vm_config.ht_enabled = Some(true);
788 assert_eq!(
789 vm_resources.set_vm_config(&vm_config),
790 Err(VmConfigError::InvalidMaxVcpuCount)
791 );
792 vm_config.ht_enabled = Some(false);
793
794 vm_config.max_vcpu_count = Some(8);
796 vm_config.max_mem_size_mib = Some(512);
797 assert_eq!(
798 vm_resources.set_vm_config(&vm_config),
799 Err(VmConfigError::InvalidMaxMemorySize)
800 );
801 }
802
803 #[test]
804 fn test_set_vsock_device() {
805 let mut vm_resources = default_vm_resources();
806 let tmp_sock_file = TempSockFile::new(TempFile::new().unwrap());
807 let new_vsock_cfg = default_config(&tmp_sock_file);
808 assert!(vm_resources.vsock.get().is_none());
809 vm_resources
810 .set_vsock_device(new_vsock_cfg.clone())
811 .unwrap();
812 let actual_vsock_cfg = vm_resources.vsock.get().unwrap();
813 assert_eq!(
814 actual_vsock_cfg.lock().unwrap().id(),
815 &new_vsock_cfg.vsock_id
816 );
817 }
818}