A routed network is usually only used when a Bridged network is unavailable, either due to hosting provider restrictions or because the libvirt server is connected wirelessly to the LAN. Virtual machines (VMs) have their own IP addresses, but do not bind directly to them. Instead, packets destined for those addresses are statically routed to the libvirt server and forwarded to VMs (without using NAT).
Unfortunately, libvirt’s built-in routed network automatically inserts iptables rules whether you want them or not, in an order that is difficult to control. If you would rather be in full control and prevent libvirt from interfering, create a Custom routed network instead.
On a dedicated server, a routed network is only possible when there are enough IP addresses to allocate one per VM. This is not a problem for IPv6, as hosting providers usually provide many free IPv6 addresses. However, extra IPv4 addresses are rarely free. If you only have one public IPv4 address (and need to serve clients over IPv4), either buy more IPv4 addresses or create a NAT-based network.
In this example:
- The server has an Ethernet device called
- VMs bind to a virtual bridge called
virbr1, which is created by libvirt.
- The hosting provider has allocated two address blocks (see CIDR notation):
- one public IPv4 address block (
- one public IPv6 address block (
- one public IPv4 address block (
- The server binds statically to
To begin, choose which IP addresses to make available to VMs. In this example, a
subnet of six IPv4 addresses (
203.0.113.88/29) will be sliced from the
allocated address block and made available to VMs. In an Intranet or home lab,
you might choose a whole
/24 subnet (eg,
For IPv6, always use a
/64 subnet prefix to avoid breaking various IPv6
features. In this example,
2001:db8::/56 can be sliced into 256 different
/64 subnets, one of which (
2001:db8:aa::/64) will be made available to
VMs. (Most hosting providers allocate a
/64 block for every server, and
should allocate a free
/56 on request.)
Configure static routes¶
The LAN router is unaware that the subnets chosen above are located on the libvirt server, so network packets can only reach VMs if you configure static routes on the LAN router. In this example, two static routes are required:
ip -4 route add 203.0.113.88/29 via 203.0.113.86
ip -6 route add 2001:db8:aa::/64 via 2001:db8::1
For a dedicated server, ask your hosting provider to configure these routes for you. For an Intranet or home lab, consult the documentation for your router.
If the router in your home lab is consumer-grade, it might have buggy support for static routes or it might not allow static routes at all. If possible, install alternative firmware such as OpenWRT or Merlin. (A painful last resort is to add static routes to every client on the LAN.)
Configure the virtual network¶
/tmp/mynetwork1.xml with the following contents. If only a single
protocol version is required, omit either the IPv4 or IPv6
(Optionally, use DHCP host entries to always assign the same IP
address to a particular VM.)
<network> <name>mynetwork1</name> <bridge name="virbr1" /> <forward mode="route"/> <ip address="203.0.113.88" netmask="255.255.255.248"> <dhcp> <range start="203.0.113.89" end="203.0.113.94"/> </dhcp> </ip> <ip family="ipv6" address="2001:db8:aa::1" prefix="64"/> </network>
IPv6 addresses are allocated via stateless address autoconfiguration (SLAAC).
Alternatively, you may want to allocate IPv6 addresses via DHCPv6 instead, in
which case add a
<dhcp> element with a range of addresses to offer to VMs:
<network> <name>mynetwork1</name> <bridge name="virbr1" /> <forward mode="route"/> <ip address="203.0.113.88" netmask="255.255.255.248"> <dhcp> <range start="203.0.113.89" end="203.0.113.94"/> </dhcp> </ip> <ip family="ipv6" address="2001:db8:aa::1" prefix="64"> <dhcp> <range start="2001:db8:aa::1000" end="2001:db8:aa::1fff"/> </dhcp> </ip> </network>
/tmp/mynetwork1.xml to define a new network.
# virsh net-define /tmp/mynetwork1.xml # virsh net-autostart mynetwork1 # virsh net-start mynetwork1
Multiple virtual networks
You can create as many routed networks as required. Simply choose a different
name for the network (eg,
mynetwork2), a different name for the virtual
virbr2), and a different range of IP addresses. Also see
Configure virtual machines¶
# virt-install --network network=mynetwork1 ...
--network more than once to create additional virtual Ethernet
interfaces for the VM.
# virt-install --network network=mynetwork1 --network network=mynetwork2 ...
Open the XML configuration for the VM in a text editor.
# virsh edit name-of-vm
There should already be an
<interface> section that configures a virtual
Ethernet interface for the VM. Note down the MAC address.
<interface type="network"> <source network="default"/> <mac address="52:54:00:4f:47:f2"/> </interface>
To reconfigure the virtual Ethernet interface, replace the
section with the following contents. Use the MAC address noted above, otherwise
the MAC address of the VM will change.
<interface type="network"> <source network="mynetwork1"/> <mac address="52:54:00:4f:47:f2"/> </interface>
To add an additional virtual Ethernet interface, append a new
section. libvirt generates a random MAC for the new interface if
<interface type="network"> <source network="mynetwork1"/> </interface>
Reboot the VM to apply the changes. You may need to amend the VM’s network initialization scripts to account for the network interface changes.