Build a custom Linux Router image for UNetLab and EVE-NG network emulators

March 8, 2017

The UNetLab and EVE-NG network emulators can become powerful tools for emulating open-source networks. However, When first installed, they support Linux images only in a limited way. Fortunately, it is easy to extend UNetLab and EVE-NG to support powerful, general-purpose Linux router and server images.

In their default configuration, UNetLab and EVE-NG support Linux nodes running boot-able live CD disk images that offer a graphical user interface accessible via VNC. This is not suitable for emulating Linux routers or servers.

To fix this limitation, we will show you how to build a Linux router image for EVE-NG that boots from a virtual hard disk, can be accessed via Telnet to simplify configuration and management, and that has a persistent file system onto which we can install software and modify configuration files.

Add a custom Linux server image to UNetLab or EVE-NG by following the procedure below:

  1. Install a Linux server on a virtual machine on your host computer
  2. Start the new virtual machine and configure it so it is accessible via Telnet after it is moved into UNetLab or EVE-NG:
    • Install and enable Telnet
    • Add a serial interface
    • Add networking software
    • Stop the virtual machine
  3. Copy the new virtual machine’s disk image to the UNetLab or EVE-NG virtual machine
  4. Convert the disk image to QEMU format
  5. Create a custom UNetLab template file and a new config file
  6. Test the image and template

Alternatively, you may copy the installation disk ISO image to the UNetLab or EVE-NG VM and build the Ubuntu Server virtual machine disk image using QEMU commands. This would replace steps 1 to 4, above.

Install a Linux server on a virtual machine

In this case, we will install Ubuntu Server 16.10 in a virtual machine managed by VMware Player. We use VMware Player because we’re already using it to run the EVE-NG VM1 and it should work on any host computer’s operating system.

Download the currently-available Ubuntu Server ISO file — in this case it is ubuntu-16.10-server-amd64.iso — from the Ubuntu Server web site.

Open the VMware Player application and click on the Create a New Virtual Machine button. The New Virtual Machine Wizard window will appear.

In this example, we will use VMware’s Easy Install feature and then install OpenSSH manually after we create the VM. Click on the Use ISO image radio button to use Easy Install2.

To use Easy Install, click on the Use ISO image radio button and enter the path to the ISO file you downloaded earlier. Next, you will be asked to enter the userid and password you wish to set up on the new VM. Then it will ask you to enter the name of the new virtual machine. I chose to name it ubuntuserver.

The last step is very important: we must create a single virtual disk file for the new virtual machine. By default, VMware player will create multiple disk files. In the Disk Size window, be sure to select the Store virtual disk as a single file radio button. Remember, it is not the default option so you must select it yourself.

The wizard will complete the installation without any more user input required. The process should take a few minutes.

Start the new virtual machine and configure it

If you selected the option to Automatically start the virtual machine, it will start automatically. If not, start the virtual machine in VMware Player.

The VMware Player virtual machine console appears with a login prompt. Log in using the user id and password you specified during the installation process.

Install OpenSSH

Since we used VMware’s Easy Install function, OpenSSH is not yet available on the virtual machine.

Install OpenSSH. In the VMware Player console window, enter the following commands:

ubuntu:~$ sudo apt-get update
ubuntu:~$ sudo apt-get install openssh-server

Connect to VM from Terminal window

In the VMware console window, find the IP address assigned to the virtual machine. I used the ifconfig command. In my case, the assigned IP address is 172.16.66.131.

Minimize the VMware console window. We do not want to use it anymore. We will use a Terminal window.

Open a Terminal window and SSH to the VM. In my case, I installed the Ubuntu Server VM with a userid brian and VMware provided it with the IP address 172.16.66.131 so my SSH command looks like the one below. Both these values will be different for you.

t420:~$ ssh brian@172.16.66.131

Install Telnet on the Ubuntu Server VM

We need Telnet to interact with the EVE-NG network emulator but it is not installed or enabled in Ubuntu Server. We need to install and enable telnet on the Ubuntu Server.

To install Telnet:

ubuntu:~$ sudo apt-get install xinetd telnetd

To enable Telnet, create a telnet config file in the /etc/xinetd.d directory3:

ubuntu:~$ sudo nano /etc/xinetd.d/telnet

Add the following text to the new /etc/xinetd.d/telnet file:

service telnet
{
disable = no
flags = REUSE
socket_type = stream
wait = no
user = root
server = /usr/sbin/in.telnetd
log_on_failure += USERID
}

Save the file and restart the xinetd service.

ubuntu:~$ sudo service xinetd restart

Add a serial port on the VM

When not using VNC, UNetLab or EVE-NG connects to nodes using a serial interface. To allow a node to connect with UNetLab or EVE-NG, we must enable the serial port ttyS0 connection on the Ubuntu Server VM4.

Execute the following commands in the Terminal window:

ubuntu:~$ sudo systemctl enable serial-getty@ttyS0.service
ubuntu:~$ sudo systemctl start serial-getty@ttyS0.service

NOTE: Ubuntu Server 16.10 uses systemd init system so the procedure above works in Ubuntu Server 16.10 or any other distribution that uses systemd. The procedure you use to add a serial interface to a Linux system may be different if you are using another init system. For example, if you are using a different Linux distribution or an older version of Ubuntu Server. Below, I list some links to other serial interface configuration methods for other init systems and Linux distributions:

If you are new to the various initialization systems used in Linux, see this nice summary of the differences between init, upstart, and systemd, or search Google for “comparison of init systems”.

Install networking software

Install the network services we may use in our UNetLab or EVE-NG labs: Quagga and Traceroute.

ubuntu:~$ sudo apt-get install -y quagga quagga-doc traceroute

It is best to install any software you think you may use in this image now, before you install the image in the EVE-NG or UNetLab VM.

Stop the VM

We have completed setting up the new VM. To stop the new VM, execute the following command in the VM console:

ubuntu:~$ sudo shutdown -h now

Copy the new Linux server disk image to the UNetLab or EVE-NG virtual machine

In this example, I am using EVE-NG but all the procedures below work the same in UNetLab.

Start the EVE-NG VM in VMware Player.

Open a new Terminal window and login to the EVE-NG VM using SSH. The EVE-NG VM’s IP address is displayed on the EVE-NG VM’s console window. In this case, it is 172.16.66.120.

t420:~$ ssh root@172.16.66.120

Now you are logged into the EVE-NG VM’s Linux shell. On the EVE-NG VM, create a new directory for the Linux Router image:

eve-ng:~# mkdir /opt/unetlab/addons/qemu/linuxrouter-ubuntu.server.16.10

Remember that the directory name must follow the EVE-NG naming convention. We plan to create a custom template that will use the name “linuxrouter” so the directory name must start with the suffix “linuxrouter-“. You may choose a different name if you wish but the template name and the directory name suffix must match according to the correct naming convention.

Assuming you named the VM you created ubuntuserver, the disk image is stored on your laptop computer in the directory $HOME/vmware/ubuntuserver. To copy the image to the EVE-NG VM, open another Terminal window on your host computer and run the following command in that terminal window:

t420:~$ scp $HOME/vmware/ubuntuserver/ubuntuserver.vmdk root@172.16.66.120://opt/unetlab/addons/qemu/linuxrouter-ubuntu.server.16.10

Convert the VMware disk image to a QEMU disk image

EVE-NG and UNetLab both require that disk images be in the QCOW2 format and that the disk image file be named hda.qcow2. We uploaded a VMware VMDK formatted disk image. We need to convert it.

To convert the VMDK disk image to a QCOW2 disk image, execute the following commands in the EVE-NG terminal window:

eve-ng:~# cd /opt/unetlab/addons/qemu/linuxrouter-ubuntu.server.16.10
eve-ng:~# /opt/qemu/bin/qemu-img convert -f vmdk -O qcow2 ubuntuserver.vmdk hda.qcow2
eve-ng:~# /opt/unetlab/wrappers/unl_wrapper -a fixpermissions
eve-ng:~# rm ubuntuserver.vmdk

Now we have a file named hda.qcow2 in the image directory named linuxrouter-ubuntu.server.16.10.

Create new template file

Every node type in EVE-NG has a template file that specifies node startup parameters such as node name, number of interfaces, which hypervisor supports the node, and the startup parameters used by the hypervisor.

When creating a new custom image, it is usually easiest to create a template file by copying an existing template that is similar to the type of node you will create, and then modifying the copy. We’ll create a new template by copying the linux template and naming the copy linuxrouter.

The template files are stored in the EVE-NG directory /opt/unetlab/html/templates. Copy the linux.php template to create a new template file named linuxrouter.php:

eve-ng:~# cd /opt/unetlab/html/templates
eve-ng:~# cp linux.php linuxrouter.php

Next, edit the linuxrouter.php file:

eve-ng:~# vi linuxrouter.php

Make the following changes to the file:

  • Change the ‘name’ value to ‘LinuxRouter’
  • Change the ‘icon’ value to ‘Router.png’
  • Reduce the ‘ram’ value to ‘1024’
  • Increase ‘ethernet’ value to ‘4’ (or higher)
  • Change ‘console’ value to ‘telnet’
  • Change ‘qemu_options’ value as follows:
    • delete ‘-vga std -usbdevice tablet -boot order=dc’
    • add ‘-serial mon:stdio -nographic -boot order=c’

The final linuxrouter.php file should look like:

<?php
$p['type'] = 'qemu';
$p['name'] = 'LinuxRouter';
$p['icon'] = 'Router.png';
$p['cpu'] = 1;
$p['ram'] = 1024; 
$p['ethernet'] = 4;
$p['console'] = 'telnet';
$p['qemu_arch'] = 'x86_64';
$p['qemu_nic'] = 'virtio-net-pci';
$p['qemu_options'] = '-machine type=pc-1.0,accel=kvm -serial mon:stdio -nographic -boot order=c';
?> 

Create the config.php* file

We need to add the template to the node-templates list in the EVE-NG initialization file, /opt/unetlab/html/includes/init.php, so it will appear in the EVE-NG user interface. However, the init.php file is overwritten whenever we update EVE-NG.

According to the comments in the init.php file, we can create a file named config.php in the same directory and add in our own configuration which will then be included in the EVE-NG configuration when init.php runs, and which will override the associated configuration in the init.php file. The config.php file will not get overwritten when you update the EVE-NG VM.

The template names are listed in the $node-templates array in the init.php file. Copy this array to the config.php file and then add the new linuxrouter template name to the array5.

In the EVE-NG terminal window, list the init.php file:

eve-ng:~# cd /opt/unetlab/html/includes/
eve-ng:~# cat init.php

Scan through the text output for a block of text starting with $node_templates = Array(. Copy the block of text starting with $node_templates = Array( and ending with the closing parenthesis and semicolon );.

Next, create and edit the file config.php:

eve-ng:~# vi config.php

If config.php did not previously exist and you are editing a blank file, add the PHP descriptors <?php and ?> to make the new config.php file a PHP file.

Paste the copied block of text into the file, then add the following line to the array:

'linuxrouter'   =>  'Linux Router'

If adding this line somewhere inside the array, add a comma , to the end of the line. If adding this line to the end of the array, add a comma , to the end or the previous line.

You may comment out lines related to templates you will never use. This makes the EVE-NG or UNetLab user interface a bit easier to use when adding new nodes. In my case, I commented-out most of the lines in the array, except for a few Linux-related templates.

In the version of EVE-NG I used when writing this post, the contents of the config.php file with the added linuxrouter line, and with unused lines commented out, will be:

<?php
  $node_templates = Array(
    //'a10'         =>  'A10 vThunder',
    //'clearpass'       =>  'Aruba ClearPass',
    //'timos'       =>  'Alcatel 7750 SR',
    //'veos'        =>  'Arista vEOS',
    //'barracuda'       =>  'Barraccuda NGIPS',
    //'brocadevadx'     =>  'Brocade vADX',
    //'cpsg'        =>  'CheckPoint Security Gateway VE',
    'docker'        =>  'Docker.io',
    //'acs'         =>  'Cisco ACS',
    //'asa'         =>  'Cisco ASA',
    //'asav'        =>  'Cisco ASAv',
    //'cda'         =>  'Cisco Context Directory Agent',
    //'csr1000v'        =>  'Cisco CSR 1000V',
    //'cips'        =>  'Cisco IPS',
    //'ise'         =>  'Cisco ISE',
    //'c1710'       =>  'Cisco IOS 1710 (Dynamips)',
    //'c3725'       =>  'Cisco IOS 3725 (Dynamips)',
    //'c7200'       =>  'Cisco IOS 7206VXR (Dynamips)',
    //'iol'         =>  'Cisco IOL',
    //'titanium'        =>  'Cisco NX-OSv (Titanium)',
    //'firepower'       =>  'Cisco FirePower',
    //'firepower6'      =>  'Cisco FirePower 6',
    //'ucspe'       =>  'Cisco UCS-PE',
    //'vios'        =>  'Cisco vIOS',
    //'viosl2'      =>  'Cisco vIOS L2',
    //'vnam'        =>  'Cisco vNAM',
    //'vwlc'        =>  'Cisco vWLC',
    //'vwaas'       =>  'Cisco vWAAS',
    //'phoebe'      =>  'Cisco Email Security Appliance (ESA)',
    //'coeus'       =>  'Cisco Web Security Appliance (WSA)',
    //'xrv'         =>  'Cisco XRv',
    //'xrv9k'       =>  'Cisco XRv 9000',
    //'nsvpx'       =>  'Citrix Netscaler',
    //'sonicwall'       =>  'Dell SonicWall',
    'cumulus'       =>  'Cumulus VX',
    //'extremexos'      =>  'ExtremeXOS',
    //'bigip'       =>  'F5 BIG-IP LTM VE',
    //'fortinet'        =>  'Fortinet FortiGate',
    //'radware'     =>  'Radware Alteon',
    //'hpvsr'       =>  'HP VSR1000',
    //'olive'       =>  'Juniper Olive',
    //'vmx'         =>  'Juniper vMX',
    //'vmxvcp'          =>  'Juniper vMX VCP',
    //'vmxvfp'          =>  'Juniper vMX VFP',
    //'vsrx'        =>  'Juniper vSRX',
    //'vsrxng'      =>  'Juniper vSRX NextGen',
    //'vqfxre'      =>  'Juniper vQFX RE',
    //'vqfxpfe'     =>  'Juniper vQFX PFE',
    'linux'         =>  'Linux',
    'mikrotik'      =>  'MikroTik RouterOS',
    'ostinato'      =>  'Ostinato',
    //'paloalto'        =>  'Palo Alto VM-100 Firewall',
    'pfsense'       =>  'pfSense Firewall',
    //'riverbed'        =>  'Riverbed',
    //'sterra'      =>  'S-Terra',
    'vyos'          =>  'VyOS',
    //'esxi'        =>  'VMware ESXi',
    'win'           =>  'Windows',
    'vpcs'          =>  'Virtual PC (VPCS)',
    'linuxrouter'       =>  'Linux Router'
  );
?>

You can see that the new linuxrouter template is listed at the end of the array, or wherever you chose to insert it.

Troubleshooting

If you find that EVE.NG or UNetLab does not work after editing either the init.php or the config.php file, you probably forgot a comma.

Ensure you add a comma at the end of every line in the array except the last line.

Finding new templates after updating EVE-NG

As I stated before, the init.php file may be overwritten by a new version when you update EVE-NG and the config.php file is not touched when you upgrade EVE-NG. This ensures that your changes are not erased after an update but, since the config.php file remains unchanged and since it overrides contents of the init.php file, you may miss new templates that have been added by an update in the new version of the init.php file.

After updating the EVE-NG VM, check the init.php file for any new templates and add them to your config.php file, if appropriate.

Test the new custom Linux Server image

We created a new template and image for the Linux Router node and modified the EVE-NG configuration files so we can access this new node type in the EVE-NG user interface. Now, let’s test that we can access the new node from the EVE-NG user interface by using Telnet.

Start up the EVE-NG user interface in your browser. Remember, we set up the EVE-NG virtual machine on a Linux host computer in my previous post.

Open a new project and add the Linux Router node.

The first thing we see is that the normally long list of templates has been reduced to a handful. This is because, in addition to adding the Linux Router template in the config.php file, we commented out many templates we don’t need to use right now.

The Linux Router template panel appears. We accept all the default settings as they are and click Save. Now we have a Linux Router node on the EVE-NG network topology canvas.

Start the node and wait a minute. It is running an Ubuntu Server image, which is a full-featured Linux server, so it will take about a minute to boot.

Click on the node in the EVE-NG topology. A Launch Application window will appear. Select UNetLab-X-Integration. Then, a Terminal window will open and you will see it connects to the node. Press the Return key to see the login prompt.

Now we know we can telnet to this node via its serial interface.

When we use this Linux Router image and template for future projects, we can copy configurations from text files and paste them in each node’s terminal window. This is more convenient than connecting to nodes using VNC.

Troubleshooting

If the login prompt does not appear in the Terminal window, then recheck your procedure. You may have a problem with how you configured the serial interface. This was the problem I encountered most often.

You can check the disk image on the EVE-NG virtual machine by booting a QEMU virtual machine from it on the EVE-NG virtual machine. Then you can access it via VNC and see what the problem is. You’ll need to set up bridges and networking so I think it is easier to go back to the Linux host computer and start the original image up again in VMware and fix it there, then copy the fixed image back to the EVE-NG VM.

Regardless whether you fixed the disk image directly in the EVE-NG VM or whether you copied a new image from your host computer to the EVE-NG VM, you need to ensure that you pick up the new disk image in the test project. To do this, delete the Linux Router node you added and add a new Linux Router node to test project. Otherwise, EVE-NG uses the snapshot of the disk image it created when the node was originally placed in the test project — which is based on the old version of the image that was not working.

Conclusion

We successfully created a Linux router image that can be accessed in EVE-NG via Telnet over a serial interface and installed it in the EVE-NG virtual machine. We created a new template that uses the Linux router image.

The same procedure will also work in UNetLab.


  1. We could also use VirtualBox or QEMU to create the new Ubuntu Server image. VirtualBox or QEMU will allow us to create an image in the QCOW2 format, which means we would not need to convert it after we copy it to the EVE-NG VM. 

  2. If you want more control over the installation process — for example, so you can select OpenSSH as part of the install process — choose the third radio button in this window, I will install the operating system later, which allows you to manually work through all the installation steps

  3. Reference: https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/3/html/Reference_Guide/s1-tcpwrappers-xinetd-config.html 

  4. Reference: https://help.ubuntu.com/community/KVM/Access 

  5. Reference: http://noshut.ru/2015/09/adding-spirent-virtual-test-center-traffic-generator-to-unetlab/ 

One response to Build a custom Linux Router image for UNetLab and EVE-NG network emulators

  1. could you make a tutorial how to install gns3 with virtualbox in ubuntu machine. thanks in advance