Skip to main content

vm_ch/
configuration.rs

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)>, // (tag, host_path, read_only)
29}
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        // Entropy device is a no-op on KVM — /dev/urandom is available.
121    }
122
123    pub fn set_memory_balloon_devices(&self, _devices: &[VirtioMemoryBalloonDevice]) {
124        // Memory balloon is not yet implemented for KVM.
125    }
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}