169 lines
4.3 KiB
Bash
169 lines
4.3 KiB
Bash
#!/usr/local/bin/bash
|
|
#
|
|
set -euo pipefail
|
|
IFS=$'\n\t'
|
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
|
|
: ${CD:=""}
|
|
: ${VNC_ENABLE:="NO"}
|
|
: ${VNC_LISTEN:="127.0.0.1:5900"}
|
|
: ${PID_FILE:="/var/run/opnsense.pid"}
|
|
|
|
############## Setup #########################
|
|
|
|
function cleanup {
|
|
for vm in "${vms[@]}"; do
|
|
log "Destroying bhyve vm $vm"
|
|
bhyvectl "--vm=$vm" --destroy
|
|
log "Destroyed bhyve vm $vm"
|
|
done
|
|
}
|
|
vms=()
|
|
for sig in EXIT INT QUIT HUP TERM; do
|
|
trap "set +e; sleep 10; cleanup" "$sig"
|
|
done
|
|
|
|
function die {
|
|
local status_code="$1"
|
|
shift
|
|
(>&2 echo "${@}")
|
|
exit "$status_code"
|
|
}
|
|
|
|
function log {
|
|
(>&2 echo "${@}")
|
|
}
|
|
|
|
############## Program #########################
|
|
|
|
function main {
|
|
start_vm
|
|
}
|
|
|
|
function start_vm {
|
|
local name="opnsense"
|
|
|
|
|
|
|
|
# -H release the CPU when guest issues HLT instruction. Otherwise 100% of core will be consumed.
|
|
# -s 3,ahci-cd,/vm/.iso/archlinux-2023.04.01-x86_64.iso \
|
|
# -s 29,fbuf,tcp=0.0.0.0:5900,w=1920,h=1080,wait \
|
|
# -s 29,fbuf,tcp=0.0.0.0:5900,w=1920,h=1080 \
|
|
|
|
# TODO: Look into using nmdm instead of stdio for serial console
|
|
if [ -n "$CD" ]; then
|
|
additional_args+=("-s" "5,ahci-cd,$CD")
|
|
fi
|
|
if [ "$VNC_ENABLE" = "YES" ]; then
|
|
additional_args+=("-s" "29,fbuf,tcp=$VNC_LISTEN,w=1920,h=1080")
|
|
fi
|
|
|
|
local bridge_name="bridge_vm"
|
|
local host_interface_name="bridgeif"
|
|
|
|
assert_bridge "$host_interface_name" "$bridge_name"
|
|
local mac_address
|
|
mac_address=$(calculate_mac_address "$name")
|
|
local bridge_link_name
|
|
bridge_link_name=$(detect_available_link "${bridge_name}")
|
|
additional_args+=("-s" "2:0,virtio-net,netgraph,path=${bridge_name}:,peerhook=${bridge_link_name},mac=${mac_address}")
|
|
vms+=("$name")
|
|
while true; do
|
|
set -x
|
|
set +e
|
|
bhyve \
|
|
-D \
|
|
-c 6 \
|
|
-m 8G \
|
|
-H \
|
|
-s 0,hostbridge \
|
|
-s "4,nvme,/dev/zvol/zroot/vm/opnsense/disk0" \
|
|
-S \
|
|
-s 7,passthru,1/0/0 \
|
|
-s 8,passthru,2/0/0 \
|
|
-s 9,passthru,3/0/0 \
|
|
-s 10,passthru,4/0/0 \
|
|
-s 11,passthru,5/0/0 \
|
|
-s 12,passthru,7/0/0 \
|
|
-s 30,xhci,tablet \
|
|
-s 31,lpc -l com1,stdio \
|
|
-l "bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd,/vm/opnsense/BHYVE_UEFI_VARS.fd" \
|
|
"${additional_args[@]}" \
|
|
"$name"
|
|
# local bhyvepid=$!
|
|
# echo "$bhyvepid" > "$PID_FILE"
|
|
# wait $bhyvepid
|
|
local exit_code=$?
|
|
set +x
|
|
set -e
|
|
if [ $exit_code -eq 0 ]; then
|
|
echo "Rebooting."
|
|
sleep 5
|
|
elif [ $exit_code -eq 1 ]; then
|
|
echo "Powered off."
|
|
break
|
|
elif [ $exit_code -eq 2 ]; then
|
|
echo "Halted."
|
|
break
|
|
elif [ $exit_code -eq 3 ]; then
|
|
echo "Triple fault."
|
|
break
|
|
elif [ $exit_code -eq 4 ]; then
|
|
echo "Exited due to an error."
|
|
break
|
|
fi
|
|
done
|
|
}
|
|
|
|
function ng_exists {
|
|
ngctl status "${1}" >/dev/null 2>&1
|
|
}
|
|
|
|
function assert_bridge {
|
|
local host_interface_name="$1"
|
|
local bridge_name="$2"
|
|
# local ip_range="$3"
|
|
|
|
if ! ng_exists "${bridge_name}:"; then
|
|
ngctl -d -f - <<EOF
|
|
mkpeer . eiface hook ether
|
|
name .:hook $host_interface_name
|
|
EOF
|
|
ngctl -d -f - <<EOF
|
|
mkpeer ${host_interface_name}: bridge ether link0
|
|
name ${host_interface_name}:ether $bridge_name
|
|
EOF
|
|
ifconfig "$(ngctl msg "${host_interface_name}:" getifname | grep Args | cut -d '"' -f 2)" name "${host_interface_name}" up
|
|
|
|
dhclient "${host_interface_name}"
|
|
# (set +e; service netif start wlan0) &
|
|
fi
|
|
}
|
|
|
|
function detect_available_link {
|
|
local bridge_name="$1"
|
|
local linknum=1
|
|
while true; do
|
|
local link_name="link${linknum}"
|
|
if ! ng_exists "${bridge_name}:${link_name}"; then
|
|
echo "$link_name"
|
|
return
|
|
fi
|
|
linknum=$((linknum + 1))
|
|
if [ "$linknum" -gt 90 ]; then
|
|
(>&2 echo "No available links on bridge $bridge_name")
|
|
exit 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
function calculate_mac_address {
|
|
local name="$1"
|
|
local source
|
|
source=$(md5 -r -s "$name" | awk '{print $1}')
|
|
echo "06:${source:0:2}:${source:2:2}:${source:4:2}:${source:6:2}:${source:8:2}"
|
|
}
|
|
|
|
|
|
main "${@}"
|