Skip to content

Instantly share code, notes, and snippets.

@jpeletier
Last active December 10, 2022 13:34
Show Gist options
  • Save jpeletier/b1c2bf2a1cc7523e77484680d5aeca02 to your computer and use it in GitHub Desktop.
Save jpeletier/b1c2bf2a1cc7523e77484680d5aeca02 to your computer and use it in GitHub Desktop.
How to configure public bridge for KVM
Copied from: https://levelup.gitconnected.com/how-to-setup-bridge-networking-with-kvm-on-ubuntu-20-04-9c560b3e3991
Other source: https://ostechnix.com/install-and-configure-kvm-in-ubuntu-20-04-headless-server/
The default networking that KVM provides is a private bridge that uses NAT to allow the guest VMs to talk to the outside world. This works for a lot of use-cases and is probably the best default setup. But sometimes I need the VMs to share the network with the host. In many of my past articles that created VMs, I’ve been able to get away with the default networking. But a future project I’m working on will need VMs operating on the host network, so I wanted to document how to do that here.
There are a lot of articles on setting up a public bridge; it seems like a popular topic. But many of the articles are old and don’t use the latest networking configuration software available with Ubuntu or they manage networking and KVM with a GUI interface. I will be using only command-line tools, as I don’t actually have monitors for my servers.
So here is my take on setting up KVM to use a public bridge by default. To follow along, you should have good knowledge of Linux, KVM, and modern Linux networking. We will be using Ubuntu 20.04 which uses the iproute2 package for command-line access, and netplan for configuration. Ubuntu 20.04 was released in April 2020 (hence the version number 20.04) but I have been using the daily builds since the beginning of the year to get familiar with it.
First, I’m going to install KVM, the virtual machine manager. For Ubuntu 20.04 The installation is easy:
sudo apt-get install qemu-kvm libvirt-daemon-system \
libvirt-clients virtinst bridge-utils
Test that it’s working with virsh list --all this should show you an empty listing, but a listing none-the-less:
rkamradt@artful:~$ virsh list --all
Id Name State
--------------------
The next thing we’re going to do is replace the default bridging. As mentioned above, KVM installs a virtual bridge that all the VMs connect to. It provides its own subnet and DHCP to configure the guest’s network and uses NAT to access the outside world. We’re going to replace that with a public bridge that runs on the host network and uses whatever external DHCP server is on the host network.
For performance reasons, it is recommended to disable netfilter on bridges in the host. To do that, create a file called /etc/sysctl.d/bridge.conf and fill it in with this:
net.bridge.bridge-nf-call-ip6tables=0
net.bridge.bridge-nf-call-iptables=0
net.bridge.bridge-nf-call-arptables=0
Then create a file called /etc/udev/rules.d/99-bridge.rules and add this line:
ACTION=="add", SUBSYSTEM=="module", KERNEL=="br_netfilter", RUN+="/sbin/sysctl -p /etc/sysctl.d/bridge.conf"
That should all be on one line. That will set the flags to disable netfilter on bridges at the proper place in system start-up. Reboot to take effect.
Next, we need to disable the default networking that KVM installed for itself. You can use ip to see what the default network looks like:
rkamradt@beast:~$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether d4:be:d9:f3:1e:5f brd ff:ff:ff:ff:ff:ff
6: virbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether 52:54:00:1d:5b:25 brd ff:ff:ff:ff:ff:ff
7: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc fq_codel master virbr0 state DOWN mode DEFAULT group default qlen 1000
link/ether 52:54:00:1d:5b:25 brd ff:ff:ff:ff:ff:ff
The entries virbr0 and virbr0-nic are what KVM installs by default.
Because this host just had KVM installed, I don’t have to worry about existing VMs. If you have existing VMs, you will have to edit them to use the new network setup. It’s possible you can have both public and private VMs, but I’d just as soon have only one type of network per host to avoid confusion. Here’s how to remove the default KVM network:
virsh net-destroy default
virsh net-undefine default
Now you can run ip again and the virbr0 and virbr0-nic should be gone.
rkamradt@beast:~$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether d4:be:d9:f3:1e:5f brd ff:ff:ff:ff:ff:ff
If they are not, you can remove them with ip link delete virbr0 type brigde and ip link delete virbr0-nic.
Next, we will need to set up a bridge to use when we create a VM. Edit your /etc/netplan/00-installer-config.yaml (after making a back-up) to add a bridge. This is what mine looks like after editing:
network:
ethernets:
enp0s7:
dhcp4: false
dhcp6: false
bridges:
br0:
interfaces: [ enp0s7 ]
addresses: [192.168.0.104/24]
gateway4: 192.168.0.1
mtu: 1500
nameservers:
addresses: [8.8.8.8,8.8.4.4]
parameters:
stp: true
forward-delay: 4
dhcp4: no
dhcp6: no
version: 2
In my case enp0s7 is the name of my NIC, 192.168.0.104 is the IP address of my host, and192.168.0.1 is my home router. I’ve set up my home router to reserve 192.168.0.104 for this host by associating the MAC address to the IP address. The bridge br0 is attached to the enp0s7 interface, the physical network card on the host. Notice that the enp0s7 interface is not configured, the bridge now has the network configuration that used to be specified in the enp0s7 section. I’m not sure about the parameters section, I copied them straight from an example setup and I may want to play with them later.
Now run sudo netplan apply to apply your new configuration. You can use the ip command to inspect that it looks correct:
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: enp0s7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br0 state UP group default qlen 1000
link/ether 00:1d:72:ac:d9:95 brd ff:ff:ff:ff:ff:ff
13: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:1d:72:ac:d9:95 brd ff:ff:ff:ff:ff:ff
inet 192.168.0.104/24 brd 192.168.0.255 scope global br0
valid_lft forever preferred_lft forever
inet6 fe80::21d:72ff:feac:d995/64 scope link
valid_lft forever preferred_lft forever
Note that the br0 entry now has the IP address and the enp0s7 entry now has master br0 to show that it belongs to the bridge.
Now we can make KVM aware of this bridge. create a scratch XML file called host-bridge.xml and insert the following:
<network>
<name>host-bridge</name>
<forward mode="bridge"/>
<bridge name="br0"/>
</network>
Use the following commands to make that our default bridge for VMs:
virsh net-define host-bridge.xml
virsh net-start host-bridge
virsh net-autostart host-bridge
And then list the networks to confirm it is set to autostart:
rkamradt@artful:~$ virsh net-list --all
Name State Autostart Persistent
------------------------------------------------
host-bridge active yes yes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment