innercoder.com

A blog for Linux programming enthusiasts

Automating Quagga With QEMU-KVM: Part 1

| Comments

Intro

Some days ago I needed a proof of concept for some routing configuration using Linux that was stuck in my head for days already. So I needed a way to bring up some Linux boxes to quickly to check this. The ONL website proved very useful, but I needed to use CentOS. So I came up with a script based on the mentioned tutorial that brings up QEMU-KVM images with Quagga already installed and configured.

This post takes you through the basics of installing and configuring both QEMU-KVM and Quagga. And with the ease of a script to create multiple VMs to play with.

What is QEMU?

QEMU is a hypervisor, simple as that. It can emulate different hardware architectures and devices. It is considered a Type 2 hypervisors since it runs with a host OS. Other populars hypervisors in this category are ORACLE Virtualbox and VMware Fusion.

What is KVM?

KVM is a Linux kernel module that allows the utilization of hardware extension for virtualization, in this case Intel VT-x and AMD-V. This module increases the performance of QEMU since instructions to the virtual cpu do not need to be translated by the hypervisor, they can be directly executed by the physical cpu.

What is Quagga?

Quagga is a routing protocol suite. It allows for a Linux box to run routing protocols by way of a daemon that control the kernel’s routing table. Another popular routing protocol suite is Bird.

Procedure

Install needed packages

1
apt-get install kvm libvirt qemu-kvm

Get VM creation privileges

1
adduser YOUR_USER libvirt

Download the ISO

The ISO used for this small project was CentOS 7. Specifically CentOS-7-x86_64-Minimal-1511.iso. Here is the link

Create the image

With the ISO in our hands we need to create the image where it is going to be installed, we have to options a raw and qcow2. Raw images allow for faster I/O with the disadvantage that they take the full hard disk space they were created with. Qcow2 takes a hit on peformance but saves you space. You can choose either of them depending on your situation. Here is the output for a qcow2 image. CentOS 7 requires around ~2.5GBi of HD space.

1
2
3
qemu-img create -f qcow2 image_name.qcow2 3G
Formatting 'image_name.qcow2', fmt=qcow2 size=5368709120 encryption=off
cluster_size=65536 lazy_refcounts=off 

Install CentOS on image

After having the created the image we are ready to install our new OS into it. I gave it 2 GB of RAM to speed it up. NOTE: the command is called kvm but it is actually a wrapper/backend for the command qemu-system-x86_64 -enable-kvm

1
2
kvm -m 2048 -cdrom CentOS-7-x86_64-Minimal-1511.iso -vga vmware -hda
router.qcow2

Basic configuration of Linux box

After a succesfull installation of the OS we reboot and get into our command line. We are going to do basic configuration to prepare the OS for Quagga. Run the image:

1
kvm -m 2048 -vga vmware -hda router.qcow2

QEMU will automatically brigde our network interface for internet access as the host.

Run the following commands for basic configuration. The numbers belongin to the quagga directory could be different.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// I really dislike systemd's network interface renaming
Append "net.ifnames=0" and "biosdevname=0" as kernel arguments to /etc/default/grub 
"GRUB_CMDLINE_LINUX" then,
grub2-mkconfig -o /boot/grub2/grub.cfg

// This might take a while
yum update
yum install quagga

// Allow changes to Zebra's configuration file
setsebool -P zebra_write_config 1

// Enables IP forwading between interfaces inside the host
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf

// Obtain zebra configuration file
cp /usr/share/doc/quagga-0.99.22.4/zebra.conf.sample /etc/quagga/zebra.conf

// Obtain ospf configuration file
cp /usr/share/doc/quagga-0.99.22.4/ospfd.conf.sample /etc/quagga/ospfd.conf

// Obtain rip configuration file
cp /usr/share/doc/quagga-0.99.22.4/ripd.conf.sample /etc/quagga/ripd.conf

// Obtain bgp configuration file 
cp /usr/share/doc/quagga-0.99.22.4/bgpd.conf.sample /etc/quagga/bgpd.conf

// Enable zebra daemon 
systemctl enable zebra

So now our gold image is ready to be used for multiple purposes. One thing that can still be done right now or can be left for later is the hostname renaming and the enabling of which routing protocol daemons to enable.

1
2
3
4
5
6
7
// Set hostname
hostnamectl set-hostname routerX

// Enable routing protocol daemons
systemctl enable ospf
systemctl enable bgp
systemctl enable rip

This will depend of what things you need to automate. We will come back to this at the end.

Automation Script

Now I am going to analyze our automation script to bring up the images, create, and setup the bridges. The full script is at my github repo.

1
2
3
4
5
if [ ! -e /dev/kvm ]; then
  set +e
  mknod /dev/kvm c 10 $(grep '\<kvm\>' /proc/misc | cut -f 1 -d' ')
  set -e
fi

This part is essential for the use of kvm virtualization extension. This section makes sure there is a device node created for the kvm module. It creates it otherwise.

1
2
3
4
5
6
7
8
9
10
for bridge in $BRIDGES; do
  printf "Adding bridge $bridge\n"
  $BRCTL addbr $bridge || die "$BRCTL addbr $bridge Failed"
  sleep 2
  $IP link set $bridge address 00:11:11:aa:aa:aa
  $IP link set $bridge address 00:11:11:bb:bb:bb
  sleep 2
  printf "Bringing up all bridge interfaces\n"
  $IP link set dev $bridge up || die "$IP link set dev $bridge up"
done

This part pretty much creates the bridges for the routers and enables them. Each bridge requires a different MAC address. Further automation for this could be to perform this at the end by deducing from the amount of routers peer routers that are going to be configured and/or needed.

1
2
3
4
5
6
7
$KVM $KVM_OPTS \
  -name router1 \
  -net nic,macaddr=52:54:00:00:01:00 -net tap,ifname=r1-eth0,script=no,downscript=no \
  -net nic,macaddr=52:54:00:00:01:01 -net tap,ifname=r1-eth1,script=no,downscript=no \
  -net nic,macaddr=52:54:00:00:01:02 -net tap,ifname=r1-eth2,script=no,downscript=no \
  -hda ./images/router1.qcow2 &
sleep 5

This is done for every router, we create three interfaces here but this can be automated even further to whatever we need. For example, we could ask the user how many interfaces are needed for a particular router. We let the command take a few seconds before going with the other routers.

1
2
3
for intf in $INTF; do
  $IP link set dev $intf up
done

This small piece simply brings up the newly created interfaces.

1
2
3
4
5
#### Creating physical-links/bridges for routers
$BRCTL addif brdg1 r1-eth0 || die "$BRCTL addif brdg1 r1-eth0"
$BRCTL addif brdg1 r2-eth0 || die "$BRCTL addif brdg1 r2-eth0"
$BRCTL addif brdg2 r1-eth1 || die "$BRCTL addif brdg1 r1-eth1"
$BRCTL addif brdg2 r3-eth0 || die "$BRCTL addif brdg1 r3-eth0"

This final part is what joins the bridges with the respective router interfaces. This part could be automated to ask the user what interfaces are going to be logically connected.

This is it. Take a look at the script. I was able to quickly and succesfully bring up three routers and configure them with OSPF. I could make another post where OSPF, BGP ,and RIP are configured with Quagga but there are so many out there already.

On Part 2, I will analyze a more automated version of this script and show the steps to pack this script into the image.

Thanks for visiting.

Comments