Professional Documents
Culture Documents
Introduction To Mininet
Introduction To Mininet
Pages 64
Mininet
Get Started
Sample Workflow
Walkthrough
Overview
Download
Documentation
Videos
Source Code
Apps
FAQ
Wiki
Teaching
Papers
Support
Contribute
News
Credits
https://githu
This document is meant to give you a brief sense of what Mininet is and how it works, including
a basic introduction to Mininet's Python API, the core of Mininet's functionality that you will
usually want to use to create networks and run experiments.
What is Mininet?
Why is Mininet cool?
What are Mininet's limitations?
Working with Mininet
o Creating Topologies
o Setting Performance Parameters
o Running Programs in Hosts
o New: popen()/pexec() interface
o Host Configuration Methods
o Naming in Mininet
o Customizing mn using --custom files
o Additional Examples
Understanding the Mininet API
Mininet API Documentation
Measuring Performance
OpenFlow and Custom Routing
o OpenFlow Controllers
o External Controllers
o Multipath Routing
Updating Mininet
Learning Python
Useful Background Information
Useful Python Resources
How Does It Really Work? (optional: for the curious)
What is Mininet?
Mininet is a network emulator, or perhaps more precisely a network emulation orchestration
system. It runs a collection of end-hosts, switches, routers, and links on a single Linux kernel. It
uses lightweight virtualization to make a single system look like a complete network, running the
same kernel, system, and user code. A Mininet host behaves just like a real machine; you can
ssh into it (if you start up sshd and bridge the network to your host) and run arbitrary programs
(including anything that is installed on the underlying Linux system.) The programs you run can
send packets through what seems like a real Ethernet interface, with a given link speed and
delay. Packets get processed by what looks like a real Ethernet switch, router, or middlebox, with
a given amount of queueing. When two programs, like an iperf client and server, communicate
through Mininet, the measured performance should match that of two (slower) native machines.
In short, Mininet's virtual hosts, switches, links, and controllers are the real thing – they are just
created using software rather than hardware – and for the most part their behavior is similar to
discrete hardware elements. It is usually possible to create a Mininet network that resembles a
hardware network, or a hardware network that resembles a Mininet network, and to run the same
binary code and applications on either platform.
Running on a single system is convenient, but it imposes resource limits: if your server
has 3 GHz of CPU and can switch about 10 Gbps of simulated traffic, those resources
will need to be balanced and shared among your virtual hosts and switches.
Mininet uses a single Linux kernel for all virtual hosts; this means that you can't run
software that depends on BSD, Windows, or other operating system kernels. (Although
you can attach VMs to Mininet.)
Mininet won't write your OpenFlow controller for you; if you need custom routing or
switching behavior, you will need to find or develop a controller with the features you
require.
By default your Mininet network is isolated from your LAN and from the internet - this is
usually a good thing! However, you may use the NAT object and/or the --nat option to
connect your Mininet network to your LAN via Network Address Translation. You can
also attach a real (or virtual) hardware interface to your Mininet network (see
examples/hwintf.py for details.)
By default all Mininet hosts share the host file system and PID space; this means that you
may have to be careful if you are running daemons that require configuration in /etc, and
you need to be careful that you don't kill the wrong processes by mistake. (Note the
bind.py example demonstrates how to have per-host private directories.)
Unlike a simulator, Mininet doesn't have a strong notion of virtual time; this means that
timing measurements will be based on real time, and that faster-than-real-time results
(e.g. 100 Gbps networks) cannot easily be emulated.
An aside on performance: The main thing you have to keep in mind for network- limited
experiments is that you will probably need to use slower links, for example 10 or 100 Mb/sec
rather than 10 Gb/sec, due to the fact that packets are forwarded by a collection of software
switches (e.g. Open vSwitch) that share CPU and memory resources and usually have lower
performance than dedicated switching hardware. For CPU-limited experiments, you will also
need to make sure that you carefully limit the CPU bandwidth of your Mininet hosts. If you
mainly care about functional correctness, you can run Mininet without specific bandwidth limits
- this is the quick and easy way to run Mininet, and it also provides the highest performance at
the expense of timing accuracy under load.
With a few exceptions, many limitations you may run into will not be intrinsic to Mininet;
eliminating them may simply be a matter of code, and you are encouraged to contribute any
enhancements you may develop!
Creating Topologies
Mininet supports parametrized topologies. With a few lines of Python code, you can create a
flexible topology which can be configured based on the parameters you pass into it, and reused
for multiple experiments.
Note that this is the recommended (simplified) topology syntax introduced in Mininet 2.2:
#!/usr/bin/python
class SingleSwitchTopo(Topo):
"Single switch connected to n hosts."
def build(self, n=2):
switch = self.addSwitch('s1')
# Python's range(N) generates 0..N-1
for h in range(n):
host = self.addHost('h%s' % (h + 1))
self.addLink(host, switch)
def simpleTest():
"Create and test a simple network"
topo = SingleSwitchTopo(n=4)
net = Mininet(topo)
net.start()
print "Dumping host connections"
dumpNodeConnections(net.hosts)
print "Testing network connectivity"
net.pingAll()
net.stop()
if __name__ == '__main__':
# Tell mininet to print useful information
setLogLevel('info')
simpleTest()
Important classes, methods, functions and variables in the above code include:
build(): The method to override in your topology class. Constructor parameters (n) will be
passed through to it automatically by Topo.__init__().
addLink(): adds a bidirectional link to a topology (and returns a link key, but this is not
important). Links in Mininet are bidirectional unless noted otherwise.
pingAll(): tests connectivity by trying to have all nodes ping each other
setLogLevel( 'info' | 'debug' | 'output' ): set Mininet's default output level; 'info' is
recommended as it provides useful information.
Additional example code may be found in mininet/examples.
Note for earlier Mininet Versions The topology API has changed slightly across different
versions of Mininet. In 1.0, methods such as addSwitch and addHost were called add_switch
and add_host. Additionally, in both 1.0 and 2.0, the preferred method to override was __init__
rather than build:
class SingleSwitchTopo(Topo):
"Single switch connected to n hosts."
def __init__(self, n=2, **opts):
# Initialize topology and default options
Topo.__init__(self, **opts)
switch = self.addSwitch('s1')
# Python's range(N) generates 0..N-1
for h in range(n):
host = self.addHost('h%s' % (h + 1))
self.addLink(host, switch)
In addition to basic behavioral networking, Mininet provides performance limiting and isolation
features, through the CPULimitedHost and TCLink classes.
There are multiple ways that these classes may be used, but one simple way is to specify them as
the default host and link classes/constructors to Mininet(), and then to specify the appropriate
parameters in the topology. (You could also specify custom classes in the topology itself, or
create custom node and link constructors and/or subclasses.)
#!/usr/bin/python
class SingleSwitchTopo(Topo):
"Single switch connected to n hosts."
def build(self, n=2):
switch = self.addSwitch('s1')
for h in range(n):
# Each host gets 50%/n of system CPU
host = self.addHost('h%s' % (h + 1),
cpu=.5/n)
# 10 Mbps, 5ms delay, 10% loss, 1000 packet queue
self.addLink(host, switch,
bw=10, delay='5ms', loss=10, max_queue_size=1000,
use_htb=True)
def perfTest():
"Create network and run simple performance test"
topo = SingleSwitchTopo(n=4)
net = Mininet(topo=topo,
host=CPULimitedHost, link=TCLink)
net.start()
print "Dumping host connections"
dumpNodeConnections(net.hosts)
print "Testing network connectivity"
net.pingAll()
print "Testing bandwidth between h1 and h4"
h1, h4 = net.get('h1', 'h4')
net.iperf((h1, h4))
net.stop()
if __name__ == '__main__':
setLogLevel('info')
perfTest()
self.addHost(name, cpu=f):
This allows you to specify a fraction of overall system CPU resources which will be allocated to
the virtual host.
You may find it useful to create a Python dictionary to make it easy to pass the same parameters
into multiple method calls, for example:
This same technique (**dict) is useful for passing options to Matplotlib and other libraries.
net.get(): retrieves a node (host or switch) object by name. This is important if you want to
send a command to a host (e.g. using host.cmd()) and get its output.
Note: In the current master branch of Mininet, you can simply use braces (e.g. net['h1']) to
retrieve a given node by name.
Each Mininet host is essentially a bash shell process attached to one or more network interfaces,
so the easiest way to interact with it is to send input to the shell using the cmd() method.
To run a command in a host and get the output, use the cmd() method.
h1 = net.get('h1')
result = h1.cmd('ifconfig')
print result
In many cases, you will wish to run a command in the background for a while, stop the
command, and save its output to a file:
Note that we used the shell's output redirection feature to send output to /tmp/date.out, the
background execution feature & of the shell to run the command in the background, and job
control kill %while to shut down the program that is running in the background. Unfortunately,
if you leave jobs running in the background they are not guaranteed to stop if Mininet exits
(either intentionally or due to an error), so you will need to make sure that you stop all of your
jobs cleanly. You may wish to use the ps command periodically to make sure that no zombie
jobs are mindlessly marching onward and slowing down your EC2 instance.
(Note: Python strings may be delimited using either single or double quotes. The example above
uses double quotes in print statements and single quotes for function arguments, but you can do
whatever you like. Python's print statement exists for convenience and possibly to help BASIC
programmers feel more at home.)
Having a shell process at your disposal makes it easy to perform other tasks as well. For
example, you can find out the PID of a background command using
h1.cmd('wait', pid)
Note that this will only work for UNIX commands and not for commands (e.g. while, cd) which
are built into the bash shell itself (and don't have a separate pid!) Note also that each of these
commands executed in the foreground (no &) rather than the background (&) since we want to get
the output.
[Editorial: UNIX's (and bash's) abbreviations and special characters ($, !, &) date back to the
days of blazingly fast 300 bit per second "networks" and Teletype™ terminals that printed on
paper as you typed. Linux stuck with them for compatibility and because humans still type
slowly. bash sometimes provides more verbose equivalents, if you wish to use them.]
In addition to using the shell's wait mechanism, Mininet itself allows you to start a foreground
command using sendCmd() and then wait for it to complete at some later time using
waitOutput():
for h in hosts:
h.sendCmd('sleep 20')
…
results = {}
for h in hosts:
results[h.name] = h.waitOutput()
If you are sending output to a file, you may wish to monitor that file's contents interactively
while your test is running. The examples/multipoll.py example provides a function
monitorFiles() which implements one possible mechanism for monitoring multiple output
files. This simplifies the implementation of a test which interactively monitors output from
multiple hosts:
Warning: in Mininet 2.0.0, pmonitor() may return a number of blank lines after
receiving EOFs. This should now be fixed in the master branch.
Of course, you do not have to use pmonitor() - you can use Popen.communicate() (as long as
you don't have too many file descriptors) or select.poll() or any other mechanism that works.
One thing to keep in mind is that by default Mininet hosts share the root filesystem of the
underlying server. Usually this is a very good thing, since it is a huge pain (and slow) to create a
separate filesystem for each Mininet host (which you can do if you like and then chroot into it!)
Sharing the root filesystem also means that you almost never need to copy data between Mininet
hosts because it's already there.
One side-effect of this however is that hosts share the Mininet server's /etc directory. This
means that if you require specific configuration for a program (e.g. httpd) then you may need to
create different configuration files for each Mininet host and specify them as startup options to
the program that you are running.
Another side-effect is that you can have file collisions if you try to create the same file in the
same directory on multiple hosts.
If you need per-host private directories, you can specify them as options to Host, for example:
For example:
Naming in Mininet
In order to use Mininet effectively, it is important to understand its naming scheme for hosts,
switches and interfaces. Usually, hosts are called h1..hN and switches are called s1..sN. We
recommend that you follow this convention or a similar one. For clarity, interfaces belonging to
a node are named beginning with the node's name, for example h1-eth0 is host h1's default
interface, and s1-eth1 is switch s1's first data port. Host interfaces are only visible from within
the host itself, but switch data ports are visible in the "root" namespace (you can see them by
typing ip link show in another window while Mininet is running.) As a result, it's easy to
examine switch interfaces but slightly trickier to examine host interfaces, since you must tell the
host to do so (typically using host.cmd().)
CLI
Mininet includes a command-line interface (CLI) which may be invoked on a network, and
provides a variety of useful commands, as well as the ability to display xterm windows and to
run commands on individual nodes in your network. You can invoke the CLI on a network by
passing the network object into the CLI() constructor:
net = Mininet(SingleSwitchTopo(2))
net.start()
CLI(net)
net.stop()
Starting up the CLI can be useful for debugging your network, as it allows you to view the
network topology (with the net command), test connectivity (with the pingall command), and
send commands to individual hosts.
In addition to writing complete Mininet scripts in Python, you can also extend the mn command
line tool using the --custom option. This allows you to use mn to invoke your own custom
topology, switch, host, controller, or link classes. You can also define and invoke your own
system tests, and add new Mininet CLI commands.
To add new features which can be invoked using the mn command, you need to define a dict in
your --custom file based on the option type. The dict's keys are short names passed to the
appropriate option, and the values are the corresponding subclasses, constructors, or functions:
For example:
This adds the MyTopo class (or constructor) to the topos dictionary, allowing it to be used with
the --topo option, as well as a new test, mytest. Note that the test function is called with the
top-level Mininet object, and you can pass string or numeric parameters to MyTopo:
This will use mytopo as the default topology and invoke the mytest test.
This can be a very convenient one-line command to start up Mininet, run an end-to-end system
test (or multiple tests), and shut down Mininet. If an exception occurs, the standard Mininet
cleanup code will be invoked as mn usually does in that case.
Adding new CLI commands in a --custom file
Note that the command function name that you add to CLI should have the do_ prefix.
Additional Examples
The examples are intended to be educational as they demonstrate different ways that the Mininet
API may be used. We encourage you to try both reading the Python code and running the
examples themselves. If they don't work for some reason, see if you can figure out why!
You may find some of them (e.g. consoles.py) to be interesting demonstrations that you can
build upon.
In particular, you may find (miniedit.py) to be a particularly useful GUI for simple
experiments with Mininet.
Note: The examples are intended as instructional material to be read and understood, not as
complete, out-of-the-box solutions to whatever problem you may have. You may be able to use
some of the code with modification, but it's important to be able to examine and understand the
code.
Over the course of this introduction, you have been exposed to a number of Python classes which
comprise Mininet's API, including classes such as Topo, Mininet, Host, Switch, Link and their
subclasses. It is convenient to divide these classes into levels (or layers), since in general the
high-level APIs are built using the lower-level APIs.
It is valuable to understand each of the API levels. In general when you want to control nodes
and switches directly, you use the low-level API. When you want to start or stop a network, you
usually use the mid-level API (notably the Mininet class.)
Things become interesting when you start thinking about creating full networks. Full networks
can be created using any of the API levels (as seen in the examples), but usually you will want to
pick either the mid-level API (e.g. Mininet.add*()) or the high-level API (Topo.add*()) to
create your networks.
h1 = Host( 'h1' )
h2 = Host( 'h2' )
s1 = OVSSwitch( 's1', inNamespace=False )
c0 = Controller( 'c0', inNamespace=False )
Link( h1, s1 )
Link( h2, s1 )
h1.setIP( '10.1/8' )
h2.setIP( '10.2/8' )
c0.start()
s1.start( [ c0 ] )
print h1.cmd( 'ping -c1', h2.IP() )
s1.stop()
c0.stop()
net = Mininet()
h1 = net.addHost( 'h1' )
h2 = net.addHost( 'h2' )
s1 = net.addSwitch( 's1' )
c0 = net.addController( 'c0' )
net.addLink( h1, s1 )
net.addLink( h2, s1 )
net.start()
print h1.cmd( 'ping -c1', h2.IP() )
CLI( net )
net.stop()
As you can see, the mid-level API is a bit simpler because it doesn't require creation of a
topology class. The low-level and mid-level APIs are flexible and powerful, but may be less
convenient to reuse compared to the high-level Topo API.
Note also that in Mininet versions before 2.2.0 the high-level Topo doesn't support multiple links
between nodes, but the lower level APIs do. Currently Topo also doesn't concern itself with
which switches are controlled by which controllers (you can use a custom Switch subclass to do
this, as described above.) With the mid-level and low-level APIs, you can manually start the
switches if desired, passing the appropriate list of controllers to each switch.
Mininet includes Python documentation strings for each module and API call. These may be
accessed from Python's regular help() mechanism. For example,
python
>>> from mininet.node import Host
>>> help(Host.IP)
Help on method IP in module mininet.node:
This same documentation is also available on the Mininet web site at http://api.mininet.org.
You may wish to generate the HTML (and PDF) documentation yourself using doxypy:
Measuring Performance
These are recommended, though you’re free to use any tool you’re familiar with.
One of Mininet's most powerful and useful features is that it uses Software Defined
Networking. Using the OpenFlow protocol and related tools, you can program switches to do
almost anything you want with the packets that enter them. OpenFlow makes emulators like
Mininet much more useful, since network system designs, including custom packet forwarding
with OpenFlow, can easily be transferred to hardware OpenFlow switches for line-rate operation.
A tutorial for creating a simple learning switch using Mininet and OpenFlow may be found at:
https://github.com/mininet/openflow-tutorial/wiki
OpenFlow Controllers
If you run the mn command without specifying a controller, it will use the the ovsc
controller,ovs-controller, by default. This is equivalent to
This controller implements a simple Ethernet learning switch, and supports up to 16 individual
switches.
If you invoke the Mininet() constructor in your script without specifying a controller class, by
default it will use the Controller() class to create an instance of the Stanford/OpenFlow
reference controller, controller. Like ovs-controller, it turns your switches into simple
learning switches, but if you have installed controller using Mininet's install.sh -f script,
the patched version of controller should support a large number of switches (up to 4096 in
theory, but you'll probably max out your computing resources much earlier.) You can also select
the reference controller for mn by specifying --controller ref.
If you want to use your own controller, you can easily create a custom subclass of
Controller() and pass it into Mininet. An example can be seen in
mininet.controller.NOX(), which invokes NOX classic with a set of modules passed in as
options.
Here's a simple example of creating and using a custom POX Controller subclass:
#!/usr/bin/python
import os
if __name__ == '__main__':
setLogLevel( 'info' )
net = Mininet( topo=SingleSwitchTopo( 2 ), controller=POXBridge )
net.start()
net.pingAll()
net.stop()
Note that the above script is written so that it also can be used as a custom argument to mn for use
with different topologies and tests as well as the Mininet CLI:
If you look at the implementation of the NOX class in mininet/node.py, you will notice that it
can actually accept options to allow different modules to be started depending on what
arguments are passed into it, from the constructor or the mn command line.
Custom Controller() subclasses are the most convenient method for automatically starting and
shutting down your controller. It's easy to create start() and stop() methods so that Mininet
will automatically start and stop your controller as needed.
(For more information, check out this blog post.)
However, you may find it useful to connect Mininet to an existing controller that is already
running somewhere else, for example somewhere on your LAN, in another VM, or on your
laptop.
The RemoteController class acts as a proxy for a controller which may be running anywhere
on the control network, but which must be started up and shut down manually or by some other
mechanism outside of Mininet's direct control.
or if you prefer:
or even
Note that controller (like host and switch) in this case is a constructor, not an object (but see
below for additional info!) You can create a custom constructor in-line using partial or
lambda, or you can pass in your own function (which must take the name parameter and return a
controller object) or class (e.g. a subclass of RemoteController.)
You can also create multiple controllers and create a custom Switch() subclass which connects
to different controllers as desired:
You can also specify an external controller from the mn command line:
And get the behavior that you intended. Constructors are still permitted as well.
Multipath Routing
It's important to remember that Ethernet bridges (also known as learning switches) will flood
packets that miss in their MAC tables. They will also flood broadcasts like ARP and DHCP
requests. This means that if your network has loops or multiple paths in it, it will not work with
the default ovs-controller and controller controllers, nor NOX's pyswitch, nor POX's
l2_learning, which all act as learning switches/Ethernet bridges.
In spite of the obviousness of this issue, it has become a Frequently Asked Question.
More recent (and more complex) OpenFlow controllers do support multipath routing - consult
your controller's documentation to determine if any special configuration is required.
If you are building a fat-tree like topology, you may wish to take a look at RipLPOX, a basic
datacenter controller implemented using POX. You may be able to use it as a starting point for
your own custom multipath routing.
You may also wish to implement a custom Controller() subclass to invoke RipLPOX for
convenience.
(Or if you're truly daring/insane, you could even try importing Mininet and POX or RipLPOX
into a single Python script! But you probably don't want to do that.)
Updating Mininet
If we need to make changes or additions to Mininet to fix bugs or other problems, and you have
installed Mininet from source, you may wish to update your copy of Mininet. This is easily done
using one of two methods:
Update using symbolic links to Mininet source tree (makes it easy to update Mininet's python
code):
cd ~/mininet
git checkout master # assuming you want to update to the current master
branch
sudo make develop # this only needs to be done initially and when mnexec.c
changes
git fetch
git pull --rebase
Update copying Mininet source into /usr/lib/python... (allows you to delete or move Mininet
source tree):
cd ~/mininet
git checkout master # assuming you want to update to the current master
branch
git fetch
git pull --rebase
sudo make install
Learning Python
Mininet is written in Python and allows Python-based user scripts to interface with it.
Fortunately Python is one of the easiest computer languages to understand, learn, and use, due to
its (mostly) readable syntax, similarity to other object-oriented languages, and many useful
libraries. Once you reconcile yourself to its quirks (significant indentation, mandatory use of
self, runtime error checking, etc.) you may appreciate it as a very quick (if sometimes dirty)
way to crank out useful scripts and code.
There are a vast variety of free Python tutorials available on the internet, from books to complete
courses. The Python documentation at http://docs.python.org will also quickly become your
friend if it isn't already.
In addition to helping to locate Python tutorials, Google seems to work astoundingly well for
finding answers to Python questions, many of which are answered on http://stackoverflow.com.
http://docs.python.org/tutorial/modules.html
http://docs.python.org/library/subprocess.html http://docs.python.org/library/os.html]
https://github.com/amoffat/pbs
http://docs.python.org/library/re.html
5. Passing command line arguments to your script
http://docs.python.org/dev/library/argparse.html
http://matplotlib.sourceforge.net
http://docs.python.org/tutorial/index.html
2. Beginner’s guide:
http://www.python.org/about/gettingstarted
The magic behind Mininet’s illusion is a set of features built into Linux that allow a single
system to be split into a bunch of smaller “containers”, each with a fixed share of the processing
power, combined with virtual link code that allows links with accurate delays and speeds.
Internally, Mininet employs lightweight virtualization features in the Linux kernel, including
process groups, CPU bandwidth isolation, and network namespaces, and combines them with
link schedulers and virtual Ethernet links. These features yield a system that starts faster and
scales to more hosts than emulators which use full virtual machines.
For more details, see the Mininet website and our Mininet Publications.