From 82273f63e5a6d755505e62978ba75b7735b2f977 Mon Sep 17 00:00:00 2001 From: ghe0 Date: Fri, 13 Dec 2024 03:10:03 +0200 Subject: [PATCH] VM works on SNP server --- Cargo.lock | 2 +- Cargo.toml | 2 +- scripts/start_qemu_vm.sh | 20 ++++++++++++---- src/constants.rs | 2 +- src/main.rs | 27 ++++----------------- src/state.rs | 52 ++++++++++++++++++++++++++-------------- 6 files changed, 57 insertions(+), 48 deletions(-) mode change 100644 => 100755 scripts/start_qemu_vm.sh diff --git a/Cargo.lock b/Cargo.lock index 5510198..70b78cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -149,7 +149,7 @@ dependencies = [ ] [[package]] -name = "daemon" +name = "detee-snp-daemon" version = "0.1.0" dependencies = [ "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 525f80a..c916286 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "daemon" +name = "detee-snp-daemon" version = "0.1.0" edition = "2021" diff --git a/scripts/start_qemu_vm.sh b/scripts/start_qemu_vm.sh old mode 100644 new mode 100755 index 29bece9..46c0d38 --- a/scripts/start_qemu_vm.sh +++ b/scripts/start_qemu_vm.sh @@ -1,6 +1,6 @@ #!/bin/bash -[[ -z "$VM_UUID" ]] || { +[[ -z "$VM_UUID" ]] && { echo "Environment variable VM_UUID is not set." exit 1 } @@ -17,6 +17,7 @@ done interfaces=$(env | grep -oE '^NETWORK_INTERFACE_[0-9]*') nat_configured="false" +vtap_fd_counter=3 while read -r interface; do interface_type="$( echo ${!interface} | cut -d '_' -f1 )" @@ -24,13 +25,21 @@ while read -r interface; do if [[ "$interface_type" == "macvtap" || "$interface_type" == "ipvtap" ]]; then interface_device="$( echo ${!interface} | cut -d '_' -f2 )" interface_name="$( echo ${!interface} | cut -d '_' -f3 )" - ip link add link $interface_device name $interface_name type $interface_type mode bridge + if [[ "$interface_type" == "macvtap" ]]; then + ip link add link $interface_device name $interface_name type $interface_type mode bridge + else + ip link add link $interface_device name $interface_name type $interface_type + fi ip link set $interface_name up ip link set $interface_name promisc on + vtap_index="$(cat /sys/class/net/${interface_name}/ifindex)" vtap_addr="$(cat /sys/class/net/${interface_name}/address)" - qemu_device_params="-netdev tap,id=hostnet1,fd=3 3<>/dev/tap${macvtap_index}" - qemu_device_params+=" -device virtio-net-pci,netdev=hostnet1,mac=${macvtap_addr},romfile=" + + fd_number=$vtap_fd_counter + exec {fd_number}<> /dev/tap${vtap_index} + qemu_device_params="-netdev tap,id=hostnet1,fd=${fd_number} -device virtio-net-pci,netdev=hostnet1,mac=${vtap_addr},romfile=" + ((vtap_fd_counter++)) fi if [[ "$interface_type" == "NAT" && "$nat_configured" == "false" ]]; then @@ -54,7 +63,8 @@ vm_disk="/root/dtrfs/arch-1-ghe0.qcow2" qemu-system-x86_64 $qemu_device_params \ -enable-kvm -cpu $CPU_TYPE -vga none \ -machine q35,confidential-guest-support=sev0,memory-backend=ram1 \ - -smp $VCPUS,maxcpus=$VCPUS -m $MEMORY,slots=5,maxmem=$MAX_MEMORY \ + -smp $VCPUS,maxcpus=$VCPUS \ + -m $MEMORY,slots=5,maxmem=$MAX_MEMORY \ -no-reboot -bios /usr/share/edk2/ovmf/OVMF.amdsev.fd \ -drive file=${DISK},if=none,id=disk0,format=qcow2 \ -device virtio-blk-pci,drive=disk0 \ diff --git a/src/constants.rs b/src/constants.rs index 1810165..b73eca0 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -3,7 +3,7 @@ pub(crate) const DEFAULT_OVMF: &str = "/usr/share/edk2/ovmf/OVMF.amdsev.fd"; pub(crate) const VM_BOOT_DIR: &str = "/var/lib/detee/boot/"; pub(crate) const VM_CONFIG_DIR: &str = "/etc/detee/daemon/vms/"; -pub(crate) const DAEMON_CONFIG_PATH: &str = "/etc/detee/daemon/config.json"; +pub(crate) const DAEMON_CONFIG_PATH: &str = "/etc/detee/daemon/config.yaml"; pub(crate) const START_VM_SCRIPT: &str = "/usr/local/bin/detee/start_qemu_vm.sh"; // TODO: research if other CPU types provide better performance pub(crate) const QEMU_VM_CPU_TYPE: &str = "EPYC-v4"; diff --git a/src/main.rs b/src/main.rs index 7cf7cda..fb99b10 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,29 +7,12 @@ use crate::config::Config; use crate::state::NewVMRequest; fn main() -> Result<(), Box> { - let config = Config::from_file("prod_setting/config1.yaml")?; + let args: Vec = std::env::args().collect(); + let config = Config::from_file(crate::constants::DAEMON_CONFIG_PATH)?; let mut res = state::Resources::new(&config.volumes); - // println!("{:#?}", config); - - // let config = Config::from_file("test_data/config2.yaml")?; - // println!("{:#?}", config); - // let config = Config::from_file("test_data/config3.yaml")?; - // println!("{:#?}", config); - // let config = Config::from_file("test_data/config4.yaml")?; - // println!("{:#?}", config); - // let config = Config::from_file("test_data/config5.yaml")?; - // println!("{:#?}", config); - let new_vm_req = NewVMRequest::from_file("test_data/new_vm_req3.yaml")?; - // println!("{:#?}", new_vm_req); - - // let new_vm_req = NewVMRequest::from_file("test_data/new_vm_req2.yaml")?; - // println!("{:#?}", new_vm_req); - // let new_vm_req = NewVMRequest::from_file("test_data/new_vm_req3.yaml")?; - // println!("{:#?}", new_vm_req); - // let new_vm_req = NewVMRequest::from_file("test_data/new_vm_req4.yaml")?; - // println!("{:#?}", new_vm_req); + let new_vm_req = NewVMRequest::from_file(&args[1])?; let vm = state::VM::new(new_vm_req, &config, &mut res); - println!("vm: {:#?}", vm); - println!("{:?}", vm.unwrap().start()); + println!("Got VM: {:#?}", vm); + println!("Starting VM... \n{:?}", vm.unwrap().start()); Ok(()) } diff --git a/src/state.rs b/src/state.rs index 46ddc2e..7ac7ee4 100644 --- a/src/state.rs +++ b/src/state.rs @@ -38,7 +38,7 @@ impl Resources { available_gb: config_vol.max_reservation_gb, }); } - Resources { + let mut res = Resources { reserved_vcpus: 0, reserved_memory: 0, reserved_ports: HashSet::new(), @@ -46,7 +46,9 @@ impl Resources { reserved_ips: HashSet::new(), reserved_if_names: HashSet::new(), boot_files: HashSet::new(), - } + }; + res.scan_boot_files().unwrap(); + res } fn available_storage_pool(&mut self, required_gb: usize) -> Option { @@ -319,9 +321,7 @@ pub struct VM { // currently hardcoded to EPYC-v4 // cpu_type: String, vcpus: usize, - // memory in MB memory_mb: usize, - // disk size in GB disk_size_gb: usize, kernel_sha: String, dtrfs_sha: String, @@ -510,7 +510,7 @@ impl VM { for nic in self.nics.iter() { for ip in nic.ips.iter() { ip_string += &format!( - "detee_net_eth{}={}_{}_{}", + "detee_net_eth{}={}_{}_{} ", i, ip.address, ip.mask, ip.gateway ); } @@ -527,12 +527,14 @@ impl VM { let mut i = 0; for nic in self.nics.iter() { let mut interface = String::new(); - interface += &format!("NETWORK_INTERFACE_{}={}", i, nic.if_config.if_type()); + interface += &format!(r#"export NETWORK_INTERFACE_{}="{}"#, i, nic.if_config.if_type()); // device is currently ignored in case of NAT cause we assume QEMU userspace NAT if let Some(vtap_name) = nic.if_config.vtap_name() { interface += &format!("_{}_{}", nic.if_config.device_name(), vtap_name); } - vars += &format!("{}\n", interface); + interface += r#"""#; + vars += &format!(r#"{}"#, interface); + vars += "\n"; i += 1; } @@ -541,17 +543,32 @@ impl VM { ports += &format!("{}:{} ", port.0, port.1); } if ports != "" { - vars += &format!("NAT_PORT_FW={}", ports.trim_end()); + vars += &format!(r#"NAT_PORT_FW="{}""#, ports.trim_end()); + vars += "\n"; } - vars += &format!("KERNEL={}\n", VM_BOOT_DIR.to_string() + &self.kernel_sha); - vars += &format!("INITRD={}\n", VM_BOOT_DIR.to_string() + &self.dtrfs_sha); - vars += &format!("PARAMS={}\n", self.kernel_params()); - vars += &format!("CPU_TYPE={}\n", QEMU_VM_CPU_TYPE); - vars += &format!("VCPUS={}\n", self.vcpus); - vars += &format!("MEMORY={}MB\n", self.memory_mb); - vars += &format!("MAX_MEMORY={}MB\n", self.memory_mb + 256); - vars += &format!("DISK={}\n", self.disk_path()); + vars += &format!( + r#"export KERNEL="{}""#, + VM_BOOT_DIR.to_string() + &self.kernel_sha + ); + vars += "\n"; + vars += &format!( + r#"export INITRD="{}""#, + VM_BOOT_DIR.to_string() + &self.dtrfs_sha + ); + vars += "\n"; + vars += &format!(r#"export PARAMS="{}""#, self.kernel_params()); + vars += "\n"; + vars += &format!(r#"export CPU_TYPE="{}""#, QEMU_VM_CPU_TYPE); + vars += "\n"; + vars += &format!(r#"export VCPUS="{}""#, self.vcpus); + vars += "\n"; + vars += &format!(r#"export MEMORY="{}M""#, self.memory_mb); + vars += "\n"; + vars += &format!(r#"export MAX_MEMORY="{}M""#, self.memory_mb + 256); + vars += "\n"; + vars += &format!(r#"export DISK="{}""#, self.disk_path()); + vars += "\n"; let mut file = File::create(VM_CONFIG_DIR.to_string() + &self.uuid)?; file.write_all(vars.as_bytes())?; @@ -600,8 +617,7 @@ impl VM { contents += &format!("[Install]\n"); contents += &format!("WantedBy=multi-user.target\n"); - let mut file = - File::create("/tmp/etc/systemd/system/".to_string() + &self.uuid + ".service")?; + let mut file = File::create("/etc/systemd/system/".to_string() + &self.uuid + ".service")?; file.write_all(contents.as_bytes())?; Ok(()) }