Ad-hoc router using OpenWrt in a VM
During writing of the last post I actually bricked my home router after installing a custom image. At the same time I didn't manage to get TFTP recovery working [1] so I started searching for ways to restore my home network for now to worry about fixing the router later.
The choice fell on using an ARM board to run OpenWrt, which required some creative workarounds. This post documents them.
What I want to replace:
router-switch combo: 1x WAN, 5x LAN, no WiFi
OS: OpenWrt
What I have:
64-bit ARM SBC, capable of hardware virtualization
USB 3.0 Ethernet adapter (if your SBC has 2x LAN natively that works too)
6-port Ethernet switch
Network setup
eth0
will be the LAN, eth1
the WAN.
The LAN bridge also gets an IP address for management (pick one outside your DHCP pool)
so you can SSH to the host even if the OpenWrt VM is not in operation.
/etc/systemd/network/br0.netdev
:
/etc/systemd/network/br1.netdev
:
/etc/systemd/network/br0.network
:
[Match] Name=br0 [Bridge] MulticastRouter=permanent [Network] Address=192.168.2.254/24 Gateway=192.168.2.1 DNS=192.168.2.1 IPv6AcceptRA=no LinkLocalAddressing=no
/etc/systemd/network/br1.netdev
:
[Match] Name=br1 [Bridge] MulticastRouter=permanent [Network] DHCP=no IPv6AcceptRA=no LinkLocalAddressing=no
/etc/systemd/network/eth0.network
:
/etc/systemd/network/eth1.network
:
Virtual Machine
I had to virtualize OpenWrt because in terms of SBC it supports a few select platforms (eg. Raspberry Pi), but not any I own.
Installation:
cd /root wget "https://downloads.openwrt.org/snapshots/targets/armvirt/64/openwrt-armvirt-64-"{rootfs-ext4.img.gz,Image} gunzip openwrt-armvirt-64-rootfs-ext4.img.gz echo 'allow all' >/etc/qemu/bridge.conf systemctl enable guest.service
/root/run.sh
:
#!/bin/bash cd /root exec qemu-system-aarch64 -enable-kvm -cpu host \ -nographic -M virt,highmem=off -m 128 -smp 4 \ -kernel openwrt-armvirt-64-Image -append "root=fe00" \ -drive file=openwrt-armvirt-64-rootfs-ext4.img,format=raw,if=none,id=hd0 \ -device virtio-blk-pci,drive=hd0 \ -nic bridge,br=br0,model=virtio -nic bridge,br=br1,model=virtio
/etc/systemd/system/guest.service
:
OpenWrt
If the default OpenWrt configuration has address conflicts with the rest of your network, you can adjust it ahead of time like so:
ip l add dev br0 type bridge ip l add dev br1 type bridge ./run.sh # log into openwrt uci set network.eth0.ipaddr=192.168.7.1 uci commit poweroff
Now suppose you want to import the configuration of your old OpenWrt install,
except: it has totally different interface names all over! Not a problem either
as you can rename them by adding the following lines to /etc/rc.local
:
If you did everything right up until this point you can shut down the SBC, plug in all the cables, let it reboot and an OpenWrt router should appear in your network at http://192.168.1.1 just as if it was a real device.
Future thoughts
Setting
net.core.default_qdisc = pfifo_fast
on the host can save some CPU time, not sure whether this breaks QoSIf you have a WiFi USB adapter you could pull it into the VM and enjoy wireless too! See here for an example
When running this setup long term it would make sense to strip down the host OS
The QEMU serial console could be bound to a socket or PTS to interact with it even when
guest.service
is running