Added arg3 to take care of 1.3 switches
diff --git a/TestON/drivers/common/cli/emulator/mininetclidriver.py b/TestON/drivers/common/cli/emulator/mininetclidriver.py
index 095bae7..b7e3694 100644
--- a/TestON/drivers/common/cli/emulator/mininetclidriver.py
+++ b/TestON/drivers/common/cli/emulator/mininetclidriver.py
@@ -73,9 +73,9 @@
  
             main.log.info(self.name+": building fresh mininet") 
             #### for reactive/PARP enabled tests
-            cmdString = "sudo mn " + self.options['arg1'] + " " + self.options['arg2'] +  " --mac --controller " + self.options['controller']
+            cmdString = "sudo mn " + self.options['arg1'] + " " + self.options['arg2'] +  " --mac --controller " + self.options['controller'] + " " + self.options['arg3']
             #### for proactive flow with static ARP entries
-            #cmdString = "sudo mn " + self.options['arg1'] + " " + self.options['arg2'] +  " --mac --arp --controller " + self.options['controller']
+            #cmdString = "sudo mn " + self.options['arg1'] + " " + self.options['arg2'] +  " --mac --arp --controller " + self.options['controller'] + " " + self.options['arg3']
             self.handle.sendline(cmdString)
             self.handle.expect(["sudo mn",pexpect.EOF,pexpect.TIMEOUT])
             while 1: 
@@ -839,15 +839,36 @@
                             onos_ports.append(port['portNumber']) 
                 mn_ports.sort()
                 onos_ports.sort()
-                if mn_ports == onos_ports:
+                #print "mn_ports[] = ", mn_ports
+                #print "onos_ports90 = ", onos_ports
+                
+                #if mn_ports == onos_ports:
+                    #pass #don't set results to true here as this is just one of many checks and it might override a failure
+
+                #For OF1.3, the OFP_local port number is 0xfffffffe or 4294967294 instead of 0xfffe or 65534 in OF1.0, ONOS topology
+                #sees the correct port number, however MN topolofy as read from line 151 of https://github.com/ucb-sts/sts/blob/
+                #topology_refactoring2/sts/entities/teston_entities.py is 0xfffe which doesn't work correctly with OF1.3 switches.
+                #So a short term fix is to ignore the case when mn_port == 65534 and onos_port ==4294967294.
+                for mn_port,onos_port in zip(mn_ports,onos_ports):
+                    if mn_port == onos_port or (mn_port == 65534 and onos_port ==4294967294):
+                        continue
+                    else:
+                        port_results = main.FALSE
+                        break
                     pass #don't set results to true here as this is just one of many checks and it might override a failure
+                '''
                 else: #the ports of this switch don't match
                     port_results = main.FALSE
                     main.log.report("ports in MN switch %s(%s) but not in ONOS:" % (switch['name'],switch['dpid'])) 
                     main.log.report( str([port for port in mn_ports if port not in onos_ports]))
                     main.log.report("ports in ONOS switch %s(%s) but not in MN:" % (switch['name'],switch['dpid']))
                     main.log.report( str([port for port in onos_ports if port not in mn_ports]))
-
+                '''
+                if port_results == main.FALSE:
+                    main.log.report("ports in MN switch %s(%s) but not in ONOS:" % (switch['name'],switch['dpid'])) 
+                    main.log.report( str([port for port in mn_ports if port not in onos_ports]))
+                    main.log.report("ports in ONOS switch %s(%s) but not in MN:" % (switch['name'],switch['dpid']))
+                    main.log.report( str([port for port in onos_ports if port not in mn_ports]))
 
         #######Links########
         # iterate through MN links and check if and ONOS link exists in both directions
@@ -911,27 +932,6 @@
         return results
 
 
-    def links_status(self):
-        """
-        Returns list of links and their status
-        """
-        if self.handle :
-            cmd = "py 'Links: %s' % [item for sublist in [[(y[0].name, y[1].name, y[0].isUp() and y[1].isUp()) for y in x[0].connectionsTo(x[1])] for x in __import__('itertools').permutations(net.nameToNode.values(), 2) if x[0] != x[1] and x[0].connectionsTo(x[1])] for item in sublist]"
-            try:
-                response = self.execute(cmd=cmd,prompt="mininet>",timeout=10)
-                if not response:
-                  return None
-                for line in response.split('\n'):
-                  if line.startswith('Links:'):
-                    return eval(line[len("Links :"):])
-            except pexpect.EOF:
-                main.log.error(self.name + ": EOF exception found")
-                main.log.error(self.name + ":     " + self.handle.before)
-                main.cleanup()
-                main.exit()
-            return response
-        else:
-            main.log.error("Connection failed to the node")
 
 
 
diff --git a/TestON/drivers/common/cli/emulator/remotemininetdriver.py b/TestON/drivers/common/cli/emulator/remotemininetdriver.py
index d6e839d..2acddb4 100644
--- a/TestON/drivers/common/cli/emulator/remotemininetdriver.py
+++ b/TestON/drivers/common/cli/emulator/remotemininetdriver.py
@@ -91,7 +91,10 @@
             return main.FALSE
         elif re.search("found multiple mininet",outputs):
             return main.ERROR
-        return main.TRUE
+        else:
+            print outputs
+            return main.TRUE
+
 
 
     def pingLong(self,**pingParams):
@@ -421,6 +424,7 @@
         return main.TRUE
 
     def add_switch(self,sw):
+        #FIXME: Remove hardcoded number of ports
         self.handle.sendline("")
         self.handle.expect("\$")
         self.handle.sendline("sudo ovs-vsctl add-br "+sw)
@@ -472,32 +476,204 @@
             response = main.FALSE
         return response  
 
-    def get_flowTable(self,sw):
+    def get_flowTable(self, protoVersion, sw):
         self.handle.sendline("cd")
-        self.handle.expect(["\$",pexpect.EOF,pexpect.TIMEOUT])
+        #self.handle.expect(["\$",pexpect.EOF,pexpect.TIMEOUT])
+        print "cd expect status: " 
+        print self.handle.expect(["\$",pexpect.EOF,pexpect.TIMEOUT])
         #TODO: Write seperate versions of the function for this, possibly a string that tells it which switch is in use?
         #For 1.0 version of OVS
         #command = "sudo ovs-ofctl dump-flows " + sw + " | awk '{OFS=\",\" ; print $1 $6 $7 }' |sort -n -k1"
         #for 1.3 version of OVS
-        command = "sudo ovs-ofctl dump-flows " + sw + " | awk '{OFS=\",\" ; print $1 $3 $7 $8}' |sort -n -k1"
-        self.handle.sendline(command)
-        self.handle.expect(["sort -n -k1",pexpect.EOF,pexpect.TIMEOUT])
-        self.handle.expect(["NXST_FLOW",pexpect.EOF,pexpect.TIMEOUT])
-        response = self.handle.before
-        return response 
+        #command = "sudo ovs-ofctl dump-flows " + sw + " | awk '{OFS=\",\" ; print $1 $3 $7 $8}' |sort -n -k1"
+        #NOTE: Use format to force consistent flow table output across versions
+        if protoVersion==1.0:
+            command = "sudo ovs-ofctl dump-flows " + sw + " -F OpenFlow10-table_id | awk '{OFS=\",\" ; print $1  $3  $6  $7  $8}' |sort -n -k1"
+            self.handle.sendline(command)
+            self.handle.expect(["sort -n -k1",pexpect.EOF,pexpect.TIMEOUT])
+            self.handle.expect(["OFPST_FLOW",pexpect.EOF,pexpect.TIMEOUT])
+            response = self.handle.before
+            #print "response=", response
+            return response
+        elif protoVersion==1.3:
+            command = "sudo ovs-ofctl dump-flows " + sw + " -O OpenFlow13  | awk '{OFS=\",\" ; print $1  $3  $6  $7}' |sort -n -k1" 
+            self.handle.sendline(command)
+            #print "ovs-vsctl Command sent status."
+            #self.handle.expect(["sort -n -k1",pexpect.EOF,pexpect.TIMEOUT])
+            #print "sort return status: " 
+            #print self.handle.expect(["sort -n -k1",pexpect.EOF,pexpect.TIMEOUT])
+            #print self.handle.before
+            self.handle.expect(["OFPST_FLOW",pexpect.EOF,pexpect.TIMEOUT])
+            #print "OFPST_FLOW expected status: " 
+            #print self.handle.expect(["OFPST_FLOW",pexpect.EOF,pexpect.TIMEOUT])
+            #print self.handle.before
+            response = self.handle.before
+            #print "response=", response
+            return response 
         
 
     def flow_comp(self,flow1,flow2):
+        #print "Inside flow compare function"
+        #print "Flow1 Table:"
+        #for flow in flow1:
+            #print flow1
+        #print "Flow2 Table"
+        #for flow in flow2:
+            #print flow2
+
         if flow1==flow2:
             return main.TRUE
         else:
             main.log.info("Flow tables do not match, printing tables:")
-            main.log.info("Flow Table 1:")
-            main.log.info(flow1)
-            main.log.info("Flow Table 2:")
-            main.log.info(flow2)
+            #main.log.info("Flow Table 1:")
+            #main.log.info(flow1)
+            #main.log.info("Flow Table 2:")
+            #main.log.info(flow2)
             return main.FALSE
 
+    def setIpTablesOUTPUT(self, dst_ip, dst_port, action='add', packet_type='tcp',rule='DROP'):
+        '''
+        Description:
+            add or remove iptables rule to DROP (default)  packets from specific IP and PORT
+        Usage:
+        * specify action ('add' or 'remove')
+          when removing, pass in the same argument as you would add. It will
+          delete that specific rule. 
+        * specify the destination ip to block with dst_ip 
+        * specify destination port to block to dst_port
+        * optional packet type to block (default tcp)
+        * optional iptables rule (default DROP)
+        WARNING:
+        * This function uses root privilege iptables command which may result in
+          unwanted network errors. USE WITH CAUTION
+        '''
+        import re
+        import time
+
+        #NOTE*********
+        #   The strict checking methods of this driver function is intentional
+        #   to discourage any misuse or error of iptables, which can cause
+        #   severe network errors
+        #*************
+
+        #NOTE: Sleep needed to give some time for rule to be added and registered
+        #      to the instance
+        time.sleep(5)
+
+        action_type = action.lower()
+        if action_type != 'add' and action_type !='remove':
+            main.log.error("Invalid action type. 'add' or 'remove' table rule")
+            if rule != 'DROP' and rule != 'ACCEPT' and rule != 'LOG':
+                #NOTE: Currently only supports rules DROP, ACCEPT, and LOG
+                main.log.error("Invalid rule. 'DROP' or 'ACCEPT' or 'LOG' only.")
+                return
+            return
+        else:
+
+            #If there is no existing rule in the iptables, we will see an 
+            #'iptables:'... message. We expect to see this message. 
+            #Otherwise, if there IS an existing rule, we will get the prompt
+            # back, hence why we expect $ for remove type. We want to remove
+            # an already existing rule
+
+            if action_type == 'add':
+                #NOTE: "iptables:" expect is a result of return from the command
+                #      iptables -C ...
+                #      Any changes by the iptables command return string 
+                #      will result in failure of the function. (deemed unlikely
+                #      at the time of writing this function)
+                #Check for existing rules on current input
+                self.handle.sendline("")
+                self.handle.expect("\$")
+                self.handle.sendline("sudo iptables -C OUTPUT -p "+str(packet_type)+
+                        " -d "+ str(dst_ip)+" --dport "+str(dst_port)+" -j "+str(rule))
+                i = self.handle.expect(["iptables:", "\$"])
+                print i
+                print self.handle.before
+                print "after: "
+                print self.handle.after
+
+            elif action_type == 'remove':
+                #Check for existing rules on current input
+                self.handle.sendline("")
+                self.handle.expect("\$")
+                self.handle.sendline("sudo iptables -C OUTPUT -p "+str(packet_type)+
+                        " -d "+ str(dst_ip)+" --dport "+str(dst_port)+" -j "+str(rule))
+                self.handle.expect("\$")
+            print "before: "
+            print self.handle.before
+            actual_string = self.handle.after
+            expect_string = "iptables:"
+            print "Actual String:"
+            print actual_string
+
+            if re.search(expect_string, actual_string):
+                match_result = main.TRUE
+            else:
+                match_result = main.FALSE
+            #If match_result is main.TRUE, it means there is no matching rule. 
+
+            #If tables does not exist and expected prompt is returned, go ahead and
+            #add iptables rule
+            if match_result == main.TRUE:
+                #Ensure action type is add
+                if action_type == 'add':
+                    #-A is the 'append' action of iptables
+                    action_add = '-A'
+                    try:
+                        self.handle.sendline("")
+                        self.handle.sendline("sudo iptables "+action_add+" OUTPUT -p "+str(packet_type)+
+                            " -d "+ str(dst_ip)+" --dport "+str(dst_port)+" -j "+str(rule))
+
+                        info_string = "Rules added to "+str(self.name)
+                        info_string += "iptable rule added to block IP: "+str(dst_ip)
+                        info_string += "Port: "+str(dst_port)+" Rule: "+str(rule)
+
+                        main.log.info(info_string)
+
+                        self.handle.expect(["\$",pexpect.EOF,pexpect.TIMEOUT])
+                    except pexpect.TIMEOUT:
+                        main.log.error(self.name + ": Timeout exception in setIpTables function")
+                    except:
+                        main.log.error( traceback.print_exc())
+                        main.cleanup()
+                        main.exit()
+                else:
+                    main.log.error("Given rule already exists, but attempted to add it")
+            #If match_result is 0, it means there IS a matching rule provided
+            elif match_result == main.FALSE:
+                #Ensure action type is remove
+                if action_type == 'remove':
+                    #-D is the 'delete' rule of iptables
+                    action_remove = '-D'
+                    try:
+                        self.handle.sendline("")
+                        #Delete a specific rule specified into the function
+                        self.handle.sendline("sudo iptables "+action_remove+" OUTPUT -p "+str(packet_type)+
+                            " -d "+ str(dst_ip)+" --dport "+str(dst_port)+" -j "+str(rule))
+
+                        info_string = "Rules removed from "+str(self.name)
+                        info_string += " iptables rule removed from blocking IP: "+str(dst_ip)
+                        info_string += " Port: "+str(dst_port)+" Rule: "+str(rule)
+
+                        main.log.info(info_string)
+
+                        self.handle.expect(["\$",pexpect.EOF,pexpect.TIMEOUT])
+                    except pexpect.TIMEOUT:
+                        main.log.error(self.name + ": Timeout exception in setIpTables function")
+                    except:
+                        main.log.error( traceback.print_exc())
+                        main.cleanup()
+                        main.exit()
+                else:
+                    main.log.error("Given rule does not exist, but attempted to remove it")
+            else:
+                #NOTE: If a bad usage of this function occurs, exit the entire test
+                main.log.error("Bad rule given for iptables. Exiting...")
+                main.cleanup()
+                main.exit()
+
+
 if __name__ != "__main__":
     import sys
     sys.modules[__name__] = RemoteMininetDriver()