Merge branch 'ONOS-Next' of https://github.com/OPENNETWORKINGLAB/ONLabTest into ONOS-Next
diff --git a/TestON/drivers/common/cli/emulator/mininetclidriver.py b/TestON/drivers/common/cli/emulator/mininetclidriver.py
index 9c48e32..b217913 100644
--- a/TestON/drivers/common/cli/emulator/mininetclidriver.py
+++ b/TestON/drivers/common/cli/emulator/mininetclidriver.py
@@ -808,7 +808,6 @@
 
         '''
         import json
-        results = main.TRUE
         output = {"switches":[]}
         for switch in topo.graph.switches: #iterate through the MN topology and pull out switches and and port info
             #print vars(switch)
@@ -852,6 +851,174 @@
 
 
 
+    def compare_ports(self, topo, ports_json):
+        '''
+        Compare mn and onos ports
+        topo: sts TestONTopology object
+        ports_json: parsed json object from the onos ports api
+
+        Dependencies: 
+            1. This uses the sts TestONTopology object
+            2. numpy - "sudo pip install numpy"
+
+        '''
+        import json
+        from numpy import uint64
+        port_results = main.TRUE
+        output = {"switches":[]}
+        for switch in topo.graph.switches: #iterate through the MN topology and pull out switches and and port info
+            #print vars(switch)
+            ports = []
+            for port in switch.ports.values():
+                #print port.hw_addr.toStr(separator = '')
+                ports.append({'of_port': port.port_no, 'mac': str(port.hw_addr).replace('\'',''), 'name': port.name})
+            output['switches'].append({"name": switch.name, "dpid": str(switch.dpid).zfill(16), "ports": ports })
+        #print "compare_ports 'output' variable:"
+        #print output
+
+
+        ################ports#############
+        for switch in output['switches']:
+            mn_ports = []
+            onos_ports = []
+            for port in switch['ports']:
+                mn_ports.append(port['of_port'])
+            for onos_switch in ports_json:
+                if onos_switch['device'].replace(':','').replace("of", '') == switch['dpid']:
+                    for port in onos_switch['ports']:
+                        onos_ports.append(int(port['port'])) 
+            mn_ports.sort(key=float)
+            onos_ports.sort(key=float)
+            #print "\nPorts for Switch %s:" % (switch['name'])
+            #print "\tmn_ports[] = ", mn_ports
+            #print "\tonos_ports[] = ", 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 topology 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.
+            
+            #ONOS-Next is abstracting port numbers to 64bit unsigned number. So we will be converting the OF reserved ports to these numbers
+            #TODO: handle other reserved port numbers besides LOCAL
+            for mn_port,onos_port in zip(mn_ports,onos_ports):
+                if mn_port == onos_port or (mn_port == 65534 and onos_port ==int(uint64(-2))):
+                    continue
+                    #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
+                    break
+            if port_results == main.FALSE:
+                main.log.report("The list of ports for switch %s(%s) does not match:" % (switch['name'], switch['dpid']) )
+                main.log.report("mn_ports[] = " +  str(mn_ports))
+                main.log.report("onos_ports[] = " + str(onos_ports))
+        return port_results
+
+
+
+
+    def compare_links(self, topo, links_json):
+        '''
+        Compare mn and onos links
+        topo: sts TestONTopology object
+        links_json: parsed json object from the onos links api
+
+        This uses the sts TestONTopology object
+
+        '''
+        import json
+        link_results = main.TRUE
+        output = {"switches":[]}
+        onos = links_json
+        for switch in topo.graph.switches: #iterate through the MN topology and pull out switches and and port info
+            #print vars(switch)
+            ports = []
+            for port in switch.ports.values():
+                #print port.hw_addr.toStr(separator = '')
+                ports.append({'of_port': port.port_no, 'mac': str(port.hw_addr).replace('\'',''), 'name': port.name})
+            output['switches'].append({"name": switch.name, "dpid": str(switch.dpid).zfill(16), "ports": ports })
+        #######Links########
+
+        if 2*len(topo.patch_panel.network_links) == len(onos):
+            link_results = main.TRUE
+        else:
+            link_results = main.FALSE
+            main.log.report("Mininet has %i bidirectional links and ONOS has %i unidirectional links" % (len(topo.patch_panel.network_links), len(onos) ))
+
+
+        # iterate through MN links and check if an ONOS link exists in both directions
+        # NOTE: Will currently only show mn links as down if they are cut through STS. 
+        #       We can either do everything through STS or wait for up_network_links 
+        #       and down_network_links to be fully implemented.
+        for link in topo.patch_panel.network_links: 
+            #print "\n"
+            #print "Link: %s" % link
+            #TODO: Find a more efficient search method
+            node1 = None
+            port1 = None
+            node2 = None
+            port2 = None
+            first_dir = main.FALSE
+            second_dir = main.FALSE
+            for switch in output['switches']:
+                #print "Switch: %s" % switch['name']
+                if switch['name'] == link.node1.name:
+                    node1 = switch['dpid']
+                    for port in switch['ports']:
+                        if str(port['name']) == str(link.port1):
+                            port1 = port['of_port'] 
+                    if node1 is not None and node2 is not None:
+                        break
+                if switch['name'] == link.node2.name:
+                    node2 = switch['dpid']
+                    for port in switch['ports']: 
+                        if str(port['name']) == str(link.port2):
+                            port2 = port['of_port'] 
+                    if node1 is not None and node2 is not None:
+                        break
+
+
+            for onos_link in onos:
+                onos_node1 = onos_link['src']['device'].replace(":",'').replace("of", '')
+                onos_node2 = onos_link['dst']['device'].replace(":",'').replace("of", '')
+                onos_port1 = onos_link['src']['port']
+                onos_port2 = onos_link['dst']['port']
+
+                #print "Checking ONOS for link %s/%s -> %s/%s and" % (node1, port1, node2, port2)
+                #print "Checking ONOS for link %s/%s -> %s/%s" % (node2, port2, node1, port1)
+                # check onos link from node1 to node2
+                if str(onos_node1) == str(node1) and str(onos_node2) == str(node2):
+                    if int(onos_port1) == int(port1) and int(onos_port2) == int(port2):
+                        first_dir = main.TRUE
+                    else:
+                        main.log.report('The port numbers do not match for ' +str(link) +\
+                                ' between ONOS and MN. When cheking ONOS for link '+\
+                                '%s/%s -> %s/%s' % (node1, port1, node2, port2)+\
+                                ' ONOS has the values %s/%s -> %s/%s' %\
+                                (onos_node1, onos_port1, onos_node2, onos_port2))
+
+                # check onos link from node2 to node1
+                elif ( str(onos_node1) == str(node2) and str(onos_node2) == str(node1) ):
+                    if ( int(onos_port1) == int(port2) and int(onos_port2) == int(port1) ):
+                        second_dir = main.TRUE
+                    else:
+                        main.log.report('The port numbers do not match for ' +str(link) +\
+                                ' between ONOS and MN. When cheking ONOS for link '+\
+                                '%s/%s -> %s/%s' % (node2, port2, node1, port1)+\
+                                ' ONOS has the values %s/%s -> %s/%s' %\
+                                (onos_node2, onos_port2, onos_node1, onos_port1))
+                else:#this is not the link you're looking for
+                    pass
+            if not first_dir:
+                main.log.report('ONOS does not have the link %s/%s -> %s/%s' % (node1, port1, node2, port2))
+            if not second_dir:
+                main.log.report('ONOS does not have the link %s/%s -> %s/%s' % (node2, port2, node1, port1))
+            link_results = link_results and first_dir and second_dir
+            return link_results
+
+
 
 
     def compare_topo(self, topo, onos_json):
@@ -946,7 +1113,7 @@
                     #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/
+                #sees the correct port number, however MN topology 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):
@@ -955,7 +1122,6 @@
                     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
diff --git a/TestON/drivers/common/cli/onosclidriver.py b/TestON/drivers/common/cli/onosclidriver.py
index b5faab1..2d4afd4 100644
--- a/TestON/drivers/common/cli/onosclidriver.py
+++ b/TestON/drivers/common/cli/onosclidriver.py
@@ -399,7 +399,7 @@
         
     def devices(self, json_format=True, grep_str=""):
         '''
-        Lists all infrastructure devices
+        Lists all infrastructure devices or switches
         Optional argument:
             * grep_str - pass in a string to grep
         '''
@@ -421,7 +421,7 @@
                 '''
                 handle variable here contains some ANSI escape color code sequences at the end which are invisible in the print command output
                 To make that escape sequence visible, use repr() function. The repr(handle) output when printed shows the ANSI escape sequences.
-                In json.loads(somestring), this somestring variable is a actually repr(somestring) and json.loads would fail with the escape sequence.
+                In json.loads(somestring), this somestring variable is actually repr(somestring) and json.loads would fail with the escape sequence.
                 So we take off that escape sequence using 
                 ansi_escape = re.compile(r'\r\r\n\x1b[^m]*m')
                 handle1 = ansi_escape.sub('', handle) 
@@ -482,7 +482,7 @@
                 '''
                 handle variable here contains some ANSI escape color code sequences at the end which are invisible in the print command output
                 To make that escape sequence visible, use repr() function. The repr(handle) output when printed shows the ANSI escape sequences.
-                In json.loads(somestring), this somestring variable is a actually repr(somestring) and json.loads would fail with the escape sequence.
+                In json.loads(somestring), this somestring variable is actually repr(somestring) and json.loads would fail with the escape sequence.
                 So we take off that escape sequence using 
                 ansi_escape = re.compile(r'\r\r\n\x1b[^m]*m')
                 handle1 = ansi_escape.sub('', handle) 
@@ -544,8 +544,8 @@
                 '''
                 handle variable here contains some ANSI escape color code sequences at the end which are invisible in the print command output
                 To make that escape sequence visible, use repr() function. The repr(handle) output when printed shows the ANSI escape sequences.
-                In json.loads(somestring), this somestring variable is a actually repr(somestring) and json.loads would fail with the escape sequence.
-                So we take off that escape sequence using 
+                In json.loads(somestring), this somestring variable is actually repr(somestring) and json.loads would fail with the escape sequence.
+                So we take off that escape sequence using the following commads: 
                 ansi_escape = re.compile(r'\r\r\n\x1b[^m]*m')
                 handle1 = ansi_escape.sub('', handle) 
                 '''
@@ -689,8 +689,8 @@
         '''
         
         try:
-            self.handle.sendline("")
-            self.handle.expect("onos>")
+            #self.handle.sendline("")
+            #self.handle.expect("onos>")
 
             onos_host_list = []