Mininet Internals and Network Namespaces

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.

mininet1

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:

5 thoughts on “Mininet Internals and Network Namespaces

  1. 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

      1. 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!!!

Leave a comment