Monday, November 18, 2013

Execution and Surprises

We decided to filter the packets based on the network number of the source packet as a first step. To do that we need to enhance the source of openvswitch and also Mininet. Why Mininet? It's because Mininet is like an interface between the users and the switch. We are going with the following command in the Mininet for specifying about the network split.

sudo python mn --controller=remote,192.168.1.10,192.168.1.11 --multictrl=s1:c0@c1,s2:c2 --netsplit=c0:172.16.10.0/24@172.16.11.0/24,c1:172.16.12.0/24

Why '@' for specifying multiple network numbers? Well, it's just for a start. We will make it to ':' soon as even we find it difficult to remember the input sequence. :P

Doing what we did for multictrl previously
Coming through, the following line is added in the file bin/mn class MininetRunner's parseArgs method.
    opts.add_option( '--netsplit', '-s', type='string', default=False,
        help='set the network splitting for multiple controllers')

Similary, the following line in the begin method of MininetRunner class.
    networkSplit = self.options.netsplit
and another parameter in the Net instance creation

    networkSplit=networkSplit
Going into the file mininet/net.py we added another parameter in the init method of the Mininet class, ie, networkSplit=False.

Knock knock, who is it? Redundancy!
Now, our objective is to prepare an associative array of controller to list of network numbers. But wait! Aren't we familiar with this operation? Yes we are! We did the same thing for switchControlPair method in the following post. So, as we learned about the importance of redundancy while going through the source, we were delighted to experience it as we wouldn't have to rethink or rewrite the code (except for renaming the method from switchControlPair to pairGenerate for being generic).

As of now this is where we have stopped in Mininet. We are looking into openvswitch to see how source IP could be put into use for deciding the controller it should forward to. And also, we will use ovs-vsctl command for creating files containing the network splitting information via OpenVSwitch. We will post about the changes made in the OpenVSwitch in the coming post for the file creation and then come back to Mininet as it will use the same commands that we wrote for OpenVSwitch.

So till then, adios Mininet! See ya later.

Thursday, November 14, 2013

Controller or OpenVswitch?

As you guys saw in the last blog, our modified Mininet can have switches connected to multiple controllers based on the input the user specifies. But there is a problem here!

Look at this output:
[...]

h1 ping h2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_req=1 ttl=64 time=104 ms
64 bytes from 10.0.0.2: icmp_req=1 ttl=64 time=105 ms (DUP!)
64 bytes from 10.0.0.2: icmp_req=1 ttl=64 time=143 ms (DUP!)
64 bytes from 10.0.0.2: icmp_req=1 ttl=64 time=143 ms (DUP!)
64 bytes from 10.0.0.2: icmp_req=2 ttl=64 time=0.432 ms
64 bytes from 10.0.0.2: icmp_req=3 ttl=64 time=0.058 ms

[...]

What is this (DUP!) packets?
 It means the reply packet is a duplicate. Each ICMP packet sent out to ping a host has a sequence number that is returned with the response.
   The reason why we are getting duplicate packets is because when host,h1, pings host, h2, the ping packets is sent to switch S1. Switch, by default forwards this new packet to all the connected controllers as it does not have a flow entry for this new packet. The controllers are configured in a way that both of them give the same flow. So the host is getting multiple packets consisting of same flow thus generating a DUP packet.


Well, this is not a good sign of progress :( For one thing we are getting duplicate packets, which is generally considered as a phenomenon of faulty networks, and also when you think about it, there is a lot of bandwidth wasted. In the example, switch was connected only to 2 controllers but imagine if it was connected to 100 controllers and for every new packet, it is broadcasting to all those controllers!! That will be one heck of a nightmare.

    In order to solve this problem, we have to either go to the controller and build a mechanism where in the actions specify that switch should talk to specific controller for specific packets. Or we have to modify OpenVswitch such that, given a packet, it will decide which controller to forward to based on the specifications we configure it with. So we are going the latter approach i.e., we are diving into OpenVswitch and modifying it such that whenever a packet in action takes place, the switch will know which controller to send it; thus avoiding the broadcasting.

In the next blog, you will see how we are going to divide the network and configure OpenVswitch such that it will forward each packet to  single controller.

Tuesday, November 12, 2013

Modifying the Source Code

Previously we handled the error that we faced in the Mininet constructor. Following are the 2 information that is needed by Mininet software in order to establish a connection to multiple controllers:
  • Controllers to which Mininet should connect
  • Which switches are connected to which controllers
We will describe point by point and see what we did to achieve it.

1. Specifying multiple remote controllers for Mininet


You mention about the remote controller using --controller=remote,<ip_addr_of_controller>. We thought of extending the same method for specifying multiple IP addresses. Hence, the format we have specified is:
--controller=remote,<ipaddr1>,<ipaddr2>,<ipaddr3>" and so on.
Now, since there is a variation in the input style, we also have to manage the underlying code.

After the command-line parsing in parseArgs() method, the string passed in the RHS of = in the command-line is made available via self.options.controller. We modified the controller creation code with the following:

So,
controller = customConstructor( CONTROLLERS, self.options.controller )

was transformed to:
[...]
if self.options.controller.split(',')[0] == 'remote':
    controller = list()
    length = len(self.options.controller.split(',')) - 1
    addresses = self.options.controller.split(',')[1:]
    for i in range (0, length):
        controller.append(customConstructor( CONTROLLERS, 'remote,%s' % addresses[i] ) )
else:
    controller = customConstructor( CONTROLLERS, self.options.controller )

[...]
With no intention to disturb the underlying method of customConstructor, we decided to create the controllers one at a time in a loop. Therefore, we first split the left most argument to check if it is remote. If it isn't, it would go back as how normally the controllers are created using customConstructor. If it was remote controller, we further segragate the remaining ip addresses passed by
addresses = self.options.controller.split(',')[1:]
and then append each address into customConstructor in the loop using
controller.append(customConstructor( CONTROLLERS, 'remote,%s' % addresses[i] ) )
Well, this way it's easy to test too. If the user passed a single address, then controller is just an instance of type customConstructor. If he passed multiple addresses, then controller is a list.

2. Switch to Controller association


For this association, we added multictrl as a command-line input. So a typical multictrl command would appear as:

--multictrl=s1:c0@c1,s2:c2 and so on.

Rules:
  • Use a switch name first followed by a colon, :, and then the controller name.
  • To mention 2 or more controllers then use '@' in between, like, s1:c1@c2@c3
  • c0, c1 are actually controllers in which the remote controllers are written.
    For eg: --controller=remote,192.168.1.2,192.168.1.3, c0 will take the value as 192.168.1.2 and c1 will take the value as 192.168.1.3
Everything in the RHS of = in multictrl command-line is passed into the __init__ of the Mininet class. Now we have to parse the input and create a dictionary as described in the previous post. So, we added the following line into the __init__ method:
self.multiCtrl = switchControlPair( multiCtrl ) if multiCtrl else False

and defined switchControlPair in util.py, where all utility methods are written. The switchControlPair will convert the string s1:c0@c1,s2:c1 into a dictionary as {'s1':['c0', 'c1'], 's2':['c1']} and return this dictionary. This returned dictionary is of not much use to us, we have to create an association between the switch and the controller object, not string. So we will setup another associative array where we will have the controller associated to switch name. So, in the addController method of the same class Mininet, we added the following lines:
[...]
if self.multiCtrl is not False:
    for switchName, controlList in self.multiCtrl.items():
        switchKeys = self.switchToCtrl.keys()
        if name in controlList:
            if switchName not in switchKeys:
                self.switchToCtrl[ switchName ] = list()
            self.switchToCtrl[switchName].append(controller_new)
[...]
In the above lines, we collect switchName will be the key and controlList will be the list of controller names. We have another empty associative array called self.switchToCtrl defined in the __init__. We then check the existence of the controller object's "name" created in this method with those in that controlList. If they exist then we check if switchName exists in the keys of switchToCtrl dictionary, switchKeys. If they don't, we create a list() against the switch name, and start appending.

In buildFromTopo() method where addController is called, there is a comparison that was already present in the source to check if the controllers taken from user is a list or not, if not then make it to a list. So since we passed the controller as a list in case of multiple remote controllers, we don't have to bother much.
[...]
   #the snippet converting the controller variable to a list
   classes = self.controller
   if type( classes ) is not list:
       classes = [ classes ]
   for i, cls in enumerate( classes ):
       self.addController( 'c%d' % i, cls )

[...]
The for loop then iterates to add those many controllers in the list.
We know that the changes made is consuming more memory, as in, we are associating a copy of the controller object into switchToCtrl. Also we know that we are doing double work of first creating an associative array of strings to strings and using the same for strings to controller objects. Better memory usage and implementation will be managed in further iterations when we confirm that our logic is meeting the results.

The next post will address the execution of the changes made in the code and their results.