Mininet is a very powerful virtual network emulation system that’s generally used in SDN development environments. With Mininet, a complex network with hundreds of switches can be simulated in a laptop and this opens up testing real-life network usecases. I have covered Mininet usage in 1 of my earlier blogs on tools used with Opendaylight. I have always wondered about how Mininet works under the hood. Recently, i went through a Stanford webinar which shed details on the Mininet internals. In this blog, I will cover Mininet internals along with a sample network that I tried out. 1 of the key concepts used in Mininet is Network namespaces which is also the basis for Linux containers. I will also cover briefly about Network namespaces in this blog.
Network Namespaces:
Network namespaces allows for creation of virtual networking domain with its own set of interfaces, ip addresses, routing table etc. This is similar to VRF in Cisco terminology. Network namespaces connect to outside world using virtual ethernet links. Virtual ethernet link is a wire with 2 endpoints, typically 1 end point is located in local namespace and another in global namespace. Network namespaces are also used in Docker and Openstack Neutron. With Openstack neutron, Network namespaces allows for isolating tenants as well as to have overlapping IP addresses.
Mininet internals:
Mininet uses the following Linux concepts:
- Network namespaces are used to implement hosts or endpoints. Each host will have its own set of interfaces, IP and routing table.
- Openvswitch or Linux switch is used to implement switches. Openvswitch is used by default. Openflow is used to program data path and ovsdb is used for setting up configuration on Openvswitch.
- Controller could be any Openflow controller like Opendaylight, Floodlight etc.
- For controlling link characteristics like bandwidth, latency, Linux tc tool is used.
- For limiting CPU usage of individual namespaces, Linux cpu groups is used.
- Mininet uses a Python wrapper on top of the above tools as well as other Linux tools like perf to present a high level abstraction.
Hands-on:
To try out the different concepts above, I have the following environment:
- Ubuntu 12.04
- Opendaylight controller helium release.
- Openvswitch 2.1.3
- Mininet 2.1.0
I want to create a sample network with 2 hosts and 1 switch and connect the switch to Opendaylight controller to allow forwarding between the 2 hosts through the switch. Instead of setting up this network using Mininet which can be done using simple CLI like “mn –controller=remote,ip=127.0.0.1,port=6633”, I am going to set up this network using raw Linux CLI.
Following picture shows what we are trying to do.
Following set of commands will accomplish the above network. Comments above each step provides more details.
# 1. Create 2 namespaces ip netns add h1 ip netns add h2 # 2. Create openvswitch ovs-vsctl add-br s1 # 3. Create vethernet links ip link add h1-eth1 type veth peer name s1-eth1 ip link add h2-eth1 type veth peer name s1-eth2 # 4. Move host ports into namespaces ip link set h1-eth1 netns h1 ip link set h2-eth1 netns h2 # 5. Connect switch ports to OVS ovs-vsctl add-port s1 s1-eth1 ovs-vsctl add-port s1 s1-eth2 # 6. Connect controller to switch ovs-vsctl set-controller s1 tcp:127.0.0.1 # 7. Setup ip ip netns exec h1 ifconfig h1-eth1 10.1 ip netns exec h1 ifconfig lo up ip netns exec h2 ifconfig h2-eth1 10.2 ip netns exec h2 ifconfig lo up ifconfig s1-eth1 up ifconfig s1-eth2 up
After this step, following are some interesting outputs:
List namespaces:
>ip netns list h2 h1
Ifconfig of the individual namespaces:
>ip netns exec h1 ifconfig h1-eth1 Link encap:Ethernet HWaddr b6:9b:eb:d7:78:b8 inet addr:10.0.0.1 Bcast:10.255.255.255 Mask:255.0.0.0 inet6 addr: fe80::b49b:ebff:fed7:78b8/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:71 errors:0 dropped:39 overruns:0 frame:0 TX packets:9 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:9593 (9.5 KB) TX bytes:650 (650.0 B) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) >ip netns exec h2 ifconfig h2-eth1 Link encap:Ethernet HWaddr 22:45:e0:64:61:67 inet addr:10.0.0.2 Bcast:10.255.255.255 Mask:255.0.0.0 inet6 addr: fe80::2045:e0ff:fe64:6167/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:69 errors:0 dropped:40 overruns:0 frame:0 TX packets:9 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:9348 (9.3 KB) TX bytes:650 (650.0 B) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Links in h1, h2, global namespace:
> ip link list 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: eth3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 08:00:27:84:31:d4 brd ff:ff:ff:ff:ff:ff 3: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN link/ether 92:2a:6e:49:a2:19 brd ff:ff:ff:ff:ff:ff 4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff 11: ovs-system: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN link/ether 7a:70:25:24:54:33 brd ff:ff:ff:ff:ff:ff 90: s1: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN link/ether 9a:e3:67:6e:bb:49 brd ff:ff:ff:ff:ff:ff 91: s1-eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether ca:a5:ad:75:76:59 brd ff:ff:ff:ff:ff:ff 93: s1-eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether da:27:58:38:94:dd brd ff:ff:ff:ff:ff:ff > ip netns exec h1 ip link list 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 92: h1-eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether b6:9b:eb:d7:78:b8 brd ff:ff:ff:ff:ff:ff > ip netns exec h2 ip link list 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 94: h2-eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 22:45:e0:64:61:67 brd ff:ff:ff:ff:ff:ff
Switch details:
ovs-vsctl show 6accb155-3a7c-46f1-851d-ac9905116b5d Bridge "s1" Controller "tcp:127.0.0.1" is_connected: true Port "s1-eth1" Interface "s1-eth1" Port "s1" Interface "s1" type: internal Port "s1-eth2" Interface "s1-eth2" ovs_version: "2.1.3"
Lets try to ping between the namespaces from h1 to h2. Ping is successful.
> ip netns exec h1 ping -c1 10.2 PING 10.2 (10.0.0.2) 56(84) bytes of data. 64 bytes from 10.0.0.2: icmp_req=1 ttl=64 time=0.456 ms --- 10.2 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.456/0.456/0.456/0.000 ms
In the Opendaylight controller helium release, I have installed L2 switch module that allows the topology to be learnt automatically and the controller adds Openflow entries to allow the switching to happen. Following are the Openflow entries in the switch. The first 2 flows are the ones that allows for forwarding between 2 ports of the switch. The other flow entries are for punting control packets to CPU.
>ovs-ofctl dump-flows s1 NXST_FLOW reply (xid=0x4): cookie=0x2a0000000000001c, duration=809.205s, table=0, n_packets=3, n_bytes=182, idle_timeout=1800, hard_timeout=3600, idle_age=191, priority=10,dl_src=22:45:e0:64:61:67,dl_dst=b6:9b:eb:d7:78:b8 actions=output:1 cookie=0x2a0000000000001d, duration=809.205s, table=0, n_packets=2, n_bytes=140, idle_timeout=1800, hard_timeout=3600, idle_age=191, priority=10,dl_src=b6:9b:eb:d7:78:b8,dl_dst=22:45:e0:64:61:67 actions=output:2 cookie=0x2b00000000000017, duration=825.080s, table=0, n_packets=6, n_bytes=364, idle_age=196, priority=2,in_port=1 actions=output:2,CONTROLLER:65535 cookie=0x2b00000000000016, duration=825.080s, table=0, n_packets=6, n_bytes=412, idle_age=809, priority=2,in_port=2 actions=output:1,CONTROLLER:65535 cookie=0x2b00000000000015, duration=829.033s, table=0, n_packets=0, n_bytes=0, idle_age=829, priority=100,dl_type=0x88cc actions=CONTROLLER:65535 cookie=0x2b00000000000015, duration=829.066s, table=0, n_packets=11, n_bytes=854, idle_age=819, priority=0 actions=drop
To illustrate effects of link delay, we can use tc utility to increase latency of the link:
> tc qdisc add dev s1-eth2 root handle 5: netem delay 50ms
If we run the ping test again, we see the following result. Ping has increased latency by 50ms now.
> ip netns exec h1 ping -c1 10.2 PING 10.2 (10.0.0.2) 56(84) bytes of data. 64 bytes from 10.0.0.2: icmp_req=1 ttl=64 time=50.2 ms --- 10.2 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 50.260/50.260/50.260/0.000 ms
To change the bandwidth of link, following is 1 example:
tc qdisc add dev s1-eth2 root handle 5: tbf rate 100Mbit burst 5mb latency 12ms
To see the effect of link bandwidth change, we can run the iperf tool between the 2 hosts and check it out.
To cleanup all the previous configuration including namespaces, we can do the following:
ip netns delete h1 ip netns delete h2 tc qdisc del dev s1-eth2 root ip link delete s1-eth1 ip link delete s1-eth2 ovs-vsctl del-br s1
In conclusion, Network namespaces allows us to achieve some cool stuff and Mininet is a great example.
References:
- Mininet Introduction
- Stanford Netseminar on Mininet
- Scott’s blog on Namespaces – 1 and 2
- Linux traffic shaping articles – 1 and 2
- Interconnecting namespaces
Sreeni Boss, This post is very useful.But if use mininet tool to create the topoloy, i am unable to see the network namespaces created by mininet. I followed as below,
1. sudo mn –controller remote,ip=127.0.0.1 –topo tree,2
2. sudo ip netns list (nothing is listed, empty. Also i tried in /var/run/netns (dir is empty))
Please suggest, waiting your reply.
Thanks for the great post.
Regards
Senthil
Eagerly awaiting for your reply :), Checking daily.
hi Senthil
Mininet uses nameless network namespace, so it doesnt list in netns list. I think the latest version might have switched to named.
(https://mailman.stanford.edu/pipermail/mininet-discuss/2014-July/004827.html)
you can still see other things like links(ip link list), switches(ovs-vsctl show)
Regards
Sreenivas
Thanks a ton Sreeni!!!. If you can please tell me about how nameless namespace are working particularly with mininet, that will be great for me.
Again waiting for reply.
Thanks again!!!
what is the best way to test a load balancer for web servers in mininet ?