Saturday 27 September 2014

How to use Marionnet and create networks of relativistic virtual machines


Marionnet


This tutorial will guide through the creation of a simple virtual network with Marionnet.

Devices


Let's take a quick look at the devices that Marionnet offers:



Machine


This is the representation of a classical computer running Linux. Usually the end point of a communication, it's emulated with User Mode Linux, and offers all its functionalities.

Hub


A hub is layer 2 device that just relays frames to all its connected ports. Nowadays in real life hubs are often replaced by switches, but hubs can make it easy to intercept frames transmitted between multiple devices, so you could place one if you plan on capturing frames with auditing tools like wireshark.

Switch


You can think of a switch as smart hub. Instead of blindly repeating the signals received, a switch forwards received frames only to ports that lead to the destination host. Use it to create simple or complex local area networks. The switch is implemented with VDE. If you want to try complex experiments with switches, be sure to check out Virtual Square's wiki: http://wiki.v2.cs.unibo.it/wiki/index.php/VDE .

Router


A router is a machine that can connect multiple subnetworks together. In Marionnet routers are implemented with a User Mode Linux process running on a small filesystem that includes the quagga routing suite. The filesystems provided by Marionnet are named Pinocchio and Guignol.

Straight cable


Marionnet makes the distinction between stright cables and crossover cables: the connection will not work if you chose the wrong cable type. Straight cables are able to connect different kinds of devices.

Crossover cable


Marionnet makes the distinction between stright cables and crossover cables: the connection will not work if you chose the wrong cable type. Crossover cables are able to connect machines of the same kind.

Unknown layer 2 sub-network


This is the abstract representation of an unknown subnetwork. We don't know what is in the cloud, we only know what enters it and what comes out of it. Although the effects in the virtual network are the same as those of a hub, this element highlights a lack of information about the network topology.

Real world access


Under this section you will find two subdevices called Gateway and Bridge. These can be used to connect the virtual network with the real network of your host machine.

Simple network


Let's start by creating a very basic network with Marionnet. We will create two machines and connect them with a cable.

Before adding the devices, we need to specify a location for our new project. Click on Project and select New from the menu. A classic path selection window will appear. Navigate to the location where you want your project to be saved and choose a file name for it. Marionnet is somewhat picky with project file paths: it will not accept some special characters, but it will not warn you either. This should not be a problem if you don't choose fancy path names, but be wary of the ' ' character (whitespace) because it won't be accepted.

The file name should also not include dots '.', because the first dot will be interpreted as the beginning of the extension, which must be .mar
After creating the project file, you will find yourself with an empty canvas. It's time add some devices!
Click on the Machine icon on the left, and select add from the menu.
 A popup with a form will appear, asking you to configure the new machine.

You can type any name for Name and Label (the latter is optional). I suggest labelling the machine with the IP address that you intend to assign it.



Hardware

For this example you can leave Memory and Ethernet cards to their default value. User Mode Linux doesn't need much memory, and you will probably want more only for running graphical programs like wireshark.

Machines can have multiple ethernet ports, but in our example we need only one port per machine.



Software

The Distribution field instructs Marionnet on what filesystem it should use for the new machine. A few filesystems are already provided by marionnet, but you can add your own to the list, if you wish. If you installed Marionnet with marionnet_from_scratch with the default parameters, it will look for virtual filesystems in /usr/local/share/marionnet/filesystems. You can change this location by editing /etc/marionnet/marionnet.conf. If you want your custom filesystem to be recognized by marionnet, be sure to name the file with the prefix “machine-”.

Variants are modified versions of the standard filesystems, and are handy if you want to run a copy of the same machine in multiple networks or projects. For now, you can safely ignore this field.

The Kernel field allows you to select the UML (User Mode Linux) kernel version to use. Marionnet provides its own patched kernels, but you can easily build your own. The mechanics are similar to those for filesystems: the default location is /usr/local/share/marionnet/kernels, files must be named with the prefix “linux-”.



Access

I see no reason to edit this field, but if desired here you can change the way that X windows are displayed.



Relativization

I added this section myself, and I don't know if it will be included in the official Marionnet project. To experiment with the relativization feature, get the patched Marionnet, or just the patch. For information on compiling and installing Marionnet check out its wiki.

The controls in this section let you change the virtual frequency of properly patched UML machines. The Frequency field sets the frequency of the virtual clock. It is expressed as the number of Hz of the virtual frequency: the number of virtual seconds elapsed for each real second. A value less than 1 will generate a virtual time slower than the real one, while a value greater than 1 will generate a virtual time faster than the real one. Note that this doesn't affect the speed of operation. Indeed, from the point of view of virtual machines with high frequency all operations will seem proportionally slower!

Convergence is the point in time when real and virtual time are the same. For virtual frequencies different than 1, the virtual time will diverge from this point, meaning that at great time distances the virtual date and the real one will look very different. The value of Convergence is expressed as a Unix timestamp, that is the number of seconds elapsed since the Epoch (00:00:00 UTC, 1 Jan 1970).

When you're done click on OK. Repeat the process to add the second machine.

To connect these machines we're going to add a crossover cable. Click on the Crossover cable icon and select Add. In the dialog that appears you can name the cable and optionally assign a label to it. More importantly, you can choose the names of the machines that you want to connect and their port numbers. In our case we're fine with the default values.


The resulting network graph should look like this:


Let's start up the machines by clicking on the Start all button. After a while two terminal emulator windows will appear. Login in both terminals with the default username/password: root/root. When you create networks with lots of machines, all those terminal windows could be confusing. To find out the machine which the terminal is attached to, look at the window's title: it will show the machine name and, in parenthesis, the virtual filesystem image.

Before the machines can talk to each other, you must configure them. In my debian wheezy image I have the ip command, so I can issue this:
[0 root@m1 ~]$ ip addr add 192.168.50.2/24 dev eth0
[0 root@m1 ~]$ ip link set eth0 up
[0 root@m2 ~]$ ip addr add 192.168.50.3/24 dev eth0
[0 root@m2 ~]$ ip link set eth0 up
If ip is not installed, try with ifconfig:
[0 root@m1 ~]$ ifconfig eth0 192.168.50.2/24 up
[0 root@m2 ~]$ ifconfig eth0 192.168.50.3/24 up

Now the machines should be properly connected. Let's test them by pinging m2 from m1:
[0 root@m1 ~]$ ping -c 3 192.168.50.3
PING 192.168.50.3 (192.168.50.3) 56(84) bytes of data.
64 bytes from 192.168.50.3: icmp_req=1 ttl=64 time=0.827 ms
64 bytes from 192.168.50.3: icmp_req=2 ttl=64 time=1.03 ms
64 bytes from 192.168.50.3: icmp_req=3 ttl=64 time=0.809 ms

--- 192.168.50.3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 0.809/0.889/1.032/0.104 ms
As you can see we have correctly set up the network.
To shutdown the machines, click on the Shutdown all button in the bottom of Marionnet's window. You can also shutdown the machines individually by clicking on the Machine icon and selecting Stop, then the machine name. The opposite can be achieved by selecting Start.
Now we want to save the project, so click on Project and select Save or Save as. If you try to close the project without saving it, Marionnet will warn you and ask if you want to save. The saved project will keep all the machines disk information, but the changes made by the commands we issued were not stored, so the next time when you open the project you will have to configure the machines again.

Adding Real World Access: Gateway

There are many reasons why you may want to connect your virtual network to the real world, but you usually want it to install new packages in the virtual filesystems. Read on to find out how to achieve this.
On the left panel you will find the Real world access icon. After clicking it you have to choose between two types of device. In the wiki you can read a guide on how to use Bridge. I recommend choosing Gateway as way to access the host network because it is much simpler to set up.
Select Gateway, then Add. This window will pop up:





Name and Label fields are unimportant, since usually you don't need more than one gateway to the real world in your virtual network.
By modifying the IPv4 address fields you can set the address that the gateway will have inside the virtual network, meaning that virtual devices must be configured to connect to this address. For this example set the address to 192.168.50.1/24.
If DHCP service is checked the gateway will keep and internal pool of IP addresses and automatically assign them to devices that wish to connect to it. DHCP is quite handy, so we're going to check the box.
Integrated switch ports is self-explaining: it is the number of ports of the integrated switch. The default is 4, meaning that up to four devices can directly connect to this gateway simultaneously. For our purposes the default is fine.
When you're done click the OK button.
Now you have to connect machine m1 to gateway G1. Marionnet's gateway device has the Auto-MDIX feature, so either a straight cable or a crossover cable can be used to connect the gateway.
For example, you could modify the cable you added earlier: click on the Crossover cable icon and select Modify, then just change m2 to G1 in the To section (or From, if you attached the cable that way).
If you are logged in m1 as root, I suggest you logout and log back in as a regular user. The default regular username is “student”, with password “student”. Changing the password could be a good idea, and you should feel free to take additional security measures. We you are ready, insert this in m1's terminal emulator have it be automatically assigned an IP address by G1:
[0 student@m1 ~]$ sudo dhclient eth0
Now you are connected to same network as your host machine, so if you connect your machine to the Internet you will be able to access it from m1. My ping tests failed, probably because ICMP requests are filtered at some level. You can still test the connection with something like telnet:
[0 student@m1 ~]$ telnet www.google.com 80
Trying 173.194.65.147...
Connected to www.google.com.
Escape character is '^]'.
(press ctl+C to terminate the connection) or with web browsers like lynx and links.
Now that you have a working internet connection, you can download and install distribution packages. If you want to install distribution packages, now you can do that. Mind that before installing, you must download the package index files (aptitude update) and that can take time, as well as disk space. Try installing pv and mtr:
[0 student@m1 ~]$ sudo aptitude update && sudo aptitude install pv mtr-tiny
Aptitude seems to be unbelievably slow in Marionnet's virtual machines, so the console might appear to be stuck during the update, but you have to be patient. Grab a cup of coffe or make good use of your operating system multitasking feature.

Variants

After booting up your virtual machines, sometimes you make permanent changes to them, i.e. You modify their filesystem status. Normally, when you save the project the filesystem status of all the virtual machines within the project is saved. What is actually stored though is the differences between the standard Marionnet's filesystem image and the modified one.
The new filesystems are limited to their respective project and cannot be reused for new machines. Sometimes you may want to export modified filesystems for reuse in other projects, for example if you installed new packages that you use often: you have to create Variants.
Let's create a variant for the current status of machine m1's filesystem (where you installed some packages).
If the virtual machines are still running, click on the Shutdown all button to stop them.
On the lower part of Marionnet's main window, click on
Disks to bring up that tab. You will be shown a list of the machines present in the current project. Click on the left arrows to expand the rows. Expand m1 until you reach the last level, then right click on it. Select Export as machine variant.



 

Write the name for the new variant in the dialog that appears, following the rules explained in it. After clicking OK it will take some time to save the data on disk, so be patient.
Now, when you add a new machine with the same base filesystem as the one of the exported variant, you can choose the variant from the menu.


 

Relativization experiment

This example shows how to set up the relativization parameters to test a well-known clock synchronization protocol: NTP.
We want a simple network consisting of two connected machines. If you followed the steps described in the Simple network tutorial you know how to set it up.
When adding the machines, or later by modifying them with Machine → Modify → m1/m2, you have to change the relativization parameters. Set m1's frequency to 10.1 and m2's frequency to 10.0. Set the convergence value to something near the current time. You can get the current time with unix “date”:
asig@asig-laptop:~$ date +%s
1408721348
If you set the convergence time to something too far in the past you can cause critical errors in the virtual machines. This is especially true if your virtual kernels are for the x86 32 bit processor architecture, because internally they use a smaller amount of memory to represent timestamps.
The frequencies chosen differ, so eventually (actually, almost immediately) the time kept by the two machines will differ: they are not synchronized. Why did we set virtual times that are 10 times faster than real time? NTP gradually adjusts timekeeping in order to synchronize the local machine's frequency with the frequency of other machine's clocks. This process, that includes regular information requests, is rather slow, mainly not to cause errors in the local machine's programs. Since maybe you don't want to spend a lot of time for this experiment, I chose higher frequencies to hasten the process. The higher frequencies come with less accurate virtual clocks, but we don't mind too much for the purposes of this example.
Start all the devices by clicking Start all. Set m1's and m2's addresses to 192.168.50.2 and 192.168.50.3 m1 will be the client and m2 will be the server: m1 will try to adjust to m2's frequency. In m1 edit /etc/ntp.conf (that is the NTP configuration file). To keep things simple it's best to erase the contents of the file, then add the following lines:
#Server to query
server 192.168.50.3 iburst minpoll 4 maxpoll 6
server 127.127.1.0

#Calculate and store drift
driftfile /etc/ntp.drift
This way m1 will ask 192.168.50.3 (that is m2) for the correct time, and it will ask itself if m2 is not reachable. The flag iburst instructs the NTP deamon (ntpd) to send more requests at startup, while minpoll and maxpoll are useful to reduce the time elapsed between requests.
Now edit m2's ntp.conf so that it looks like this:
#Self-sync
server 127.127.1.0 iburst

#Respond to local requests
restrict 192.168.50.0 mask 255.255.255.0 nomodify notrap
This way m2 will synchronize with itself, and will act as an NTP server for the 192.168.50.0/24 network, that includes m1.
Before starting the ntpd daemon, verify that the two machines are not running at the same frequency. You can check the current setting for the frequency like this:
[0 root@m1 ~]$ cat /proc/uml_reltime/frequency
10.1000000000
[0 root@m2 ~]$ cat /proc/uml_reltime/frequency
10.0
However, if you want to have more visual feedback, you could compare the seconds ticking on two graphical clocks:
[0 root@m1 ~]$ xclock -update 1 &
[0 root@m2 ~]$ xclock -update 1 &
Two windows will pop up, showing you two traditional analog clocks. A 0.1 Hz skew is quite big, so this difference can be easily seen.
If you don't like the idea of launching a graphical application just to check the time, you may obtain a similar effect with these commands:
[0 root@m1 ~]$ watch -n 1 date
[0 root@m2 ~]$ watch -n 1 date
When you are ready, start the ntpd daemon on both machines:
[0 root@m1 ~]$ /etc/init.d/ntp start
[0 root@m2 ~]$ /etc/init.d/ntp start
If you keep monitoring the two clocks you will see that, given enough time, they will show approximately the same values. In contrast with the difference in frequency, with time the two clocks will progressively converge. Note that, if the initial offset between the clocks is too big, ntpd will panic and you will not be able to see the convergence. To solve this, try to set the clocks to the same value, reduce the frequency offset, or set the Convergence field to some point in the near future.
Wireshark
To better monitor NTP doing its job, you could observe the packets exchanged. Wireshark is a graphical packet sniffer tool included in Marionnet's debian filesystems. Is is very useful to localize network problems and to understand routing and switching, among other things.
Start wireshark in m2:
[0 root@m2 ~]$ wireshark &
When the window has been loaded, select Capture → Interfaces, check the box next to eth0, then click Start.

Adding switches and routers

This tutorial assumes that you know the basics explained in the simple tutorial, and you set up a network like the one described there.
If you have saved the project described in the simple tutorial, open it by clicking on Project, selecting Open and choosing the correct project file.
This is how the network looks like:





We want to add a third machine, and connect all three machines together. Start by adding a new machine as described in the simple tutorial and set its label to the address you want to assign it: 192.168.50.4/24. Remember that if you want to change the label or other parameters later, you can do that by shutting down the machine, clicking on the Machine icon and selecting Modify. The form is the same as that generated when you add a machine, with the exception that you can't change the filesystem. So you can change most parameters at any time, if the the machine that you are interested in is not running.

We have three machines, each with only one ethernet port. To connect them together, the best solution is to add a switch: all the machines will be connected to the switch, and the switch will forward packets between the machines. Click on the Switch icon and select Add:

The default settings are fine.

Now we have to attach cables to our devices, but first the crossover cable must be removed. Click on the Crossover cable icon on the left panel and select Remove: you see a list of all the cables name, which for now includes only d1. Click the name to remove the cable and confirm by answering Yes to the following question.

Add three cables. We are connecting machines to a switch, so we need straight cables. Click on the Straight cable icon and select Add. You will notice that the dialog looks just like that of the crrossover cable. Select name m1 and port eth0 in the From section and name S1 and port port1 in the To section. The port number of the switch doesn't actually need to be exacly 1, you can select any port. Also note that even though the dialog sections are named From and To, ethernet cables are actually bidirectional and without orientation, so it doesn't matter if you invert these fields.

Repeat the process for the other two machines and you will obtain something like this:



 
You may notice that one of the cables is twisted, and that could be a little confusing when you build a complex network. The default setting for displaying cables is a “top-to-bottom” arrangement, which will try to place the devices on the canvas in a vertical fashion. You can change this behaviour by clicking on the right-pointing arrow icon in the right panel. This is how the canvas will look like:
 
Alternatively, you could invert the cable placement in the image: click on the circling arrow in the right panel and select the name of the cable that you wish to move.



Now let's start everything by clicking on the Start all button on the lower panel.

Only three terminal windows will appear, because we didn't check the Show VDE terminal option when we added the switch. However, the switch ports can be checked for connectivity by looking at the little window that popped up beside the terminals: the green leds indicate activity on the corresponding ports.

It's time to configure the machines. Since we plan on using this network again, this time we will set a permanent configuration in the machines' filesystems. I will show you the easiest way to store network configurations in debian, although there are other methods for different distributions.

Login with root/root in every terminal. Edit the file /etc/network/interfaces. I like the vim editor and I found it preinstalled in the virtual filesystems, so that's what I used for editing the files. Other editors that I found preinstalled are vi and nano, but there may be other ones that I don't know of. In the future I will also show you how to install packages from the Internet on the virtual machines, so you shouldn't worry if your favourite editor is not already installed. Anyways, this is how the file for machine m1 looks like:
[0 root@m1 ~]$ vim /etc/network/interfaces

# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback
That two lines will make the loopback network interface be brought up when the system boots.
Add these lines to bring up the eth0 interface with a static IP address when the system boots:
#static address for eth0
auto eth0
iface eth0 inet static
address 192.168.50.2
netmask 255.255.255.0
The meaning is pretty straightforward. Read this for more information on setting a static IP in Debian. The netmask is here written in the dot notation, whereas before we used to write it with the “/24” suffix.
To quickly make the changes effective without restarting the machine:
[0 root@m1 ~]$ service networking restart
Now test the connection between any couple of machines, with ping:
[0 root@m1 ~]$ ping 192.168.50.4
PING 192.168.50.4 (192.168.50.4) 56(84) bytes of data.
64 bytes from 192.168.50.4: icmp_req=1 ttl=64 time=2.31 ms
64 bytes from 192.168.50.4: icmp_req=2 ttl=64 time=1.25 ms
64 bytes from 192.168.50.4: icmp_req=3 ttl=64 time=1.10 ms
64 bytes from 192.168.50.4: icmp_req=4 ttl=64 time=1.21 ms
64 bytes from 192.168.50.4: icmp_req=5 ttl=64 time=0.460 ms
64 bytes from 192.168.50.4: icmp_req=6 ttl=64 time=1.06 ms
^C
--- 192.168.50.4 ping statistics ---
6 packets transmitted, 6 received, 0% packet loss, time 5023ms
rtt min/avg/max/mdev = 0.460/1.235/2.310/0.548 ms
This shows that m1 and m3 are connected.
You may also try to compare these ping statistics with the ones we got in the Simple network experiment. In my case the number of test packets is quite small, so it's not an accurate estimation, but the results show that our new network has a slightly higher round trip time (rtt). This is probably caused by a little overhead induced by the switch. It's nothing to worry about, but in a large network this effect may become noticeable.
Let's add more machines to create a separate network. Add two machines, named m4 and m5, and assign them the addresses 192.168.100.2/24 192.168.100.3/24 respectively.
To quickly assign the addresses permanently you can make use of the Interfaces tab. Click on its name in the lower part of Marionnet's window. You will find a list of all of your project's level 3 devices. Expand the rows to see their interfaces (ports). You can change the MAC address of the interfaces, their MTU, and their IP parameters. Click on a field to edit its value. Set m4's IPv4 address and IPv4 netmask to 192.168.100.2 and 255.255.255.0. Repeat to set m5's address. When you start the machines they will be automatically assigned the addresses you set.

 

In this screenshot I was reducing the minimum edge size (cable length) by moving the slider in the right panel. This way I can see the whole network topology in one screenful.
Notice that the addresses for the new machines define a new subnetwork, because the netmask 255.255.255.0 implies that only the addresses whose first 24 bits (3 bytes) match (between addresses) belong to the same subnetwork.
To verify this, connect the new machine to the switch with a straight cable, configure the machine with the address that you wrote in its label, and start the machine (you can start it with MachineStart → m4 or with the Start all button). If you try pinging from, say, m1 to m4:
 
We need a router to connect the subnetworks together.
Click on the Router icon in the left panel and select Add.

 
In marionnet a router is simply a machine with the quagga routing suite installed and running. In the Add router dialog you will find familiar parameters, like filesystem and kernel images. Marionnet provides “Pinocchio” and “Guignol” as router filesystems. The latter is not included in the stable version, but a script is available in the development version to create it.
In addition you can pre-configure the IP address of the first port of the router, port0, and optionally enable or disable the virtual terminal window for this device. The reason behind this is that port0 has by default some open TCP ports in order to let you access the router terminal via ssh, or the quagga daemons via telnet, so if you know its address you will not need the terminal window. In this example however I suggest you check the Show unix terminal item in the Access section.
The help window (accessed by clicking the Help button) will show you, among other things, a brief reminder of the usernames, TCP ports, and password required for accessing the quagga daemons via telnet.
Select the address 192.168.50.1/24 for the first port. We're going to set the address for the second port via the unix terminal.
Start up the router with the Start all button.
Login as root/root and set the eth1 interface to 192.168.100.1/24:
[0 root@R1 ~]$ ip addr add 192.168.100.1/24 broadcast 192.168.100.255 dev eth1
[0 root@R1 ~]$ ip link set eth1 up
The router is already configured to forward packets between its interfaces, so we're almost done. Connect the router to the switch with a straight cable: be sure to attach one end to port0 of router R1. We want to connect both m4 and m5 to the network. We have two choices: we can connect m4 and m5 directly to R1 with crossover cables, or add one switch and have it connected with m4, m5 and R1, using straight cables. The first alternative looks a bit weird to me, because the addresses that we choose suggest that m4 and m5 belong to the same subnetwork. Indeed, that's why I chose those addresses. So let's add another switch with default parameters and call it S2.
After adding the new switch remember to start it by clicking Start all.
We need to attach three straight cables: one to m4 and S2, one to m5 and S2, and one to S2 and R1. Be sure to attach the last one to port1 of R1, like this:
  Once everything is connected, it will look like this:

 
At this point I actually tried to ping m1 from m5. As you might have predicted, my test failed because the network was unreachable. This happens because m5 doesn't know where to send packets that are not destinated to its own network. To fix this, set the default gateway for m5:
[0 root@m5 ~]$ route add default gw 192.168.100.1 eth0
 To make this change permanent, add this line to /etc/network/interfaces
gateway 192.168.100.1
Now try to ping m1:
 
This time the network is not unreachable, but we can't receive any response packets. This is because we added the default gateway only for m5, but not for m1. m1 receives our packets, but then it doesn't know on which interface it should send the response. Add the default gateway for m1:
[0 root@m1 ~]$ route add default gw 192.168.50.1 eth0
Now the ping finally succeeds. Until now we always used ping to perform our tests, but there are other tools as well. For example, “traceroute” will show us the path taken by packets to reach their final destination (their route will be traced):
 
As you can see, the packets go through R1 before reaching m1. The result is quite obvious given our network topology and our static routing policy, but in a network that includes many routers and dynamic routing it might help you find errors in the routing policies. Another good tool is mtr. Try it, it basically is like ping and traceroute in one single command.

Set the default gateway in a similar way for the other machines to connect them together. If you want to save the gateway to permanent memory, edit /etc/network/interfaces like this:
# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback

#static address for eth0
auto eth0
iface eth0 inet static
address 192.168.50.2
netmask 255.255.255.0
gateway 192.168.50.1
That's the configuration file for m1, where we added the last line.

Relativization experiment

It's time to play with relativization again. This time you will see how the virtual network bandwidth is affected by time relativity. You will simply transfer one big file between two machines.
If you have previously installed the pv package and exported a variant of the filesystem, you won't need to do that again. The pv program is easy to use and it provides a good visual feedback, but there are good alternatives, so don't feel forced to install it.
Remove machine m3 and add it back with the variant you created. Start everything up, and login in m3 and m5. Test the connection between m3 and m5 with the usual ping command. Alternatively if you installed the package mtr-tiny you can test the connection with mtr, although you would find more use for it if you had to diagnose more complex network problems.
[0 root@m3 ~]$ mtr 192.168.100.3
Netcat is yet another useful tool, often rightfully regarded as the swiss army knife of networking. IN this instance you will use netcat to create a simple TCP stream between m3 and m5.
Set up m5 as the server:
[0 root@m5 ~]$ nc -l -v -p 30000 > /dev/null
The '-l' flag tells netcat to listen for new connections. The '-v' makes netcat verbose and '-p 2000' specifies the TCP port to listen on. The output will just be thrown away (/dev/null).
You want m3 to be the client that sends data to m5, but first you must create some data to send:
[0 root@m3 ~]$ truncate -s 20M newfile
[0 root@m3 ~]$ pv newfile | nc -w 3 192.168.100.3 30000
With truncate you create a new sparse file called “newfile”, of size 20 MB. The second line tells netcat to connect with m5, with the input given by pv. You will immediately see a loading bar, and statistics like transfer speed. This is what it looks like after the file has been transfered:
20MB 0:00:48 [ 424kB/s] [==================================>] 100%
So the virtual bandwidth is approximately 400 kB/s.
Now shutdown everything with the Shutdown all button. In the upper menu bar select Options → Relativization. This is the dialog that you will get:

It contains the same relativization parameters that you can modify in machine and router Add/Modify dialogs. The values that you select here will be used as default when you add new machines or routers. If you leave the option Apply to existing machines checked, the values will also be applied to machines and routers that you already created, provided that they are not running. Leave the option checked and set frequency to 0.4 and convergence to any value, preferably near the current time. When you're done click OK. You can check that the values have been changed by opening the Modify dialogs for any machine or router.
After applying the new parameters, click Start all to restart the network. Connect m3 and m5 with netcat as before, and transfer the 20 MB file. This is the output for m3:
20MB 0:00:19 [1.01MB/s] [==================================>] 100%
As you can see, this time the tranfer was perceived as much faster by m3, and the speed was around 1 MB/s. Let's compare with speed with the one we got without relativization. We notice that
(1 MB/s) / (0.4 MB/s) = 2.5
So by decreasing the virtual frequency by a 0.4 factor, we get a transfer speed two times and a half faster than normal. This happens because the virtual machine perceives time as running slower, but the real transfer speed actually remained the same, so the virtual machine thinks that only 19 s elapsed after starting the transfer, instead of the real 48. In fact, 2,5 is the factor by which the virtual speed is increased and it's the inverse of the virtual frequency.
If you are interested in relativization, try other commands like ping and see how they are affected by frequency. This feature is also potentially useful to test the behaviour of your own programs.

Defects

Marionnet offers the possibility to introduce defects in various devices. We will see how to set the defects through some examples. The network used in the example is the one built in the Switch and Router tutorial.

In the bottom of the Marionnet window there are four tabs: Image, Interfaces, Defects, Disks.

Until now you probably used the Image tab most of all, because it lets you view the network topology, but the other tabs have useful functions as well.

Click on the Defects tab on the lower part of the window.

 
As you can see the Defects tab presents a list of all the devices in the network, including cables. If you expand anything that is not a cable, it will display the list of its own ports/interfaces. Cables and ports can be edited to introduce defects in them. You can alter the properties of frames in either one or both directions.

There are five editable numeric fields: Loss, Duplication, Flipped bits, Minimum delay, Maximum delay. All of them accept rational numbers as input. To edit one field just click on it (initially all fields will be 0), write the new value for it, and click somewhere else or press Enter. You can edit these parameters even while the devices are running. Do not enter empty strings as values, because Marionnet will not like it.

In the example I chose the cable named d1, which connects machine m1 with switch S1, and tried to add defects to it.

Loss

It's simply the percentage of lost frames. For example, if you set it to 50, approximately one half of the frames that go in the chosen direction will be lost. This is a ping test from m1 to m2, where the cable connecting m1 to S1 drops 50% of the frames destinated to S1.
[0 root@m1 ~]$ ping -c 6 192.168.50.3
PING 192.168.50.3 (192.168.50.3) 56(84) bytes of data.
64 bytes from 192.168.50.3: icmp_req=1 ttl=64 time=1.17 ms
64 bytes from 192.168.50.3: icmp_req=2 ttl=64 time=1.40 ms
64 bytes from 192.168.50.3: icmp_req=3 ttl=64 time=1.40 ms
64 bytes from 192.168.50.3: icmp_req=4 ttl=64 time=1.11 ms

--- 192.168.50.3 ping statistics ---
6 packets transmitted, 4 received, 33% packet loss, time 5030ms
rtt min/avg/max/mdev = 1.119/1.273/1.405/0.137 ms
Ping sent 6 packets, but received only 4 responses. The estimated packet loss is 33%, because we tested only a few packets. The more the packets sent, the more accurate the estimation would be, because we actually set the probability of loss, so it's not always exact.



Duplication

In a way this is like the opposite of frame loss: some frames are duplicated. As with Loss, the field represents the probability of errors of this kind to be present in the communication.

This is a ping test from m1 to m2, with Duplication set to 25 in the m1-to-S1 direction.
[0 root@m1 ~]$ ping -c 8 192.168.50.3
PING 192.168.50.3 (192.168.50.3) 56(84) bytes of data.
64 bytes from 192.168.50.3: icmp_req=1 ttl=64 time=1.18 ms
64 bytes from 192.168.50.3: icmp_req=2 ttl=64 time=1.16 ms
64 bytes from 192.168.50.3: icmp_req=3 ttl=64 time=0.513 ms
64 bytes from 192.168.50.3: icmp_req=4 ttl=64 time=0.947 ms
64 bytes from 192.168.50.3: icmp_req=5 ttl=64 time=1.24 ms
64 bytes from 192.168.50.3: icmp_req=6 ttl=64 time=1.25 ms
64 bytes from 192.168.50.3: icmp_req=7 ttl=64 time=1.29 ms
64 bytes from 192.168.50.3: icmp_req=7 ttl=64 time=1.30 ms (DUP!)
64 bytes from 192.168.50.3: icmp_req=8 ttl=64 time=0.800 ms

--- 192.168.50.3 ping statistics ---
8 packets transmitted, 8 received, +1 duplicates, 0% packet loss, time 7156ms
rtt min/avg/max/mdev = 0.513/1.076/1.301/0.258 ms
Highlighted by the (DUP!) tag, we see that the seventh response was received two times.

Flipped bits

This arguably is the most dangerous type of error in a communication system: when random bits are flipped (0 becomes 1 and 1 becomes 0), the frame is considered corrupted and must be discarded. It's more dangerous than loss and duplication because frames must be checked and correctly recognized as clean or corrupt. The IEEE 802.3 standards defines an efficient technique of finding errors, called cyclic redundancy check (CRC), thus most corrupted frames will be discarded. At the application level, discarded packets (consequence of discarded frames) have the same effects of lost frames.

The field represents the probability of flipped bits occurring, although I am not sure on how this probability is defined. It probably is the total number of bits divided by the number of flipped bits. Targeted testing or reading the source code could help to solve this doubt.

This are the ping results with Flipped bits set to 0.05 in the outgoing direction.
[0 root@m1 ~]$ ping -c 6 192.168.50.3
PING 192.168.50.3 (192.168.50.3) 56(84) bytes of data.
64 bytes from 192.168.50.3: icmp_req=2 ttl=64 time=1.26 ms
64 bytes from 192.168.50.3: icmp_req=3 ttl=64 time=1.28 ms
64 bytes from 192.168.50.3: icmp_req=4 ttl=64 time=1.18 ms
64 bytes from 192.168.50.3: icmp_req=5 ttl=64 time=1.13 ms
64 bytes from 192.168.50.3: icmp_req=6 ttl=64 time=1.31 ms

--- 192.168.50.3 ping statistics ---
6 packets transmitted, 5 received, 16% packet loss, time 5019ms
rtt min/avg/max/mdev = 1.137/1.238/1.315/0.079 ms

Minimum delay and Maximum delay

These two values, expressed as time intervals in milliseconds, define the delay range. There many reasons for a long delay in real life, like overloaded routers and faults. A slightly increased simulated delay could also be used as a representation of very long cables.

My tests with ping showed that Marionnet is not very accurate in the calculation of increased delays. This is the result of a ping from m1 to m2, with cable d1 (that connects m1 and S1) having Minimum delay and Maximum delay set to 20 and 100 respectively, in both directions.
[0 root@m1 ~]$ ping -c 6 192.168.50.3
PING 192.168.50.3 (192.168.50.3) 56(84) bytes of data.
64 bytes from 192.168.50.3: icmp_req=1 ttl=64 time=180 ms
64 bytes from 192.168.50.3: icmp_req=2 ttl=64 time=79.4 ms
64 bytes from 192.168.50.3: icmp_req=3 ttl=64 time=41.4 ms
64 bytes from 192.168.50.3: icmp_req=4 ttl=64 time=111 ms
64 bytes from 192.168.50.3: icmp_req=5 ttl=64 time=52.8 ms
64 bytes from 192.168.50.3: icmp_req=6 ttl=64 time=3.41 ms

--- 192.168.50.3 ping statistics ---
6 packets transmitted, 6 received, 0% packet loss, time 5029ms
rtt min/avg/max/mdev = 3.413/78.254/180.835/56.610 ms
As ping calculates rtt (round trip time) and the delay, min is supposed to be greater than 40 ms and max possibly less than 200 ms. Unexpectedly, min is only 3.413 ms. I did other tests, which showed the same behaviour. This issue might have been fixed in the more recent releases of Marionnet.

Even though inaccurate, this feature is still useful for simulating long delays, especially very irregular ones.
 

Conclusion

After following these tutorials, it is your time to play with Marionnet and relativization. Learn more about network management or time-related problems and come back to test them out. Try to think of new ways to make use this software. Have fun!




6 comments:

  1. I enjoyed the tutorial, I am new to using the marionnet software and since it lacks good documentation this was a great way to get started with it. The only problem I had and am still having is that setting the static ip addresses and default gateway by modifying the interfaces file doesn't seem to work as advertised. I still need to configure the default gateway manually on each machine after every reboot to be able to ping across the router. Is there a step missing? I'm not sure what is wrong.

    Thanks for the tutorial though, it has been a great help.

    ReplyDelete
    Replies
    1. Hi, sorry for my late reply but I had trouble with the comments.
      You should add a line for the default gateway to the interfaces file, like this:

      gateway 192.168.1.1

      More info on setting a static IP in Debian can be found here: https://www.debian.org/doc/manuals/debian-reference/ch05.en.html#_the_network_interface_with_the_static_ip
      I updated the tutorial to include this piece of information. Thank you for your contribution, and let me know if this solves your problem!

      Delete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Great tutorial!

    ReplyDelete
  4. Hi, excellent tutorial, I have problems with the virtual machine filesystem debian wheezy, to start does not load the terminal emulator.

    ReplyDelete
    Replies
    1. Which version of marionnet are you using?

      Delete