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 Machine → Start → 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!