Intro

One of the quirks of Vagrants Virtualbox provider is you cannot configure the IP address of the management interface. It's a core design principal of the project that the management interface IP of a box is configured via DHCP. The Virtualbox provider uses port forwarding with a NAT network to communicate between the Host and the guest box, this behaviour cannot be changed.

In a previous post I installed the vagrant-libvirt provider for use with Vagrant. In this post I will cover how to control the IP address assigned to the Vagrant box management interface when using the vagrant-libvirt provider.

You might ask why you would want to do this. Great question. Having a method to predictably assign an IP address to a Vagrant box is useful for a number of scenarios. I find this most relevant when using provisioning tools such as Ansible and Salt to configure VM's once Vagrant has deployed them. This allows me to use the same inventory files I would normally use and not have to monkey around with the Vagrant provisioner config.

Pre-Flight Check

Libvirt comes with a command line tool virsh , we can use this tool to interact and control a hypervisors network, storage etc...

Firstly lets confirm that the vagrant-libvirt network is configured. This is the network that Vagrant VMs will use for their management interfaces.

cmd
virsh net-list --all

# output

Name                 State      Autostart     Persistent
---------------------------------------------------------
default              active     yes           yes
vagrant-libvirt      active     yes           yes

Libvirt network configurations are xml files stored in the /etc/libvirt/<hypervisor>/networks/ directory. Before we make any modifications lets check the current config of the vagrant-libvirt network.

cmd
virsh net-dumpxml vagrant-libvirt

# output

<network ipv6='yes'>
  <name>vagrant-libvirt</name>
  <uuid>589814cf-fdf7-45c8-87bc-707314b9254d</uuid>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <bridge name='virbr1' stp='on' delay='0'/>
  <mac address='52:54:00:0e:6d:db'/>
  <ip address='192.168.121.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.121.1' end='192.168.121.254'/>
    </dhcp>
  </ip>
</network>

You can see above that the IP range for the vagrant-libvirt network is 192.168.121.0/24 and the DHCP range is 192.168.121.1 - 254 . This network is mapped to a virtual interface on the host machine called virbr1 .

It is part of the core design of Vagrant that the management interface of a box gets an IP address via DHCP. This means we cannot directly assign an IP address to the management interface, we can however use some tried and true techniques to ensure a box gets the IP address we intend.

Enter the world of DHCP reservations. We can control the MAC address assigned to a Vagrant box's management interface, then use the same MAC address to reserve an IP address in the DHCP Configuration of the vagrant-libvirt network.

Coming up next I will reserve the IP address; 192.168.121.111 for the MAC address; 52:54:00:00:01:01 in the vagrant-libvirt network.

Define Box MAC Address

In the Vagrantfile define the MAC address for the box's management network with the management_network_mac parameter under the libvirt domain specific configuration.

file
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|

  config.vm.define "spine01" do |node|
    node.vm.hostname = "spine01"
    node.vm.box = "CumulusCommunity/cumulus-vx"
    node.vm.synced_folder ".", "/vagrant", disabled: true

    # Provider-specific configuration
    node.vm.provider :libvirt do |domain|
      domain.management_network_mac = "52:54:00:00:01:01" # Management interface MAC

    end
  end
end

Configure Management IP DHCP Reservation

Use the virsh tool to add a DHCP reservation to the vagrant-libvirt network.

cmd
virsh net-update vagrant-libvirt add-last ip-dhcp-host \
      '<host mac="52:54:00:00:01:01" ip="192.168.121.111"/>' \
      --live --config --parent-index 0

# output

Updated network vagrant-libvirt persistent config and live state

Confirm that the DHCP reservation was added to the vagrant-libvirt network.

cmd
virsh net-dumpxml vagrant-libvirt

# output

<network ipv6='yes'>
  <name>vagrant-libvirt</name>
  <uuid>589814cf-fdf7-45c8-87bc-707314b9254d</uuid>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <bridge name='virbr1' stp='on' delay='0'/>
  <mac address='52:54:00:0e:6d:db'/>
  <ip address='192.168.121.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.121.1' end='192.168.121.254'/>
      <host mac='52:54:00:00:01:01' ip='192.168.121.111'/> # New DHCP reservation

    </dhcp>
  </ip>
</network>

Testing

Use the above Vagrantfile to build a test VM and confirm the intended IP address was assigned.

cmd
vagrant up --provider=libvirt

# output

Bringing machine 'spine01' up with 'libvirt' provider...
==> spine01: Creating image (snapshot of base box volume).
==> spine01: Creating domain with the following settings...
..
<snip>
..
==> spine01: Setting hostname...
==> spine01: Configuring and enabling network interfaces...

Login to the box and confirm the intended IP address was assigned to the management interface.

cmd
vagrant@spine01:~$ sudo net show int eth0

# output

Name    MAC                Speed    MTU    Mode
--  ------  -----------------  -------  -----  ------
UP  eth0    52:54:00:00:01:01
  1G       1500   Mgmt

IP Details
-------------------------  ------------------
IP:                        192.168.121.111/24

IP Neighbor(ARP) Entries:  1

From the host shell we can also see the DHCP reservation in the /var/lib/libvirt/dnsmasq/virbr1.status file.

cmd
cat /var/lib/libvirt/dnsmasq/virbr1.status

# output

[
  {
      "ip-address": "192.168.121.111",
      "mac-address": "52:54:00:00:01:01",
      "hostname": "spine01",
      "expiry-time": 1508917500
  }
]

There you have it, The Vagrant box received the IP address we intended and all is right with the force.

Delete DHCP Reservations

The virsh tool can also be used to delete a DHCP reservation. Generally I dont do this and re-use the same reservations across many Vagrant environments.

cmd
virsh net-update vagrant-libvirt delete ip-dhcp-host \
      '<host mac="52:54:00:00:01:01" ip="192.168.121.111"/>' \
      --live --config --parent-index 0

# output

Updated network vagrant-libvirt persistent config and live state

Outro

Using the libvirt-vagrant provider allows us to predictibly define a box's management IP address. Vagrant is a great tool and using Libvert makes it even greater.