Bridged networking with KVM
When using a bridge, the vm’s shares the physical nic of the host. This way virtual machines can receive an ip in my lan with dhcp. I prefer my vm’s to have a LAN address, instead of the default nat networking.
In addition, when running docker on the same machine, the br_netfilter enabled by Docker, will break the default nat networking used by virsh.
Prerequisites
I’m using Ubuntu 24.04 and this might work on most distro’s using systemd. Check if bridge-utils
is installed, otherwise:
apt install bridge-utils
Configure the bridge
Before using the bridge, i only configured the enp2s0
interface with fixed ip 192.168.0.10. When using the bridge, this ip wil bind to the bridge, and be removed from the Interface enp2s0
.
Backup your netplan setting and create a new configuration in /etc/netplan/bridge.yaml
. Make sure to adjust the interface names and ip according your setup.
!!! errors in netplan configuration may make you lose access: Be very careful!
1 network:
2 version: 2
3 ethernets:
4 eno1:
5 dhcp4: true
6 activation-mode: off # i do not use the second nic
7 enp2s0:
8 dhcp4: true
9 bridges:
10 br0:
11 dhcp4: false
12 addresses:
13 - 192.168.0.10/24
14 nameservers:
15 addresses:
16 - 127.0.0.1
17 - 1.1.1.1
18 gateway4: 192.168.0.1
19 interfaces:
20 - enp2s0
Apply the configuration: netplan apply
If you still have connection, you should be able to examine the bridge.
$ brctl show br0
bridge name bridge id STP enabled interfaces
br0 8000.02973c1d2848 no enp2s0
Configure the virtual network
To let the vm’s utilise the bridge, we create a new network configuration. Adjust the variables if your bridge is named different. Since im using the default network, it probaly exist already and might need to be undifened with virsh undefine default
.
You can also choose for an uniq network name and let the default as is. In that case make sure you assign the prefered network when creating a new vm.
Create the virsh network xml template with command below:
# set variables:
BR=br0
NET_NAME=default
# create template:
echo "<network>
<name>$NET_NAME</name>
<forward mode=\"bridge\"/>
<bridge name=\"$BR\"/>
</network>" > $BR.xml
Create the network based on template made in previous step, start the network and enable auto start.
virsh net-define $BR.xml
virsh net-start $NET_NAME
virsh net-autostart $NET_NAME
Show result: virsh net-list --all
Disable netfilters for bridges.
To bypass the Docker bridge netfilter code, we disable netfilter for bridges by creating this file in /etc/sysctl.d/netfilter-bridge.conf
. Activate the setting with sysctl -p /etc/sysctl.d/netfilter-bridge.conf
net.bridge.bridge-nf-call-ip6tables=0
net.bridge.bridge-nf-call-iptables=0
net.bridge.bridge-nf-call-arptables=0
Allow forwarding for bridges
This step is optional. It is only necessary if your vm’s doesnt get on dhcp ip.
If your vm’s wont get a dhcp ip, it might be that iptables are still not forwarding. Use the following command to allow traffic forwarding to the bridge:
iptables -I FORWARD -m physdev --physdev-is-bridged -j ACCEPT
Waiting for networkd service on boot
Since a new interface is added, the bridge, it might happen that systemd service systemd-networkd-wait-online.service
will wait on boot for all nic'
s to be connected. This will not happen and makes boot times needlessly long. To prevent create this file in /etc/systemd/system/systemd-networkd-wait-online.service.d/override.conf
with the following content.
[Service]
ExecStart=
ExecStart=/usr/lib/systemd/systemd-networkd-wait-online --any
Read more
Some very clear and interesting explanation is written on this great libvirt Networking Handbook], if you like to investiage other networking options with libvirt.