Setting up a network bridge - Qrivi/KVM GitHub Wiki

Creating a network bridge in Linux that can be passed as a network interface controller (NIC) to a guest VM allows that VM to be in the same network as the host with minimum configuration required. This means that the guest OS will get its IP address from the home router/DHCP server and will be able to interact with other devices that are in the same network, such as network printers or network speakers.

While not strictly necessary, the first thing one can do is disable Predictable Network Interface Names that ship with systemd. This will make it so the ethernet interface will be eth0 again, which is fine on consumer grade motherboards that do not have multiple ethernet interfaces.

sudo ln -s /dev/null /etc/systemd/network/99-default.link
sudo systemctl restart NetworkManager.service # Not sure if this is enough -- if not: just reboot

ip a should now list your ethernet adapter as eth0. E.g.:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:8c:62:44 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.2/24 brd 192.168.121.255 scope global dynamic eth0
       valid_lft 2900sec preferred_lft 2900sec
    inet6 fe80::5054:ff:fe8c:6244/64 scope link
       valid_lft forever preferred_lft forever

I used netctl instead of NetworkManager, which came with Manjaro, to set up the bridge. However, I believe it should/might be perfectly possible to do so with NetworkManager too — I just haven't looked into this. To avoid conflicts, stop NetworkManager first, then install netctl.

sudo systemctl stop NetworkManager.service
sudo pacman -Sy netctl

To define a new network bridge, create its configuration file in /etc/netctl and give it a sensible name, such as bridge or kvm-bridge. You will need sudo to create and edit this file.

sudo nano /etc/netctl/bridge

Below is a basic bridge configuration that should suffice for most use-cases. More exotic bridge configurations are beyond the scope of this guide. Make sure BindsToInterface is set to your ethernet interface (which is eth0 if Predictable Network Interface Names is disabled) and Interface "makes sense" (by convention it should start with br).

Description="Bridge Connection for KVM"
Interface=br0
Connection=bridge
BindsToInterfaces=(eth0)
IP=dhcp

Once defined, we can enable and start the bridge. The last argument passed to the netctl commands is the file name of the bridge configuration we created in the previous step.

sudo netctl enable bridge
sudo netctl start bridge

To allow QEMU to use this bridge, append allow br0, where br0 is your bridge's name, to QEMU's bridge configuration file. If this configuration file does not exist yet, create it.

sudo nano /etc/qemu/bridge.conf

In order to have both host and guest(s) be able to connect over ethernet, the ethernet adapter needs to be replaced with the bridge, then bind the ethernet adapter to the bridge. This can be done with bridge-utils.

sudo pacman -Sy bridge-utils

Fist we'll enable IPv4 forwarding and make it permanent.

sudo -s
sysctl net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward = 1" > /etc/sysctl.d/99-sysctl.conf

Then we'll load the tun module and configure it to be loaded at boot time.

sudo -s
modprobe tun
echo "tun" > /etc/modules-load.d/tun.conf

To have the bridge behave properly when QEMU starts a guest VM, we need to create a qemu-ifup and qemu-ifdown script in /etc. We'll copy them from the scripts folder. For these scripts to work, we need to fix their owner, group and permissions.

sudo cp ~/KVM/scripts/qemu-ifup /etc
sudo chown root:kvm /etc/qemu-ifup
sudo chmod 750 /etc/qemu-ifup

sudo cp ~/KVM/scripts/qemu-ifdown /etc
sudo chown root:kvm /etc/qemu-ifdown
sudo chmod 750 /etc/qemu-ifdown

And we have to update the sudoers file so they can be run without prompting for the root password.

sudo EDITOR=nano visudo

Append the following to the sudoers file:

%kvm       ALL=NOPASSWD: /usr/bin/ip,/usr/bin/modprobe,/usr/bin/brctl

To avoid performance hickups or security conflicts, it is recommended to disable the firewall on the bridge in its configuration file. If this configuration file does not exist yet, create it.

sudo nano /etc/sysctl.d/10-disable-firewall-on-bridge.conf

Append the following to the configuration file:

net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-call-arptables = 0

For the firewall configuration to be picked up correctly, the br_netfilter module needs to be loaded. First we'll enable the filter, then we'll make it permanent.

sudo -s
modprobe br_netfilter
cat /etc/modules-load.d/br_netfilter.conf
# Only if cat does not output "br_netfilter", add it. Must not be defined twice.
echo "br_netfilter" > /etc/modules-load.d/br_netfilter.conf

In order to immediatly apply the updated configuration, we can reload the configuration file.

sudo sysctl -p /etc/sysctl.d/10-disable-firewall-on-bridge.conf

Great! The bridge is now set up and will put guests on the same network as the host, given the bridge is passed through as the guest's NIC. Both the host and the guest should be able to connect to the network (and the internet) simultaneously and ip a should now reflect the changes made to eth0 and br0.

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br0 state UP group default qlen 1000
    link/ether 1c:1b:0d:ed:39:57 brd ff:ff:ff:ff:ff:ff
3: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 1c:1b:0d:ed:39:57 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.2/24 brd 192.168.0.255 scope global noprefixroute br0
       valid_lft forever preferred_lft forever
    inet6 fe80::1e1b:dff:feed:3957/64 scope link
       valid_lft forever preferred_lft forever
⚠️ **GitHub.com Fallback** ⚠️