Create network bridge with nmcli for libvirt
Dec 1, 2016 · 6 minute read · Commentsnfvpelinuxnetworkingconsole
In order to get libvirt working properly with bridged networking, we first need to configure our local network to have network bridge slaved to our wired ethernet adapter. I don’t have to set this up too often (as once I do, it just sits there running happily). Here are some basic steps I did to get this going locally.
Add a bridge interface via Network Manager
Before we get to adding a new network interface to libvirt, we’ll add our bridge interface to our host system via Network Manager.
Review starting network configuration
First let’s look at our current network configuration with nmcli
, the Network
Manager command line interface (CLI). You can do this via the Network Manager
applet as well (nm-applet) but in recent versions of Fedora, the CLI works
quite well, and I find a little simpler since we’ll only need to execute a few
commands.
We can see the current state of our network interfaces via nmcli con show
--active
$ nmcli con show --active
NAME UUID TYPE DEVICE
docker0 770d6801-47dc-44a3-9d11-17249f11ef26 bridge docker0
wired-direct 73157bec-12fb-42d0-98c4-f4576742e095 802-3-ethernet enp0s25
Here you can see that I have a connection called wired-direct
which uses the
enp0s25
interface. I also have a docker0
bridge interface which was created
when Docker was installed on my system.
We’re going to convert the libvirt host system (e.g. my laptop) to use a bridge
interface which will get a slave port attached to enp0s25
.
Create bridge interface
Now we’re ready to create our bridge interface, and then create a slave interface and attach it to the ethernet interface. The following set of commands are taken from Fedora Magazine:
$ nmcli con add ifname br0 type bridge con-name br0
Connection 'br0' (892869fe-f8ac-4f17-ace9-b8aeeeee61a0) successfully added.
$ nmcli con add type bridge-slave ifname enp0s25 master br0
Connection 'bridge-slave-enp0s25' (33ee8c62-48d8-4789-97df-604c479b6860)
successfully added.
Let’s also disable STP since we don’t want to wait for this interface to come
up on our network (keep this enabled if you need spanning
tree enabled).
Additional properties that can be adjusted can be shown via nmcli con show
br0
.
$ nmcli con modify br0 bridge.stp no
Enable bridge interface
First let’s review where we’re at.
$ nmcli con show
NAME UUID TYPE DEVICE
docker0 770d6801-47dc-44a3-9d11-17249f11ef26 bridge docker0
wired-direct 73157bec-12fb-42d0-98c4-f4576742e095 802-3-ethernet enp0s25
br0 892869fe-f8ac-4f17-ace9-b8aeeeee61a0 bridge --
bridge-slave-enp0s25 33ee8c62-48d8-4789-97df-604c479b6860 802-3-ethernet --
As you can see in our output, our new bridge interface isn’t active yet. We’ll
first down the wired-direct (enp0s25) interface and then bring the new bridge
interface up. If you look at the output of ip a s
before running the nmcli
commands, you should see your IP address move from the enp0s25
interface to
br0
(it is assumed you’re using DHCP).
$ ip a s
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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: enp0s25: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 54:ee:75:76:50:8e brd ff:ff:ff:ff:ff:ff
inet 192.168.3.160/24 brd 192.168.3.255 scope global dynamic enp0s25
valid_lft 86394sec preferred_lft 86394sec
inet6 fe80::56ee:75ff:fe76:508e/64 scope link
valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:e7:79:09:d0 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 scope global docker0
valid_lft forever preferred_lft forever
7: br0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
OK time to down our enp0s25
interface:
$ nmcli con down wired-direct
Connection 'wired-direct' successfully deactivated (D-Bus active path:
/org/freedesktop/NetworkManager/ActiveConnection/11)
And now we can bring our new bridge up:
$ nmcli con up br0
Connection successfully activated (master waiting for slaves) (D-Bus active
path: /org/freedesktop/NetworkManager/ActiveConnection/12)
I’ve found that periodically the network interfaces won’t come up for whatever reason, and you need to kick the NetworkManager service.
sudo systemctl restart NetworkManager.service
Run nmcli con show
and nmcli con down wired-direct
if you need and then
bring the bridge back online with nmcli con up br0
. Hopefully by this point
your nmcli con show --active
output looks similar to the following:
NAME UUID TYPE DEVICE
br0 892869fe-f8ac-4f17-ace9-b8aeeeee61a0 bridge br0
bridge-slave-enp0s25 33ee8c62-48d8-4789-97df-604c479b6860 802-3-ethernet enp0s25
docker0 bdc99fc1-1e2b-4e28-8309-dd0ae9c80de3 bridge docker0
And our ip a s
output looks like this:
$ ip a s
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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: enp0s25: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br0 state UP group default qlen 1000
link/ether 54:ee:75:76:50:8e brd ff:ff:ff:ff:ff:ff
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:e7:79:09:d0 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 scope global docker0
valid_lft forever preferred_lft forever
7: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 54:ee:75:76:50:8e brd ff:ff:ff:ff:ff:ff
inet 192.168.3.160/24 brd 192.168.3.255 scope global dynamic br0
valid_lft 86211sec preferred_lft 86211sec
inet6 fe80::d813:5274:e201:f3/64 scope link
valid_lft forever preferred_lft forever
Adding bridge networks to libvirt
OK time to add a new network interface to libvirt that will utilize the br0
interface we just created above.
Review starting network configuration
As before, we’ll review what our networking configuration starting point is.
virsh net-list --all
Name State Autostart Persistent
----------------------------------------------------------
default active yes yes
In this case we only have the default NAT networks.
Create network interface
In order to create a new network interface, we need to import the XML configuration from a local file. We can do this by creating a temporary file that we’ll import the configuration in from.
cat > bridge.xml <<EOF
<network>
<name>host-bridge</name>
<forward mode="bridge"/>
<bridge name="br0"/>
</network>
EOF
You’ll notice that we’ve input our local bridge name of br0
and named the
interface host-bridge
. You can name the bridge anything you want, as long as
you don’t use things like spaces and other special characters.
We can create the network with virsh net-define
. If you use virsh
net-create
the network shows up temporarily.
$ virsh net-define bridge.xml
Network host-bridge defined from bridge.xml
Now we can validate our network shows up.
$ virsh net-list --all
Name State Autostart Persistent
----------------------------------------------------------
host-bridge active no yes
Starting the network interface
And now we can start the bridge and mark it to automatically start.
$ virsh net-start host-bridge
Network host-bridge started
$ virsh net-autostart host-bridge
Network host-bridge marked as autostarted
Conclusion
At this point you should be able to create virtual machines and use the bridged interface in order to get those virtual machines directly on your LAN using existing infrastructure instead of going via NAT.
NOTE If you are having issues with using virsh
and virt-manager
from a
non-root user, check out this
post.