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