Skip to main content

Setup KVM bridge networking on Ubuntu server

KVM provides NAT based networking to enable guest operating systems to get connectivity to the outside world. The guests sharing the same bridge are however able to communicate to each other even if no physical connection is made on the physical interface of the host. This default configuration makes it easy to get started with KVM without a lot of configuration.

NAT as the default config is convenient but has some short comings. Read more

  • NAT used private IP addresses, this makes it difficult to use public IP addresses or your own custom IP addresses.
  • Guest operating systems are not visible outside the host operating system. This means you cannot directly access a guest virtual machine if you are outside the host.
  • Network throughput and latency performance is affected.

Install KVM

sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils

Replace default bridge

We are going to replace the default KVM bridge configuration. KVM installs a virtual bridge that all the guest VMs connect to and provides its own subnet and DHCP to configure the guest’s network and uses NAT to access the outside world. We will configure a public bridge that runs on the host network and uses an external DHCP server that is on the host network.

Disable default networking

Use ip link command to view the default network configuration

needle@needle:~$ 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 54:be:79:f3:1d:5a 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:44:10:1d:5b:20 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:44:10:1d:5b:20 brd ff:ff:ff:ff:ff:ff

KVM installs virbr0 and virbr0-nic by default.

Use the commands below to remove the default KVM network:

virsh net-destroy default
virsh net-undefine default

If you run ip link again and the virbr0 and virbr0-nic are deleted.

needle@needle:~$ 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

Setup custom bridge

We will edit the /etc/netplan/00-installer-config.yaml file to
add a bridge. Below is an example after edit:

network:
  ethernets:
    enp0s1:
     dhcp4: false
     dhcp6: false
  bridges:
    br0:
     interfaces: [ enp0s1 ]
     addresses: [10.10.0.5/24]
     gateway4: 10.10.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

enp0s1 is my NIC’s name.
My host has been assigned an IP address 10.10.0.5/24 with the gateway as 10.10.0.1. The gateway is my router.
br0 is the bridge and it is attached to enp0s1 which is my physical networking card (NIC). The bridge will now handle all the networking and not the physical interface, in this case enp0s1.

Run sudo netplan apply command to apply the configuration. If you now run the ip link command you will see something like this:

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: enp0s1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel
master br0 state UP group default qlen 1000
link/ether 30:1d:52:ac:a9:65 brd ff:ff:ff:ff:ff:ff
10: 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 10.10.0.5/24 brd 10.10.0.255 scope global br0
valid_lft forever preferred_lft forever
inet6 fe50::25d:71ff:feac:d985/64 scope link
valid_lft forever preferred_lft forever

br0 has the IP address and enp0s1 belongs to the bridge br0.

Set bridge to KVM

Create a file and named main-bridge.xml like below:

<network>
 <name>host-bridge</name>
  <forward mode="bridge"/>
 <bridge name="br0"/>
</network>

Make the bridge default for VMs run the following commands:

virsh net-define main-bridge.xml
virsh net-start main-bridge
virsh net-autostart main-bridge

Check the bridge setup for KVM, run this command:

virsh net-list --all

You should see something like this:

needle@needle:~$ virsh net-list --all
Name State Autostart Persistent
------------------------------------------------
main-bridge active yes yes

The bridge is setup and is set to autostart when the host boots.