From 1927a6597a834f3f0dcc7d5c71c5425bc18905de Mon Sep 17 00:00:00 2001 From: redxef Date: Wed, 29 Sep 2021 16:19:05 +0200 Subject: [PATCH] Add another launch option compatible with multiple vms. --- .editorconfig | 26 ++++++++++++ .gitignore | 4 ++ base.conf.tmpl | 12 ++++++ default.conf.tmpl | 4 ++ default.sh | 6 +++ hardware.conf.tmpl | 6 +++ hardware.sh | 6 +++ net | 101 +++++++++++++++++++++++++++++++++++++++++++++ pre-start.sh | 6 +++ start | 98 +++++++++++++++++++++++++++++++++++++++++++ vfio_devices.txt | 4 ++ win10.conf.tmpl | 5 +++ win10.sh | 4 ++ 13 files changed, 282 insertions(+) create mode 100644 .editorconfig create mode 100644 base.conf.tmpl create mode 100644 default.conf.tmpl create mode 100755 default.sh create mode 100644 hardware.conf.tmpl create mode 100755 hardware.sh create mode 100755 net create mode 100755 pre-start.sh create mode 100755 start create mode 100644 vfio_devices.txt create mode 100644 win10.conf.tmpl create mode 100755 win10.sh diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..ab88bfa --- /dev/null +++ b/.editorconfig @@ -0,0 +1,26 @@ +root = true + +[**] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true +max_line_length = 72 + +[{**.c}] +indent_size = 8 + +[{Makefile,makefile,**.mk,makefile**,Makefile**}] +indent_style = tab +indent_size = 2 + +[{**.py,**.rb,**.bash,**.sh,**.ksh}] +indent_size = 4 + +[{**.css}] +indent_size = 2 + +[{**.json,**.yaml,**.Dockerfile}] +indent_size = 2 diff --git a/.gitignore b/.gitignore index e170ac1..41f481e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ *.iso *.rom +default.conf +base.conf +hardware.conf +win10.conf diff --git a/base.conf.tmpl b/base.conf.tmpl new file mode 100644 index 0000000..b661521 --- /dev/null +++ b/base.conf.tmpl @@ -0,0 +1,12 @@ +-boot order=dc +-machine type=q35,accel=kvm,kernel_irqchip=on +-smp 10,sockets=1,cores=5,threads=2 +-enable-kvm +-cpu host,kvm=on,topoext,tsc_deadline,tsc_adjust,l3-cache,hv_vendor_id=null,hv_vpindex,hv_runtime,hv_synic,hv_stimer,hv_reset,hv_frequencies,hv_tlbflush,hv_reenlightenment,hv_ipi,hv_time,hv_relaxed,hv_vapic,hv_spinlocks=0x1fff +-m 12G +-mem-prealloc -mem-path /dev/hugepages +-vga none -nographic +-parallel none +-serial none +-rtc clock=host,base=localtime,driftfix=none +-usb diff --git a/default.conf.tmpl b/default.conf.tmpl new file mode 100644 index 0000000..cb92a99 --- /dev/null +++ b/default.conf.tmpl @@ -0,0 +1,4 @@ +-netdev tap,id=net0,br=$BR_NAME,ifname=$TAP_NAME,script=no,downscript=no +-device e1000,netdev=net0 +-audiodev pa,id=snd0,server=unix:/run/user/$MYUID/pulse/native +-device intel-hda -device hda-duplex,audiodev=snd0 diff --git a/default.sh b/default.sh new file mode 100755 index 0000000..53584c7 --- /dev/null +++ b/default.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +source <(sudo cat "$NET_CONF_FILE") +export BR_NAME="$bridge_name" +export TAP_NAME="$tap_name" +export MYUID="$(id -u)" diff --git a/hardware.conf.tmpl b/hardware.conf.tmpl new file mode 100644 index 0000000..1ad559c --- /dev/null +++ b/hardware.conf.tmpl @@ -0,0 +1,6 @@ +-device usb-host,hostbus=1,hostport=6.1 +-device usb-host,hostbus=1,hostport=6.2 +-device usb-host,hostbus=1,hostport=6.3 +-device usb-host,hostbus=1,hostport=6.4 +-device vfio-pci,host=$GPU_ID,multifunction=on,id=gpu,romfile=$GPU_ROM +-device vfio-pci,host=$AUDIO_ID,id=audio diff --git a/hardware.sh b/hardware.sh new file mode 100755 index 0000000..73ef72f --- /dev/null +++ b/hardware.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +export GPU_ROM=/opt/vm/1080ti_asus.rom +export GPU_ID='0000:65:00.0' +export AUDIO_ID='0000:65:00.1' + diff --git a/net b/net new file mode 100755 index 0000000..2ec058c --- /dev/null +++ b/net @@ -0,0 +1,101 @@ +#!/usr/bin/env bash + + +set -euo pipefail + +BASE_BRIDGE_NAME=br-q +BASE_TAP_NAME=tap-q + +randstr() { + dd if=/dev/urandom count=1 bs=4 | xxd -p -g 0 +} + +default_route() { + ip route | grep '^default' | sed -n 's/.*dev \([^ ]*\).*/\1/p' +} + +find_next_subnet() { + local i + for i in {20..254}; do + if ip route | grep -q "^172\.$i\."; then + true + else + break + fi + done + echo "172.$i" +} + +create() { + local next_subnet + + local bridge_name + local dhcp_subnet + local dhcp_range + local tap_name + local dnsmasq_pid + + next_subnet="$(find_next_subnet)" + dhcp_subnet="$next_subnet.0.1/16" + dhcp_range="$next_subnet.0.2,$next_subnet.255.254" + + bridge_name="$BASE_BRIDGE_NAME-$(randstr)" + tap_name="$BASE_TAP_NAME-$(randstr)" + + echo > "$NET_CONF_FILE" + + ip link add name "$bridge_name" type bridge + echo "bridge_name='$bridge_name'" >> "$NET_CONF_FILE" + ip addr add "$dhcp_subnet" dev "$bridge_name" + ip link set dev "$bridge_name" up + ip tuntap add "$tap_name" mode tap + echo "tap_name='$tap_name'" >> "$NET_CONF_FILE" + ip link set "$tap_name" up + ip link set dev "$tap_name" master "$bridge_name" + dnsmasq -k --interface="$bridge_name" --bind-interface \ + --dhcp-range="$dhcp_range" & + dnsmasq_pid="$!" + echo "dnsmasq_pid='$dnsmasq_pid'" >> "$NET_CONF_FILE" + disown -h "$dnsmasq_pid" + + echo "nft_ruleset='$(nft -s list ruleset)'" >> "$NET_CONF_FILE" + + # dhcp + nft add rule ip filter INPUT udp dport 67 accept + nft add rule ip filter INPUT tcp dport 67 accept + # dns + nft add rule ip filter INPUT udp dport 53 accept + nft add rule ip filter INPUT tcp dport 53 accept + + # forward bridge + nft add rule ip filter FORWARD iifname "$bridge_name" \ + counter packets 0 bytes 0 accept + nft add rule ip filter FORWARD oifname "$bridge_name" \ + counter packets 0 bytes 0 accept + nft add rule ip nat POSTROUTING oifname "$(default_route)" \ + counter masquerade +} + +delete() { + source "$NET_CONF_FILE" + + kill "$dnsmasq_pid" + ip link del "$tap_name" + ip link del "$bridge_name" + nft flush ruleset + nft -f - <<< "$nft_ruleset" + rm "$NET_CONF_FILE" +} + +if [[ -z "$NET_CONF_FILE" ]]; then + echo Please specify the configuration file path \ + with NET_CONF_FILE >&2 + exit 1 +fi + +if [[ "EUID" -ne 0 ]]; then + echo "Please run as root" >&2 + exit 2 +fi + +"$@" diff --git a/pre-start.sh b/pre-start.sh new file mode 100755 index 0000000..b899e2c --- /dev/null +++ b/pre-start.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +if [[ -z "$DEBUG" ]]; then + echo efi-framebuffer.0 | sudo tee \ + '/sys/bus/platform/devices/efi-framebuffer.0/driver/unbind' || true +fi diff --git a/start b/start new file mode 100755 index 0000000..6780340 --- /dev/null +++ b/start @@ -0,0 +1,98 @@ +#!/usr/bin/env bash + +set -eo pipefail + +if [[ -z "$VMNAME" ]]; then + echo "VMNAME not specified, aborting" >&2 + exit 1 +fi + +if [[ -z "$DEBUG" ]]; then + DEBUG= +fi + +set -u + +SUDO=sudo + +$SUDO true + +NET_CONF_FILE="$(sudo mktemp)" + +# create bridge +NET_CONF_FILE="$NET_CONF_FILE" $DEBUG $SUDO --preserve-env=NET_CONF_FILE \ + ./net create + +# rebind devices +for device in $(< vfio_devices.txt); do + $DEBUG $SUDO ./pci vfio_rebind_device "$device" +done + +# efi variables +EFI_VARS="$(mktemp)" +cp /usr/share/ovmf/x64/OVMF_VARS.fd "$EFI_VARS" +EFI_FIRMWARE=/usr/share/ovmf/x64/OVMF_CODE.fd + +base_path=base +default_path=default +hardware_path=hardware +specific_path="$VMNAME" +if [[ -e "$base_path.conf.tmpl" ]]; then + ( + # shellcheck disable=SC1090 + [[ -e "$base_path.sh" ]] && source "$base_path.sh" + envsubst < "$base_path.conf.tmpl" > "$base_path.conf" + ) +fi +if [[ -e "$default_path.conf.tmpl" ]]; then + ( + # shellcheck disable=SC1090 + [[ -e "$default_path.sh" ]] && source "$default_path.sh" + envsubst < "$default_path.conf.tmpl" > "$default_path.conf" + ) +fi +if [[ -e "$hardware_path.conf.tmpl" ]]; then + ( + # shellcheck disable=SC1090 + [[ -e "$hardware_path.sh" ]] && source "$hardware_path.sh" + envsubst < "$hardware_path.conf.tmpl" > "$hardware_path.conf" + ) +fi +if [[ -e "$specific_path.conf.tmpl" ]]; then + ( + # shellcheck disable=SC1090 + [[ -e "$specific_path.sh" ]] && source "$specific_path.sh" + envsubst < "$specific_path.conf.tmpl" > "$specific_path.conf" + ) +fi + +if [[ -e "pre-start.sh" ]]; then + ./pre-start.sh +fi + +if [[ -e "pre-start-$VMNAME.sh" ]]; then + ./"pre-start-$VMNAME.sh" +fi + +# run qemu +base_arguments=() +default_arguments=() +hardware_arguments=() +specific_arguments=() +# mask EOF +read -ra base_arguments -d '' < "$base_path.conf" || true +read -ra default_arguments -d '' < "$default_path.conf" || true +read -ra hardware_arguments -d '' < "$hardware_path.conf" || true +read -ra specific_arguments -d '' < "$specific_path.conf" || true +$DEBUG $SUDO nice --adjustment=-20 taskset --cpu-list '1-5,7-11' \ + qemu-system-x86_64 \ + -name "$VMNAME,process=VMNAME" \ + -drive if=pflash,format=raw,readonly=on,file="$EFI_FIRMWARE" \ + -drive if=pflash,format=raw,file="$EFI_VARS" \ + "${base_arguments[@]}" \ + "${default_arguments[@]}" \ + "${hardware_arguments[@]}" \ + "${specific_arguments[@]}" + +NET_CONF_FILE="$NET_CONF_FILE" $DEBUG $SUDO --preserve-env=NET_CONF_FILE \ + ./net delete diff --git a/vfio_devices.txt b/vfio_devices.txt new file mode 100644 index 0000000..4be96e3 --- /dev/null +++ b/vfio_devices.txt @@ -0,0 +1,4 @@ +0000:02:00.0 +0000:07:00.0 +0000:65:00.0 +0000:65:00.1 diff --git a/win10.conf.tmpl b/win10.conf.tmpl new file mode 100644 index 0000000..19436c5 --- /dev/null +++ b/win10.conf.tmpl @@ -0,0 +1,5 @@ +-drive file=virtio-win-0.1.185.iso,media=cdrom +-drive file=Win10_21H1_EnglishInternational_x64.iso,media=cdrom +-device vfio-pci,host=$SSD_ID,id=sdd +-device vfio-pci,host=$SATA_ID,id=sata + diff --git a/win10.sh b/win10.sh new file mode 100755 index 0000000..cba15cb --- /dev/null +++ b/win10.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +export SSD_ID='0000:02:00.0' +export SATA_ID='0000:07:00.0'