114 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			114 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/bin/bash
 | |
| OVMF_PATH="/var/lib/detee/boot/0346619257269b9a61ee003e197d521b8e2283483070d163a34940d6a1d40d76";
 | |
| 
 | |
| [[ -z "$VM_UUID" ]] && {
 | |
|   echo "Environment variable VM_UUID is not set."
 | |
|   exit 1
 | |
| }
 | |
| source "/etc/detee/daemon/vms/${VM_UUID}.sh"
 | |
| 
 | |
| mandatory_vars=("KERNEL" "INITRD" "PARAMS" "CPU_TYPE" \
 | |
|   "VCPUS" "MEMORY" "MAX_MEMORY" "DISK")
 | |
| for var in "${mandatory_vars[@]}"; do
 | |
|   if [ -z "${!var}" ]; then
 | |
|     echo "Environment variable $var is not set."
 | |
|     exit 1
 | |
|   fi
 | |
| done
 | |
| 
 | |
| add_nft_rules() {
 | |
|   local nic_index="$1" ifname="$2" vtap_addr="$3" ipv4_addr="" ipv6_addr=""
 | |
| 
 | |
|   nft add table netdev deteemacvtap
 | |
|   nft add chain netdev deteemacvtap ${ifname}_in "{ type filter hook ingress device ${ifname} priority 0; policy accept; }"
 | |
|   nft add chain netdev deteemacvtap ${ifname}_ou "{ type filter hook egress device ${ifname} priority 0; policy accept; }"
 | |
|   # return if the rules already exist
 | |
|   nft list chain netdev deteemacvtap ${ifname}_in | grep ether && return 0
 | |
|   nft add rule netdev deteemacvtap ${ifname}_in ether type arp accept
 | |
|   nft add rule netdev deteemacvtap ${ifname}_in ether daddr != ${vtap_addr} drop
 | |
|   nft list chain netdev deteemacvtap ${ifname}_ou | grep ether && return 0
 | |
|   nft add rule netdev deteemacvtap ${ifname}_ou ether saddr != ${vtap_addr} drop
 | |
| 
 | |
|   # TODO: This will handle only one IP per VM. If you add multiple IPs, fix this.
 | |
|   # Also, we wish you good luck. We know this code is complicated. We tried, ok?
 | |
|   ipv4_addr=$(echo $PARAMS | grep -m 1 -oP "detee_net_eth${nic_index}=[0-9]{1,3}\.[0-9a-f\.]+" | cut -d "=" -f2 )
 | |
|   ipv6_addr=$(echo $PARAMS | grep -m 1 -oP "detee_net_eth${nic_index}=[0-9a-f]{1,4}\:[0-9a-f\:]+" | cut -d "=" -f2 )
 | |
| 
 | |
|   [[ -n "$ipv4_addr" ]] && {
 | |
|     nft add rule netdev deteemacvtap ${ifname}_in ip daddr != $ipv4_addr drop
 | |
|     nft add rule netdev deteemacvtap ${ifname}_ou ip saddr != $ipv4_addr drop
 | |
|   } || {
 | |
|     nft add rule netdev deteemacvtap ${ifname}_in ip version 4 drop
 | |
|     nft add rule netdev deteemacvtap ${ifname}_ou ip version 4 drop
 | |
|   }
 | |
| 
 | |
|   [[ -n "$ipv6_addr" ]] && {
 | |
|     nft add rule netdev deteemacvtap ${ifname}_in ip6 daddr != $ipv6_addr drop
 | |
|     nft add rule netdev deteemacvtap ${ifname}_ou ip6 saddr != $ipv6_addr drop
 | |
|   } || {
 | |
|     nft add rule netdev deteemacvtap ${ifname}_in ip6 version 6 drop
 | |
|     nft add rule netdev deteemacvtap ${ifname}_ou ip6 version 6 drop
 | |
|   }
 | |
| 
 | |
| }
 | |
| 
 | |
| interfaces=$(env | sort | grep -oE '^NETWORK_INTERFACE_[0-9]*')
 | |
| nat_configured="false"
 | |
| nic_count=0
 | |
| qemu_device_params=""
 | |
| while read -r interface; do
 | |
| 
 | |
|   interface_type="$( echo ${!interface} | cut -d '_' -f1 )"
 | |
| 
 | |
|   if [[ "$interface_type" == "macvtap" || "$interface_type" == "ipvtap" ]]; then
 | |
|     interface_device="$( echo ${!interface} | cut -d '_' -f2 )"
 | |
|     interface_name="$( echo ${!interface} | cut -d '_' -f3 )"
 | |
|     [[ "$interface_type" == "macvtap" ]] && {
 | |
|       ip link add link $interface_device name $interface_name type $interface_type mode bridge
 | |
|     } || { 
 | |
|       ip link add link $interface_device name $interface_name type $interface_type mode l3
 | |
|     }
 | |
|     sysctl -w net.ipv6.conf.$interface_name.accept_ra=0
 | |
|     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)"
 | |
| 
 | |
|     [[ "$interface_type" == "macvtap" ]] && add_nft_rules $nic_count $interface_name $vtap_addr
 | |
| 
 | |
|     exec {fd_number}<> /dev/tap${vtap_index}
 | |
|     qemu_device_params+=" -netdev tap,id=hostnet${nic_count},fd=${fd_number}"
 | |
|     qemu_device_params+=" -device virtio-net-pci,netdev=hostnet${nic_count},mac=${vtap_addr},romfile="
 | |
|   fi
 | |
| 
 | |
|   if [[ "$interface_type" == "NAT" && "$nat_configured" == "false" ]]; then 
 | |
|     ports=""
 | |
|     nat_configured="true"
 | |
|     for port_pair in $NAT_PORT_FW; do
 | |
|       host_port="$( echo $port_pair | cut -d ':' -f1 )"
 | |
|       guest_port="$( echo $port_pair | cut -d ':' -f2 )"
 | |
|       ports+=",hostfwd=tcp::${host_port}-:${guest_port},hostfwd=udp::${host_port}-:${guest_port}"
 | |
|     done
 | |
|     qemu_device_params+=" -netdev user,id=natnic${ports}"
 | |
|     qemu_device_params+=" -device virtio-net-pci,netdev=natnic,romfile="
 | |
|   fi
 | |
| 
 | |
|   # TODO: also handle bridge device (when IPs are public, but the host is the gateway)
 | |
| 
 | |
|   ((nic_count++))
 | |
| done <<< "$( echo "$interfaces" )"
 | |
| 
 | |
| 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 \
 | |
|     -no-reboot -bios "$OVMF_PATH" \
 | |
|     -drive file=${DISK},if=none,id=disk0,format=qcow2 \
 | |
|     -device virtio-blk-pci,drive=disk0 \
 | |
|     -object memory-backend-memfd,id=ram1,size=$MEMORY,share=true,prealloc=false \
 | |
|     -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,kernel-hashes=on \
 | |
|     -kernel $KERNEL -append "$PARAMS" -initrd $INITRD \
 | |
|     -nographic
 |