Debian 12: KVM Guest using Bridged Network

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.