1use std::cell::RefCell;
2use std::os::fd::RawFd;
3
4use crate::bootloader::LinuxBootLoader;
5use crate::directory_sharing::VirtioFileSystemDevice;
6use crate::entropy::VirtioEntropyDevice;
7use crate::error::{Result, VzError};
8use crate::memory_balloon::VirtioMemoryBalloonDevice;
9use crate::network::VirtioNetworkDevice;
10use crate::serial::VirtioConsoleSerialPort;
11use crate::socket::VirtioSocketDevice;
12use crate::storage::StorageDevice;
13
14#[derive(Clone)]
15pub(crate) struct ConfigData {
16 pub cpu_count: usize,
17 pub memory_size: u64,
18 pub kernel_path: String,
19 pub initrd_path: Option<String>,
20 pub command_line: String,
21 pub serial_read_fd: Option<RawFd>,
22 pub serial_write_fd: Option<RawFd>,
23 pub disk_path: Option<String>,
24 pub disk_read_only: bool,
25 pub network_fd: Option<RawFd>,
26 pub network_mac: Option<[u8; 6]>,
27 pub has_socket: bool,
28 pub mounts: Vec<(String, String, bool)>, }
30
31pub struct VirtualMachineConfiguration {
32 pub(crate) inner: RefCell<ConfigData>,
33}
34
35impl VirtualMachineConfiguration {
36 pub fn new(boot_loader: &LinuxBootLoader, cpus: usize, memory: u64) -> Self {
37 VirtualMachineConfiguration {
38 inner: RefCell::new(ConfigData {
39 cpu_count: cpus,
40 memory_size: memory,
41 kernel_path: boot_loader.kernel_path.clone(),
42 initrd_path: boot_loader.initrd_path.borrow().clone(),
43 command_line: boot_loader
44 .command_line
45 .borrow()
46 .clone()
47 .unwrap_or_default(),
48 serial_read_fd: None,
49 serial_write_fd: None,
50 disk_path: None,
51 disk_read_only: false,
52 network_fd: None,
53 network_mac: None,
54 has_socket: false,
55 mounts: Vec::new(),
56 }),
57 }
58 }
59
60 pub fn set_cpu_count(&self, cpus: usize) {
61 self.inner.borrow_mut().cpu_count = cpus;
62 }
63
64 pub fn set_memory_size(&self, memory: u64) {
65 self.inner.borrow_mut().memory_size = memory;
66 }
67
68 pub fn set_boot_loader(&self, boot_loader: &LinuxBootLoader) {
69 let mut inner = self.inner.borrow_mut();
70 inner.kernel_path = boot_loader.kernel_path.clone();
71 inner.initrd_path = boot_loader.initrd_path.borrow().clone();
72 if let Some(ref cmdline) = *boot_loader.command_line.borrow() {
73 inner.command_line = cmdline.clone();
74 }
75 }
76
77 pub fn set_serial_ports(&self, ports: &[VirtioConsoleSerialPort]) {
78 if let Some(port) = ports.first() {
79 let mut inner = self.inner.borrow_mut();
80 inner.serial_read_fd = port.read_fd;
81 inner.serial_write_fd = port.write_fd;
82 }
83 }
84
85 pub fn set_storage_devices(&self, devices: &[&dyn StorageDevice]) {
86 if let Some(device) = devices.first() {
87 let mut inner = self.inner.borrow_mut();
88 inner.disk_path = device.get_disk_path().map(|s| s.to_string());
89 inner.disk_read_only = device.get_read_only();
90 }
91 }
92
93 pub fn set_network_devices(&self, devices: &[VirtioNetworkDevice]) {
94 if let Some(device) = devices.first() {
95 let mut inner = self.inner.borrow_mut();
96 inner.network_fd = device.fd;
97 let mac = device.mac_bytes();
98 if mac != [0; 6] {
99 inner.network_mac = Some(mac);
100 }
101 }
102 }
103
104 pub fn set_socket_devices(&self, devices: &[VirtioSocketDevice]) {
105 if !devices.is_empty() {
106 self.inner.borrow_mut().has_socket = true;
107 }
108 }
109
110 pub fn set_directory_sharing_devices(&self, devices: &[VirtioFileSystemDevice]) {
111 let mut inner = self.inner.borrow_mut();
112 for dev in devices {
113 inner
114 .mounts
115 .push((dev.tag.clone(), dev.host_path.clone(), dev.read_only));
116 }
117 }
118
119 pub fn set_entropy_devices(&self, _devices: &[VirtioEntropyDevice]) {
120 }
122
123 pub fn set_memory_balloon_devices(&self, _devices: &[VirtioMemoryBalloonDevice]) {
124 }
126
127 pub fn validate(&self) -> Result<()> {
128 let inner = self.inner.borrow();
129 if inner.kernel_path.is_empty() {
130 return Err(VzError::new("kernel path is required"));
131 }
132 if inner.memory_size == 0 {
133 return Err(VzError::new("memory size must be > 0"));
134 }
135 if inner.cpu_count == 0 {
136 return Err(VzError::new("CPU count must be > 0"));
137 }
138 Ok(())
139 }
140}