Recently I converted from using the Virtualbox provider for Vagrant to using the Libvirt provider. This post will cover how to create a Cisco csr1000v Vagrant box for use with the vagrant-libvirt provider.

For reference the following software will be used in this post.

  • Cisco csr1000v - 3.15.00.S.155-2.S
  • Vagrant - Vagrant 1.9.6
  • vagrant-libvirt - 0.4.0
  • Ubuntu - 1604


Cisco does not provide a Vagrant Libvirt box, but they do provide a qcow2 image. You will need to download the qcow2 from the Cisco software download section.

Search for csr1000v and download csr1000v-universalk9.03.15.00.S.155-2.S-std.qcow2 .

A CCO account is required to download the software but its free to register and no support contract is required.


Create and change into directory for csr1000v files. I like to keep my custom vagrant boxes under ~/vagrant/boxes/ .

mkdir -p ~/vagrant/boxes/cisco/csr1kv
cd ~/vagrant/boxes/cisco/csr1kv

Copy the qcow2 file downloaded earlier to the ~/vagrant/boxes/cisco/csr1kv directory.

cp ~/Downloads/csr1000v-universalk9.03.15.00.S.155-2.S-std.qcow2 .

The maintainers of the vagrant-libvirt plugin have a script that can be used to convert qcow2 images to a vagrant box. Download the libvirt conversion script.

curl -O

Now lets build the csr1000v VM and apply a bootstrap configuration.

virt-install \
    --connect=qemu:///system \
    --name=csr1000v \
    --os-type=linux \
    --os-variant=rhel4 \
    --arch=x86_64 \
    --cpu host \
    --vcpus=1 \
    --hvm \
    --ram=4096 \
    --disk path=csr1000v-universalk9.03.15.00.S.155-2.S-std.qcow2,bus=ide,format=qcow2 \
    --network=network:vagrant-libvirt,model=virtio \

A virtual terminal will open that can be used to configure the VM, as far as I am aware you cannot copy and past into this terminal so it is not very convenient. Once the VM is booted configure the VM to use the serial port instead of the virtual console.

conf t
platform console serial
copy system:running-config nvram:startup-config

When the VM reboots, conenct via the console port and apply the bootstrap configuration.

virsh console csr1000v

Once connected apply the bootstrap configuration.

conf t
hostname csr
ip domain-name lab.local
crypto key generate rsa modulus 2048
ip ssh version 2
aaa new-model
aaa authentication login default local
aaa authorization exec default local
username vagrant privilege 15 secret vagrant
ip ssh pubkey-chain
  username vagrant
    key-hash ssh-rsa DD3BB82E850406E9ABFFA80AC0046ED6
interface GigabitEthernet1
  description vagrant-management
  ip address dhcp
  no shutdown
wr mem

Check the IP address assigned to interface GigabitEthernet1.

show ip int brie

# output

Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet1 YES DHCP   up                    up

To exit the console use one of these key combinations (Assuming English keyboard).

  • CTRL + ]
  • CTRL + 5
  • Press and hold CTRL and SHIFT while pressing 6 then ]

Now confirm that it is possible to SSH to the VM with the insecure_private_key .

# from host shell

ssh vagrant@ -i ~/.vagrant.d/insecure_private_key

# now logged into guest csr


If you can successfully SSH to the csr1000v with the insecure_private_key its time to package the VM into a Vagrant box. First shutdown the VM.

virsh shutdown csr1000v

# output

Domain csr1000v is being shutdown

Create a metadata.json file with the following contents.


Use the previously downloaded script to make a Vagrant box from the qcow2 image.

bash csr1000v-universalk9.03.15.00.S.155-2.S-std.qcow2

# output

==> Creating box, tarring and gzipping
Total bytes written: 1369313280 (1.3GiB, 33MiB/s)
==> created
==> You can now add the box:
==>   'vagrant box add --name csr1000v-universalk9.03.15.00.S.155-2.S-std'

Create a metadata file called csr1kv.json so that the box is added with the correct version number.

  "name": "cisco/csr1000v",
  "description": "Cisco csr1000v",
  "versions": [
      "version": "03.15.00.S-155-2-S",
      "providers": [
          "name": "libvirt",
          "url": "file:///home/bradmin/vagrant/boxes/cisco/csr1kv/"

Add the box to Vagrant using the csr1kv.json file.

vagrant box add csr1kv.json

# output

==> box: Loading metadata for box 'csr1kv.json'
    box: URL: file:///home/bradmin/vagrant/boxes/cisco/csr1kv.json
==> box: Adding box 'cisco/csr1000v' (v03.15.00.S-155-2-S) for provider: libvirt
    box: Unpacking necessary files from: file:///home/bradmin/vagrant/boxes/cisco/
==> box: Successfully added box 'cisco/csr1000v' (v03.15.00.S-155-2-S) for 'libvirt'!

Confirm the csr1000v box was added successfully.

vagrant box list

# output

CumulusCommunity/cumulus-vx          (libvirt, 3.4.2)
CumulusCommunity/cumulus-vx          (libvirt, 3.4.3)
CumulusCommunity/cumulus-vx          (virtualbox, 3.4.1)
arista/veos                          (libvirt, 4.18.1F)
arista/veos                          (virtualbox, 4.16.9M)
arista/veos                          (virtualbox, 4.17.5M)
arista/veos                          (virtualbox, 4.18.1F)
centos/7                             (libvirt, 1708.01)
centos/7                             (virtualbox, 1705.02)
cisco/asav                           (virtualbox, 9.8.1)
cisco/csr1000v                       (libvirt, 03.15.00.S-155-2-S)

cisco/csr1000v                       (virtualbox, 03.15.00)


Use this Vagrantfile to test out the new csr1000v Vagrant box.

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

Vagrant.configure("2") do |config| = "cisco/csr1000v"

  # Turn off shared folders
  config.vm.synced_folder ".", "/vagrant", disabled: true

  # Do not try to insert new SSH key
  config.ssh.insert_key = false

  # Give VM time to boot
  config.vm.boot_timeout = 180

  # Set guest type to prevent guest type detection
  config.vm.guest = :freebsd

  # Provider-specific configuration
  config.vm.provider :libvirt do |domain|
    domain.nic_adapter_count = 8
    domain.memory = 4096
    domain.cpus = 2
    domain.driver = "kvm"

I found that the VM will crash on boot if the config.vm.guest parameter is not configured. It looks like Vagrant tries to determine the guest OS type for use with post build provisioning tasks. Since we will not be performing any of that, statically configuring the value to something looks to disable the OS detection step.


Ok, with that all said and done lets vagrant up

vagrant up

# output

Bringing machine 'default' up with 'libvirt' provider...
==> default: Creating image (snapshot of base box volume).
==> default: Creating domain with the following settings...
==> default:  -- Name:              cisco-test_default
==> default:  -- Domain type:       kvm
==> default:  -- Cpus:              2
==> default:  -- Feature:           acpi
==> default:  -- Feature:           apic
==> default:  -- Feature:           pae
==> default:  -- Memory:            4096M
==> default:  -- Management MAC:
==> default:  -- Loader:
==> default:  -- Base box:          cisco/csr1000v
==> default:  -- Storage pool:      default
==> default:  -- Image:             /var/lib/libvirt/images/cisco-test_default.img (8G)
==> default:  -- Volume Cache:      default
==> default:  -- Kernel:
==> default:  -- Initrd:
==> default:  -- Graphics Type:     vnc
==> default:  -- Graphics Port:     5900
==> default:  -- Graphics IP:
==> default:  -- Graphics Password: Not defined
==> default:  -- Video Type:        cirrus
==> default:  -- Video VRAM:        9216
==> default:  -- Sound Type:
==> default:  -- Keymap:            en-us
==> default:  -- TPM Path:
==> default:  -- INPUT:             type=mouse, bus=ps2
==> default: Creating shared folders metadata...
==> default: Starting domain.
==> default: Waiting for domain to get an IP address...
==> default: Waiting for SSH to become available...
==> default: Configuring and enabling network interfaces...

Now SSH into csr1000v.

# from host shell

vagrant ssh

# now in csr1000v shell

csr#show inventory
NAME: "Chassis", DESCR: "Cisco CSR1000V Chassis"
PID: CSR1000V          , VID: V00, SN: 9NNML42HBX8

NAME: "module R0", DESCR: "Cisco CSR1000V Route Processor"
PID: CSR1000V          , VID: V00, SN: JAB1303001C

NAME: "module F0", DESCR: "Cisco CSR1000V Embedded Services Processor"
PID: CSR1000V          , VID:    , SN:

Good stuff our csr1000v is ready to go, finally clean up the box.

# from host shell

vagrant destroy -f

# output

==> default: Removing domain...


There you have it a Cisco csr1000v for use with the vagrant-libvirt provider.