Skip to content

Instantly share code, notes, and snippets.

@plembo
Last active April 4, 2025 16:38
Show Gist options
  • Save plembo/a7b69f92953a76ab2d06533754b5e2bb to your computer and use it in GitHub Desktop.
Save plembo/a7b69f92953a76ab2d06533754b5e2bb to your computer and use it in GitHub Desktop.
NetworkManager bridged network for KVM guests

Setting up a bridged network for KVM guests

This will work with either networkd or NetworkManager as a resolver. In fact, this is the only way to do bridged KVM (libvirtd) networking with NetworkManager.

If you're using NetworkManager (on a desktop or laptop, for example) on your KVM host, follow these instructions to set up a bridge interface.

Once you have the host bridge set up, proceed as follows:

  1. Create a bridge network device inside KVM. Edit and save the below text as file host-bridge.xml:
<network>
   <name>host-bridge</name>
   <forward mode="bridge"/>
   <bridge name="br0"/>
</network>

Then execute these commands (as a user in the libvirt group):

$ virsh net-define host-bridge.xml
$ virsh net-start host-bridge
$ virsh net-autostart host-bridge
  1. Make it possible for hosts outside of KVM to talk to your bridged guest by making the following changes on the KVM host.

Load the br_netfilter module:

$ sudo modprobe br_netfilter

Persist on reboot by creating /etc/modules-load.d/br_netfilter.conf:

$ sudo echo "br_netfilter" > /etc/modules-load.d/br_netfilter.conf

Create /etc/sysctl.d/10-bridge.conf:

# Do not filter packets crossing a bridge
net.bridge.bridge-nf-call-ip6tables=0
net.bridge.bridge-nf-call-iptables=0
net.bridge.bridge-nf-call-arptables=0

Apply the config now:

$ sudo sysctl -p /etc/sysctl.d/10-bridge.conf

Check result:

$ sudo sysctl -a | grep "bridge-nf-call"
  1. Configure the guest to use host-bridge. Open up the Virtual Machine Manager and then select the target guest. Go to the NIC device. The drop down for "Network Source" should now include a device called "Virtual netowrk 'host-bridge'". The "Bridge network device model" will be "virtio" if that's your KVM configuration's default.

Select that "host-bridge" device.

If you inspect the guest's XML (by using virsh dumplxml guestname), it shoud look something like this:

<interface type='network'>
   <mac address='52:54:8b:d9:bf:a2'/>
   <source network='host-bridge'/>
   <model type='virtio'/>
   <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>'

Be sure to save your changes!

  1. Go up to your router and add a DHCP reservation and DNS mapping for the guest (assuming you want a dynamic address and want to be able to easily find the guest later). Otherwise, be prepared to manually configure networking on the guest.

  2. Start (or restart) the guest.

@sashablue
Copy link

sashablue commented Mar 24, 2025

And this would be needed for the bridge creation in the first place::

root@minipc-malaga:/etc/netplan# cat 01-netcfg.yaml
# This file describes the network interfaces available on your system
# For more information, see netplan(5).
network:
  version: 2
  renderer: networkd
  ethernets:
    enp2s0:
      dhcp4: no
  bridges:
    br0:
      interfaces: [ enp2s0 ]
      dhcp4: yes
      dhcp6: no
      link-local: [ ]
      parameters:
        stp: true
        forward-delay: 4

@vinzcamp8
Copy link

I needed to do these steps in addition

I followed all the steps but my guest VM still didn't get an IP in the end.

In my case the problem was in the default firewall rules enabled by libvirt on the host. You can check if there are rules for virbr0 and/or libvirt with with sudo iptables -L -v -n.

My setup: ubuntu desktop 22.04.05, libvirtd (libvirt) 8.0.0.


By default, KVM sets up firewall rules for its NAT (virbr0), but since you’re using a bridge (br0), you need to allow traffic explicitly. These are the extra steps I've done:

1. Allow Traffic for br0 in iptables

Try adding the following rules to accept traffic on br0:

sudo iptables -A INPUT -i br0 -j ACCEPT
sudo iptables -A FORWARD -i br0 -j ACCEPT
sudo iptables -A FORWARD -o br0 -j ACCEPT
sudo iptables -A OUTPUT -o br0 -j ACCEPT

This allows all traffic in/out of br0.

2. Enable IP Forwarding (If Needed)

Since virbr0 uses NAT, it might have forwarding already enabled. If not, enable it:

echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward

Make it persistent by editing /etc/sysctl.conf:

sudo nano /etc/sysctl.conf

Uncomment or add:

net.ipv4.ip_forward=1

Apply:

sudo sysctl -p

3. Restart the Network and Verify

sudo systemctl restart NetworkManager
sudo systemctl restart libvirtd

Check the rules:

sudo iptables -L -v -n

4. Verify the VM Network

Inside the VM, check:

ip a

If still no IP, try manually requesting one:

sudo dhclient

Also check and correct your network configurations in /etc/netplan/ to automatically request an IP on the right interface.

5. Make iptables Rules Persistent

If this worked, save the rules:

sudo apt install iptables-persistent -y
sudo netfilter-persistent save

This ensures the rules stay after a reboot.

@plembo
Copy link
Author

plembo commented Apr 4, 2025

Sorry for the late reply. Good advice about checking on and modifying the host's firewall rules as needed. In my case, it wasn't necessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment