diff --git a/ansible/roles/bhyve/files/bhyve_netgraph_bridge.bash b/ansible/roles/bhyve/files/bhyve_netgraph_bridge.bash index 14aa9df..b95e55a 100644 --- a/ansible/roles/bhyve/files/bhyve_netgraph_bridge.bash +++ b/ansible/roles/bhyve/files/bhyve_netgraph_bridge.bash @@ -74,13 +74,6 @@ function main { fi } -function die { - local status_code="$1" - shift - (>&2 echo "${@}") - exit "$status_code" -} - function create_disk { local zfs_path="$1" local mount_path="$2" diff --git a/router/launch_opnsense.bash b/router/launch_opnsense.bash new file mode 100644 index 0000000..5d95444 --- /dev/null +++ b/router/launch_opnsense.bash @@ -0,0 +1,167 @@ +#!/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="bridge_if" + + 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 - <&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 "${@}" diff --git a/router/opnsense_rc.bash b/router/opnsense_rc.bash new file mode 100644 index 0000000..753c3ba --- /dev/null +++ b/router/opnsense_rc.bash @@ -0,0 +1,46 @@ +#!/bin/sh +# +# REQUIRE: LOGIN +# PROVIDE: opnsense + +. /etc/rc.subr +name=opnsense +rcvar=${name}_enable +start_cmd="${name}_start" +stop_cmd="${name}_stop" +status_cmd="${name}_status" +load_rc_config $name + +tmux_name="opnsense" + +opnsense_start() { + # /usr/local/bin/tmux new-session -d -s "$tmux_name" "/usr/bin/env VNC_ENABLE=YES VNC_LISTEN=0.0.0.0:5900 /usr/local/bin/bash /home/talexander/launch_opnsense.bash" + /usr/local/bin/tmux new-session -d -s "$tmux_name" "/usr/bin/env VNC_ENABLE=NO VNC_LISTEN=0.0.0.0:5900 /usr/local/bin/bash /home/talexander/launch_opnsense.bash" +} + +opnsense_status() { + if /usr/local/bin/tmux has-session -t $tmux_name 2>/dev/null; then + echo "$tmux_name is running." + else + echo "$tmux_name is not running." + return 1 + fi +} + +opnsense_stop() { + /usr/local/bin/tmux has-session -t $tmux_name 2>/dev/null && ( + /usr/local/bin/tmux kill-session -t $tmux_name + sleep 10 + bhyvectl --vm=opnsense --destroy + # kill `cat /var/run/opnsense.pid` + ) + opnsense_wait_for_end +} + +opnsense_wait_for_end() { + while /usr/local/bin/tmux has-session -t $tmux_name 2>dev/null; do + sleep 1 + done +} + +run_rc_command "$1"