{ "metadata": { "name": "", "signature": "sha256:31cb85e3cddf14c2715551013c2e5ec8148ee631c08a333dce4854a36deb942c" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Emulating Networks with Mininet" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*This notebook originally appeared as a blog post by Morten V. Pedersen on [blog.mortenvp.com](http://blog.mortenvp.com). The content is BSD-licensed.*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some time ago I came across [Mininet](http://mininet.org/) which allows us setup and emulate networks on a single machine. Mininet uses the [Linux container](http://en.wikipedia.org/wiki/LXC) technology (similar to [Docker](http://docker.com)) to run multiple lightweight isolated Linux environments on a single Linux host. I never had time to play with it, but recently I wanted to experiment with a new transport protocol and see how it reacted to lossy links and Mininet seemed like an good choice for emulating the network. \n", "\n", "Mininet seems quite popular for people how wants to emulate and experiment with newer networking concepts such as SDN (Software Defined Networks). Beause the overhead of running Linux containers is very low, it allows us to emulate large networks with many connected hosts on a single computer (unfeasible with virtual machines). But, it can also be used to emulated simple networks like point-to-point links, with some loss and delay characteristics. Which is what we will do here. Another great strength of Mininet is that it allows us to run existing applications over these networks. So for example on one emulated host I can open the Firefox browser and on another host a webserver. I can even connect hosts on my emulated network to the real network and let them speak to services on the Internet. How great is that!?\n", "\n", "Let get this thing up and running.\n", "\n", "## Installing mininet\n", "\n", "So the first thing we need to do is to install Mininet. There are a copule of options to choose from the easiest way it to use the prepared virtual machine. You can find additional instructions on how to set it up on the Mininet webpage [here](http://mininet.org/vm-setup-notes/). \n", "\n", "Note: The Mininet setup guide suggests that you add a \"Host-only Adapter\", when I initially tried this, it gave me a \"no host only network adapter selected\" error. This was resolve following the suggestions described [here](no host only network adapter selected).\n", "\n", "For some reason after booting the Mininet virtual machine the *host only* network was not brought up, the commands to make it accessible (run the following commands in the virtual machine):\n", "\n", "```\n", "sudo ip link set dev eth1 up\n", "sudo dhclient eth1\n", "ip link show\n", "```\n", "\n", "First we bring up the interface, then ask for an IP using DHCP and finally we show the available interfaces and their IPs.\n", "\n", "Alternatively you can add the following to `/etc/network/interfaces` inside the virtual machine:\n", "\n", "```\n", "auto eth1\n", "iface eth1 inet dhcp\n", "```\n", "\n", "Now I could ssh from my machine to the Mininet virtual machine using:\n", "\n", "```\n", "ssh mininet@192.168.56.101\n", "```\n", "\n", "To make things a bit easier I add the following to `.ssh/config`:\n", "\n", "```\n", "Host mininet\n", "User mininet\n", "HostName 192.168.56.101\n", "```\n", "\n", "Now I can login using ``ssh mininet``, see the bottom of the [Mininet VM setup notes](http://mininet.org/vm-setup-notes/) guide to see how to setup password less login.\n", "\n", "### Shared folders\n", "\n", "To make it easier to move files between the virtual machine and the host computer you can setup a shared folder. In Virtualbox go to the settings for the Mininet virtual machine and you should be able to select a host folder that you want to share in the virtual machine. In my case is just created a folder called `vm_mininet` in my home directory. \n", "\n", "To access shared folders inside the virtual machine we need to install the Virtualbox Guest Additions. Fortunately there is a package for that, so inside the Mininet virtual machine run:\n", "\n", "```\n", "sudo apt-get install virtualbox-guest-utils\n", "```\n", "\n", "As a final step you need to add the `mininet` user to the `vboxsf` group to have access to the folder:\n", "\n", "```\n", "usermod -aG vboxsf mininet\n", "```\n", "\n", "Rebooting the virtual machine, and my shared folder shows up under `/media/sf_vm_mininet`. \n", "\n", "\n", "## Creating the network\n", "\n", "Now that we have the Mininet virtual machine up and running we can start to emulate some networks. One of the really cool things about Mininet is how easy it is to define network topologies using Python scripts. As an example lets try to create a network with two hosts and ping from one to the other.\n", "\n", "The script for setting this up is available [here](https://cdn.rawgit.com/mortenvp/mortenvp-pelican/master/content/notebooks/emulating_networks_with_mininet/simple_ping.py). The `%%file simple_ping.py` is an iPython cell magic command that will save the content of the cell to a file called `simple_ping.py`, so that we later can runn the script in our Mininet virtual machine.\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%%file simple_ping.py\n", "#!/usr/bin/python\n", "\n", "\"\"\"\n", "Simple example of point-to-point link running ping\n", "\"\"\"\n", "\n", "from mininet.topo import Topo\n", "from mininet.net import Mininet\n", "from mininet.node import OVSController\n", "from mininet.link import TCLink\n", "from mininet.util import pmonitor\n", "from mininet.log import setLogLevel\n", "\n", "if __name__ == '__main__':\n", " setLogLevel('info')\n", "\n", " # Build the topology we want to play with:\n", " #\n", " # +-----------------------+\n", " # | 10Mbit/s link |\n", " # | 5ms delay |\n", " # | 10% packet loss |\n", " # | |\n", " # +-----------+-----------+\n", " # |\n", " # |\n", " # |\n", " # |\n", " # +-------------+ v +-------------+\n", " # | | | |\n", " # | host 1 (h1) +------------------+ host 2 (h2) |\n", " # | | | |\n", " # +-------------+ +-------------+\n", " # \n", " topo = Topo()\n", " topo.addHost('h1')\n", " topo.addHost('h2')\n", " topo.addLink('h1','h2', bw=10, delay='5ms', loss=10)\n", "\n", " # The TCLink is needed for use to set the bandwidth, delay and loss\n", " # constraints on the link\n", " #\n", " # waitConnected\n", " net = Mininet(topo=topo,\n", " link=TCLink,\n", " waitConnected=True)\n", " net.start()\n", "\n", " h1, h2 = net.getNodeByName('h1', 'h2')\n", "\n", " # Will open the two ping processes on both hosts and read the output\n", " popens = {}\n", " popens[h1] = h1.popen('ping -c10 {}'.format(h2.IP()))\n", " popens[h2] = h2.popen('ping -c10 {}'.format(h1.IP()))\n", "\n", " for host, line in pmonitor(popens):\n", " if host:\n", " # Output each line written as \": some output\", where X\n", " # will be replaced by the host number i.e. 1 or 2.\n", " print(\"<{}>: {}\".format(host.name, line.strip()))\n", "\n", " net.stop()\n" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Overwriting simple_ping.py\n" ] } ], "prompt_number": 8 }, { "cell_type": "markdown", "metadata": {}, "source": [ "To run the above network simply copy the `simple_ping.py` file to the Mininet virtual machine and run it (e.g. using the shared folder):\n", "\n", "```\n", "sudo ./simple_ping.py\n", "```\n", "\n", "The script should now generate a bunch of output, giving you diagnostics about the network and output from the two ping processes.\n", "\n", "```\n", "mininet@mininet-vm:/media/sf_vm_mininet$ sudo ./simple_ping.py \n", "*** Creating network\n", "*** Adding controller\n", "*** Adding hosts:\n", "h1 h2 \n", "*** Adding switches:\n", "\n", "*** Adding links:\n", "(10.00Mbit 5ms delay 10% loss) (10.00Mbit 5ms delay 10% loss) (h1, h2) \n", "*** Configuring hosts\n", "h1 h2 \n", "*** Starting controller\n", "c0 \n", "*** Starting 0 switches\n", "\n", "*** Waiting for switches to connect\n", "\n", "

: PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.\n", "

: 64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=12.5 ms\n", "

: PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.\n", "

: 64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=17.8 ms\n", "

: 64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=10.4 ms\n", "

: 64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=10.2 ms\n", "

: 64 bytes from 10.0.0.2: icmp_seq=3 ttl=64 time=10.2 ms\n", "

: 64 bytes from 10.0.0.1: icmp_seq=3 ttl=64 time=10.2 ms\n", "

: 64 bytes from 10.0.0.2: icmp_seq=4 ttl=64 time=10.2 ms\n", "

: 64 bytes from 10.0.0.1: icmp_seq=4 ttl=64 time=10.2 ms\n", "

: 64 bytes from 10.0.0.1: icmp_seq=5 ttl=64 time=10.1 ms\n", "

: 64 bytes from 10.0.0.1: icmp_seq=6 ttl=64 time=10.2 ms\n", "

: 64 bytes from 10.0.0.2: icmp_seq=6 ttl=64 time=10.2 ms\n", "

: 64 bytes from 10.0.0.1: icmp_seq=7 ttl=64 time=10.1 ms\n", "

: 64 bytes from 10.0.0.1: icmp_seq=8 ttl=64 time=10.1 ms\n", "

: 64 bytes from 10.0.0.2: icmp_seq=8 ttl=64 time=10.1 ms\n", "

: 64 bytes from 10.0.0.1: icmp_seq=9 ttl=64 time=10.1 ms\n", "

: 64 bytes from 10.0.0.2: icmp_seq=9 ttl=64 time=11.0 ms\n", "

: 64 bytes from 10.0.0.1: icmp_seq=10 ttl=64 time=10.1 ms\n", "

: \n", "

: --- 10.0.0.1 ping statistics ---\n", "

: 10 packets transmitted, 10 received, 0% packet loss, time 9014ms\n", "

: rtt min/avg/max/mdev = 10.139/10.442/12.594/0.725 ms\n", "

: 64 bytes from 10.0.0.2: icmp_seq=10 ttl=64 time=10.1 ms\n", "

: \n", "

: --- 10.0.0.2 ping statistics ---\n", "

: 10 packets transmitted, 8 received, 20% packet loss, time 9024ms\n", "

: rtt min/avg/max/mdev = 10.144/11.294/17.819/2.484 ms\n", "*** Stopping 1 controllers\n", "c0 \n", "*** Stopping 0 switches\n", "\n", "*** Stopping 1 links\n", "\n", "*** Stopping 2 hosts\n", "h1 h2 \n", "*** Done\n", "```\n", "\n", "Pretty cool right? \n", "\n", "The code was tested with Mininet version `2.2.0`, to see which version you have run: \n", "\n", "```\n", ">>> import mininet\n", ">>> print(mininet.net.VERSION)\n", "2.2.0\n", "```\n", "\n", "For more examples see the official [Mininet examples](https://github.com/mininet/mininet/tree/master/examples). Also you can find lots more information on the API etc. on the Mininet pages. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*This blog post was written entirely in the IPython Notebook. The full notebook can be downloaded\n", "[here](https://cdn.rawgit.com/mortenvp/mortenvp-pelican/master/content/notebooks/emulating_networks_with_mininet/emulating_networks_with_mininet.ipynb),\n", "or viewed statically\n", "[here](http://nbviewer.ipython.org/url/github.com/mortenvp/mortenvp-pelican/blob/master/content/notebooks/emulating_networks_with_mininet/emulating_networks_with_mininet.ipynb).*" ] } ], "metadata": {} } ] }