I’ve been playing with KVM on Debian 12 as a candidate for moving away from VMware as a hypervisor on my home server. I’ve been testing by using Debian 12 as VM in ESXI set with hardware CPU/MMU enabled, and virtualisaion passthrough enabled.
I’d like the KVM guests to access the network in bridge mode of the host for direct access to the network. However I faced the following issue:
- KVM host can ping gateway and internet.
- KVM host can ping the guest.
- Guest can ping the host.
- Guest cannot ping gateway or anything outside of the host.
- Guest is showing in router ARP table, with its IP address and own MAC
This one got me for more time than I wish to admit, and seems to have caught others out along the way, this is how I finally solved it…
This test setup has the following parameters:
- Network: 10.0.4.0/24
- Internet Gateway: 10.0.4.1
- KVM Host: 10.0.4.100
- GuestL 10.0.4.101
Install KVM and Cockpit
Install KVM and Cockpit (For easy access and testing of a guest):
apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virtinst cockpit cockpit-machines
For Debain 12, Cockpit blocks login from root, remove it from the disallowed-users file:
nano /etc/cockpit/disallowed-users
Restart Cockpit to take changes:
systemctl restart cockpit
Cockpit’s web interface can be accessed via port 9090 of the host IP.
https://10.0.4.100:9090/
Host Network
Now bridge-utils is installed, the bridge can be configured on the host:
nano /etc/network/interfaces
Remove / comment out the physical interface config and add the new bridge br0:
# The loopback network interface
auto lo
iface lo inet loopback
# The primary network interface
allow-hotplug ens192
iface ens192 inet manual
#address 10.0.4.100/24
#gateway 10.0.4.1
# dns-* options are implemented by the resolvconf package, if installed
#dns-nameservers 10.0.4.1
#dns-search debian-kvm.james-batchelor.local
auto br0
iface br0 inet static
address 10.0.4.100
netmask 255.255.255.0
network 10.0.4.0
broadcast 10.0.4.255
gateway 10.0.4.1
bridge_ports ens192
bridge_stp off
bridge_fd 0
bridge_maxwait 0
dns-nameservers 1.1.1.1
hwaddress ether 00:0c:29:3a:bc:72
post-up echo 1 > /proc/sys/net/ipv4/ip_forward
NOTE: Add the hwaddress line and use the mac address of the physical interface, otherwise you’ll loose connection to the host when networking is restarted.
NOTE: For my solution, IP forwarding needs to be enabled.
Restart networking service, cross your fingers:
systemctl restart networking
Guest setup
Create folders for the guests:
mkdir /vm
mkdir /vm/iso
mkdir /vm/datastore
This issue got me for a while, so for testing I refined the process down to using a System Rescue cd for quick VM spin ups. Download the ISO:
wget https://fastly-cdn.system-rescue.org/releases/11.01/systemrescue-11.01-amd64.iso -P /vm/iso/
Now create the VM from the CLI:
virt-install --name vm-test --ram=8192 --vcpu=4 --cpu host-passthrough --disk path=/vm/datastore/vm-test,size=8 --cdrom /vm/iso/systemrescue-11.01-amd64.iso --os-variant linux2022 --network bridge=br0,model=virtio --graphics vnc
Now you can move to Cockpit to view and configure the guest from its console.
Guest Networking
Lets take a second to think about whats happening when a guest pings the network; It has to leave through the host in order to get to the gateway, as the ARP table has has the correct details for the guest (including guest’s actual MAC), the ping reply will be send to the guest but needs to go through the host first.
Therefore a static route is needed to steer traffic for the guest through the host. On the router, create a static route:
Via Cockpit, access the console of the System Rescue OS, enter the network config via:
nmtui
Navigate to edit a connection, and select the Wired Ethernet Connection, set IPv4 configuration to Manual and add the details:
- IP address: IP address you set as the destination of the static route.
- Gateway: IP address of host.
Select OK at the bottom of the screen to confirm config, go back to the main menu.
TIP: Navigate to Activate Connections and toggle the interface off and back on, as otherwise there is a lag before the config is applied to the network.
Test with pings from the guest and to it from other machines, they should now respond.