On a Linux systems QEMU is the standard hypervisor for running virtual machines. It’s one of core technologies, which allows GNS3 and EVE-NG/UnetLab to emulate networking devices. In some situations it would be nice, if it’s possible to inspect and modify the QEMU images directly, without running the emulated system.

Linux can easily mount a disk image (sudo mount -o loop <file> <mount point>). But mounting a VM disk image is not that simple. A VM disk normally contains only the used disk blocks (sparse images). QEMU allows to use images, that contain only the differences from backing images. All that can’t be directly handled by Linux.

One simple solution is to convert the QEMU image to a raw disk image and mount that. The main drawback is, that the raw image can use a considerable size on the disk, because it contains also all unused disk blocks.

qemu-img -O raw <QEMU image> <raw image>
sudo mount -o loop <raw image> <mount point>

A much better alternative is using guestfish from the libguestfs-tools package. Roman Dodin wrote a nice article about it: http://noshut.ru/2016/09/using-guestfish-to-modify-vm-disk-image/ The main drawback is the installation size. It needs about 100 MByte disk space, when you have already installed libvirt, otherwise 200 MByte. For casual use, it’s too heavy for me.

A very lightweight alternative is qemu-nbd, a QEMU Disk Network Block Device Server. It takes a VM disk image, that QEMU supports and exports that as a NDB device. That NBD device can be mounted and then used as any other disk. It needs no extra packages, just QEMU.

sudo modprobe nbd
sudo qemu-nbd -c /dev/nbd0 -P <partition #> <QEMU image>
sudo mount /dev/nbd0 <mount point>
.  Use the mounted disk image
sudo umount /dev/nbd0
sudo qemu-nbd -d /dev/nbd0

I’ve created the shell scripts qemu-mount and qemu-umount, they hide the use of qemu-nbd and the allocation of a free NBD device. Download the ehlers/qemu-mount Gist to the GNS3 VM and install it:

sudo cp qemu-*mount /usr/local/bin/
sudo chmod +x /usr/local/bin/qemu-*mount

qemu-mount has the following usage:

Usage: qemu-mount [OPTIONS] qemu_image mount_point

  -p partition_number      select, which partition to mount, default #1
  -r                       mount read-only
  -t fstype                set filesystem type
  -u                       set owner to current user

Without arguments it prints a list of mounted images.

The usage of qemu-umount is even simpler, qemu-umount <qemu_image or mount_point>.

Both scripts can be used as a normal user, when needed the privileged commands will be started with sudo.


  • Never use any image manipulation program on an image, that is currently in use by a running device. That will very likely ruin the image.
  • If you want to only inspect an image, use the option -r (read-only).
  • Modify only copies of an image. If something goes wrong, you still have the original.

Extract the configuration from an IOSv Image

First we need an utility, that can extract the configuration out of Cisco NVRAM files. GNS3 contains the Python module iou_export, that can be used for this. It’s well hidden in the gns3server package and should be copied to /usr/local/bin for easy access.

gns3@gns3vm:~$ find /usr/lib /usr/local/lib -name iou_export.py
gns3@gns3vm:~$ sudo cp /usr/local/lib/python3.4/dist-packages/gns3server/compute/iou/utils/iou_export.py /usr/local/bin/iou_export
gns3@gns3vm:~$ sudo chmod +x /usr/local/bin/iou_export

Alternatively you can download the latest iou_export from https://github.com/ehlers/IOUtools and install it in /usr/local/bin.

iou_export -h shows a small help text:

gns3@gns3vm:~$ iou_export -h
usage: iou_export [-h] NVRAM startup-config [private-config]

iou_export exports startup/private configuration from IOU NVRAM file.

positional arguments:
  NVRAM           NVRAM file
  startup-config  startup configuration
  private-config  private configuration

optional arguments:
  -h, --help      show this help message and exit

Now we need to know, where the IOSv image is stored. In GNS3 open the project and then right-click on the IOSv device and select “Show in file manager”. You will get an information windows similar to this:

Show in file manager

Copy the path to the clipboard, so you don’t have to enter it later manually. The image gets mounted with qemu-mount -r <paste path>/hda_disk.qcow2 /mnt. The command ls -l /mnt lists the files within the image. It contains a nvram file, that stores the configuration. With iou_export /mnt/nvram <startup config> [<private config>] the startup config and optionally the private config can be extracted. After that we unmount the disk image with qemu-umount.

Here a sample session, the configs are extracted and stored in the files R1-startup-config and R1-private-config:

gns3@gns3vm:~$ qemu-mount -r /opt/gns3/projects/9ee63325-78ea-4b39-b680-1d9c7f68360d/project-files/qemu/38e3f7a9-7294-4cad-838d-a7719596037a/hda_disk.qcow2 /mnt
gns3@gns3vm:~$ ls -l /mnt
total 140352
drwxr-xr-x 3 root root      4096 Jan 30  2013 boot
drwxr-xr-x 2 root root      4096 Oct 14  2013 config
-rwxr-xr-x 1 root root       419 Oct 17 14:41 config.grub
-rwxr-xr-x 1 root root        79 Oct 17 14:39 e1000_bia.txt
-rwxr-xr-x 1 root root         0 Oct 16 15:25 ios_config_checksum
-rwxr-xr-x 1 root root         0 Oct 16 15:25 ios_config.txt
-rwxr-xr-x 1 root root    524288 Oct 16 15:25 nvram
-rwxr-xr-x 1 root root 143178592 Mar 22  2016 vios-adventerprisek9-m
gns3@gns3vm:~$ iou_export /mnt/nvram R1-startup-config R1-private-config
gns3@gns3vm:~$ qemu-umount /mnt
/dev/nbd0 disconnected
gns3@gns3vm:~$ head R1-startup-config

! Last configuration change at 12:40:57 UTC Tue Oct 17 2017
version 15.6
service timestamps debug datetime msec
service timestamps log datetime msec
no service password-encryption
hostname R1

Configure an ASAv Image for Telnet access

Cisco creates two versions of the ASAv appliances. The ASAv images downloadable from VIRL are using a serial console, accessible in GNS3 via Telnet. The ASAv images from software.cisco.com use the VGA console, GNS3 uses VNC to access it. The better method is serial/telnet access, as cut-and-paste is working and non-US keyboards have the correct layout.

Alec DuChene has posted a very nice guide how to change the console to serial/telnet. On the GNS3 community website search for “asav telnet” and choose the “How to configure any ASAv .qcow2 image for serial telnet…” result.

But by accessing the QEMU image directly, the change is really simple. First make a copy of the original image, then mount the second partition. Now create the use_ttyS0 file and umount the image. Finally modify the GNS3 ASAv template to use the modified image and to use Telnet access (right-click on the ASAv in the device area, select “Configure template” and change the console type to Telnet and change the image in the HDD tab).

gns3@gns3vm:~$ cp -p /opt/gns3/images/QEMU/asav971.qcow2 /opt/gns3/images/QEMU/asav971_serial.qcow2
gns3@gns3vm:~$ qemu-mount -u -p 2 /opt/gns3/images/QEMU/asav971_serial.qcow2 /mnt
gns3@gns3vm:~$ touch /mnt/use_ttyS0
gns3@gns3vm:~$ qemu-umount /mnt
/dev/nbd0 disconnected