Merge branch 'ONOS-Next' of https://github.com/OPENNETWORKINGLAB/ONLabTest into ONOS-Next
diff --git a/TestON/drivers/common/cli/emulator/lincoedriver.py b/TestON/drivers/common/cli/emulator/lincoedriver.py
new file mode 100644
index 0000000..4d2cc01
--- /dev/null
+++ b/TestON/drivers/common/cli/emulator/lincoedriver.py
@@ -0,0 +1,315 @@
+#!/usr/bin/env python
+
+'''
+This driver handles the optical switch emulator linc-oe.
+
+Please follow the coding style demonstrated by existing
+functions and document properly.
+
+If you are a contributor to the driver, please
+list your email here for future contact:
+
+    andrew@onlab.us
+
+OCT 20 2014
+'''
+
+import traceback
+import pexpect
+import struct
+import fcntl
+import os
+import signal
+import re
+import sys
+import core.teston
+sys.path.append("../")
+from math import pow
+from drivers.common.cli.emulatordriver import Emulator
+from drivers.common.clidriver import CLI
+
+class LincOEDriver(Emulator):
+    '''
+    LincOEDriver class will handle all emulator functions    
+    '''
+    def __init__(self):
+        super(Emulator, self).__init__()
+        self.handle = self
+        self.wrapped = sys.modules[__name__]
+        self.flag = 0
+
+    def connect(self, **connectargs):
+        '''
+        Create ssh handle for Linc-OE cli
+        '''
+        import time
+
+        for key in connectargs:
+            vars(self)[key] = connectargs[key]       
+        
+        self.name = self.options['name']
+        self.handle = \
+                super(LincOEDriver, self).connect(\
+                user_name = self.user_name,
+                ip_address = self.ip_address,
+                port = None, 
+                pwd = self.pwd)
+        
+        self.ssh_handle = self.handle
+        
+        if self.handle :
+            main.log.info("Handle successfully created")
+            self.home = "~/linc-oe"
+            self.handle.sendline("cd "+self.home)
+            self.handle.expect("oe$")
+
+            main.log.info("Building Linc-OE")
+            self.handle.sendline("make rel")
+            i = self.handle.expect(["ERROR","linc-oe\$"],timeout=60)
+            if i == 0:
+                self.handle.sendline("sudo pkill -9 epmd")
+                self.handle.expect("\$")
+                self.handle.sendline("make rel")
+                x = self.handle.expect(["\$",pexpect.EOF,pexpect.TIMEOUT])
+                main.log.info("make rel returned: "+ str(x))
+            else: 
+                main.log.info(self.name+": Starting Linc-OE CLI.. This may take a while")
+                time.sleep(30)
+                self.handle.sendline("sudo ./rel/linc/bin/linc console")
+                j = self.handle.expect(["linc@",pexpect.EOF,pexpect.TIMEOUT])
+          
+            if j == 0:
+                main.log.info("Linc-OE CLI started")
+                return main.TRUE
+
+        else:
+            main.log.error(self.name+
+                    ": Connection failed to the host "+
+                    self.user_name+"@"+self.ip_address) 
+            main.log.error(self.name+
+                    ": Failed to connect to Linc-OE")
+            return main.FALSE
+
+    def build(self):
+        '''
+        Build Linc-OE with the specified settings
+        '''
+        try:
+            self.handle.sendline("make rel")
+            i = self.handle.expect([
+                "ERROR",
+                "\$"])
+
+            if i == 0:
+                #If error, try to resolve the most common error
+                #(epmd running and cannot compile)
+                self.handle.sendline("sudo pkill -9 epmd")
+                self.handle.sendline("make rel")
+                self.handle.expect("\$")
+                    
+                handle = self.handle.before
+                return handle
+
+            else:
+                return main.TRUE
+
+        except pexpect.EOF:
+            main.log.error(self.name+ ": EOF exception")
+            main.log.error(self.name+ ":    " + self.handle.before)
+            main.cleanup()
+            main.exit()
+        except:
+            main.log.info(self.name+" :::::::")
+            main.log.error( traceback.print_exc())
+            main.log.info(self.name+" :::::::")
+            main.cleanup()
+            main.exit()
+
+    def set_interface_up(self, intfs):
+        '''
+        Specify interface to bring up.
+        When Linc-OE is started, tap interfaces should
+        be created. They must be brought up manually
+        '''
+        try:
+            self.handle.sendline("ifconfig "+str(intf)+" up")
+            self.handle.expect("linc@")
+   
+            handle = self.handle.before
+
+            return handle
+
+        except pexpect.EOF:
+            main.log.error(self.name+ ": EOF exception")
+            main.log.error(self.name+ ":    " + self.handle.before)
+            main.cleanup()
+            main.exit()
+        except:
+            main.log.info(self.name+" :::::::")
+            main.log.error( traceback.print_exc())
+            main.log.info(self.name+" :::::::")
+            main.cleanup()
+            main.exit()
+
+    def start_switch(self, sw_id):
+        '''
+        Start a logical switch using switch id
+        '''
+        try:
+            self.handle.sendline("linc:start_switch("+str(sw_id)+").")
+            self.handle.expect("linc@")
+
+            handle = self.handle.before
+
+        except pexpect.EOF:
+            main.log.error(self.name+ ": EOF exception")
+            main.log.error(self.name+ ":    " + self.handle.before)
+            main.cleanup()
+            main.exit()
+        except:
+            main.log.info(self.name+" :::::::")
+            main.log.error( traceback.print_exc())
+            main.log.info(self.name+" :::::::")
+            main.cleanup()
+            main.exit()
+
+    def stop_switch(self, sw_id):
+        '''
+        Stop a logical switch using switch id
+        '''
+        try:
+            self.handle.sendline("linc:stop_switch("+str(sw_id)+").")
+            self.handle.expect("linc@")
+
+            handle = self.handle.before
+
+        except pexpect.EOF:
+            main.log.error(self.name+ ": EOF exception")
+            main.log.error(self.name+ ":    " + self.handle.before)
+            main.cleanup()
+            main.exit()
+        except:
+            main.log.info(self.name+" :::::::")
+            main.log.error( traceback.print_exc())
+            main.log.info(self.name+" :::::::")
+            main.cleanup()
+            main.exit()
+     
+    def get_datapath_id(self, sw_id):
+        '''
+        Get datapath id of a specific switch by switch id
+        '''
+        try:
+            self.handle.sendline("linc_logic:get_datapath_id("+
+                    str(sw_id)+").")
+            self.handle.expect("linc@")
+
+            handle = self.handle.before
+        
+        except pexpect.EOF:
+            main.log.error(self.name+ ": EOF exception")
+            main.log.error(self.name+ ":    " + self.handle.before)
+            main.cleanup()
+            main.exit()
+        except:
+            main.log.info(self.name+" :::::::")
+            main.log.error( traceback.print_exc())
+            main.log.info(self.name+" :::::::")
+            main.cleanup()
+            main.exit()
+
+    def list_ports(self, sw_id):
+        '''
+        List all ports of a switch by switch id
+        '''
+        try:
+            self.handle.sendline("linc:ports("+str(sw_id)+").")
+            self.handle.expect("linc@")
+
+            handle = self.handle.before
+
+        except pexpect.EOF:
+            main.log.error(self.name+ ": EOF exception")
+            main.log.error(self.name+ ":    " + self.handle.before)
+            main.cleanup()
+            main.exit()
+        except:
+            main.log.info(self.name+" :::::::")
+            main.log.error( traceback.print_exc())
+            main.log.info(self.name+" :::::::")
+            main.cleanup()
+            main.exit()
+
+    def port_up(self, sw_id, pt_id):
+        '''
+        Bring port up using switch id and port id
+        '''
+        try:
+            self.handle.sendline("linc:port_up("+
+                    str(sw_id)+", "+str(pt_id)+").")
+            self.handle.expect("linc@")
+
+            handle = self.handle.before
+
+        except pexpect.EOF:
+            main.log.error(self.name+ ": EOF exception")
+            main.log.error(self.name+ ":    " + self.handle.before)
+            main.cleanup()
+            main.exit()
+        except:
+            main.log.info(self.name+" :::::::")
+            main.log.error( traceback.print_exc())
+            main.log.info(self.name+" :::::::")
+            main.cleanup()
+            main.exit()
+    
+    def port_down(self, sw_id, pt_id):
+        '''
+        Bring port down using switch id and port id
+        '''
+        try:
+            self.handle.sendline("linc:port_down("+
+                    str(sw_id)+", "+str(pt_id)+").")
+            self.handle.expect("linc@")
+
+            handle = self.handle.before
+
+        except pexpect.EOF:
+            main.log.error(self.name+ ": EOF exception")
+            main.log.error(self.name+ ":    " + self.handle.before)
+            main.cleanup()
+            main.exit()
+        except:
+            main.log.info(self.name+" :::::::")
+            main.log.error( traceback.print_exc())
+            main.log.info(self.name+" :::::::")
+            main.cleanup()
+            main.exit()
+
+    def disconnect(self):
+        '''
+        Send disconnect prompt to Linc-OE CLI
+        (CTRL+C)
+        '''
+        try:
+            #Send CTRL+C twice to exit CLI
+            self.handle.sendline("\x03")
+            self.handle.sendline("\x03")
+            self.handle.expect("\$")
+
+        except pexpect.EOF:
+            main.log.error(self.name+ ": EOF exception")
+            main.log.error(self.name+ ":    " + self.handle.before)
+            main.cleanup()
+            main.exit()
+        except:
+            main.log.info(self.name+" :::::::")
+            main.log.error( traceback.print_exc())
+            main.log.info(self.name+" :::::::")
+            main.cleanup()
+            main.exit()
+
+if __name__ != "__main__":
+    import sys
+    sys.modules[__name__] = LincOEDriver()
+
diff --git a/TestON/drivers/common/cli/emulator/mininetclidriver.py b/TestON/drivers/common/cli/emulator/mininetclidriver.py
index 9c48e32..ccf3baf 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 dff8c18..cf9029c 100644
--- a/TestON/drivers/common/cli/onosclidriver.py
+++ b/TestON/drivers/common/cli/onosclidriver.py
@@ -84,11 +84,16 @@
         response = ''
         try:
             self.handle.sendline("")
-            self.handle.expect("onos>")
-            self.handle.sendline("system:shutdown")
-            self.handle.expect("Confirm")
-            self.handle.sendline("yes")
+            i = self.handle.expect(["onos>","\$"])
+            if i == 0:
+                self.handle.sendline("system:shutdown")
+                self.handle.expect("Confirm")
+                self.handle.sendline("yes")
+                self.handle.expect("\$")
+            self.handle.sendline("\n")
             self.handle.expect("\$")
+            self.handle.sendline("exit")
+            self.handle.expect("closed")
 
         except pexpect.EOF:
             main.log.error(self.name + ": EOF exception found")
@@ -753,30 +758,54 @@
             main.exit()
 
     def add_point_intent(self, ingress_device, port_ingress,
-            egress_device, port_egress):
+            egress_device, port_egress, ethType="", ethSrc="",
+            ethDst=""):
         '''
         Required:
             * ingress_device: device id of ingress device
             * egress_device: device id of egress device
+        Optional:
+            * ethType: specify ethType
+            * ethSrc: specify ethSrc (i.e. src mac addr)
+            * ethDst: specify ethDst (i.e. dst mac addr)
         Description:
             Adds a point-to-point intent (uni-directional) by
-            specifying device id's 
-        
+            specifying device id's and optional fields
+
         NOTE: This function may change depending on the 
               options developers provide for point-to-point
               intent via cli
         '''
         try:
+            cmd = ""
+
+            #If there are no optional arguments
+            if not ethType and not ethSrc and not ethDst:
+                cmd = "add-point-intent "+\
+                        str(ingress_device) + "/" + str(port_ingress) + " " +\
+                        str(egress_device) + "/" + str(port_egress)
+       
+            else:
+                cmd = "add-point-intent "
+                
+                if ethType:
+                    cmd += " --ethType " + str(ethType)
+                if ethSrc:
+                    cmd += " --ethSrc " + str(ethSrc) 
+                if ethDst:    
+                    cmd += " --ethDst " + str(ethDst) 
+                        
+                cmd += " "+str(ingress_device) + "/" + str(port_ingress) + " " +\
+                str(egress_device) + "/" + str(port_egress) 
+
             self.handle.sendline("")
             self.handle.expect("onos>")
 
-            self.handle.sendline("add-point-intent "+
-                    str(ingress_device) + "/" + str(port_ingress) + " " +
-                    str(egress_device) + "/" + str(port_egress))
+            self.handle.sendline(cmd)
             i = self.handle.expect([
                 "Error",
                 "onos>"])
-            
+          
             self.handle.sendline("")
             self.handle.expect("onos>")
 
@@ -787,7 +816,7 @@
                 return handle
             else:
                 return main.TRUE
-        
+
         except pexpect.EOF:
             main.log.error(self.name + ": EOF exception found")
             main.log.error(self.name + ":    " + self.handle.before)
@@ -833,22 +862,32 @@
             main.cleanup()
             main.exit()
 
-    def intents(self):
+    def intents(self, json_format = False):
         '''
+        Optional:
+            * json_format: enable output formatting in json
         Description:
             Obtain intents currently installed 
         '''
         try:
-            self.handle.sendline("")
-            self.handle.expect("onos>")
+            if json_format:
+                self.handle.sendline("intents -j")
+                self.handle.expect("intents -j")
+                self.handle.expect("onos>")
 
-            self.handle.sendline("intents")
-            self.handle.expect("onos>")
+                handle = self.handle.before
 
-            self.handle.sendline("")
-            self.handle.expect("onos>")
+            else:
+                self.handle.sendline("")
+                self.handle.expect("onos>")
 
-            handle = self.handle.before
+                self.handle.sendline("intents")
+                self.handle.expect("onos>")
+
+                self.handle.sendline("")
+                self.handle.expect("onos>")
+
+                handle = self.handle.before
 
             return handle
 
@@ -864,6 +903,45 @@
             main.cleanup()
             main.exit()
 
+    def topology_events_metrics(self, json_format=True):
+        '''
+        Description:Returns topology metrics 
+        Optional:
+            * json_format: enable json formatting of output
+        '''
+        try:
+            if json_format:
+                self.handle.sendline("topology-events-metrics -j")
+                self.handle.expect("topology-events-metrics -j")
+                self.handle.expect("onos>")
+                
+                handle = self.handle.before
+              
+                #Some color thing that we want to escape
+                ansi_escape = re.compile(r'\r\r\n\x1b[^m]*m')
+                handle = ansi_escape.sub('', handle)
+            
+            else:
+                self.handle.sendline("topology-events-metrics")
+                self.handle.expect("topology-events-metrics")
+                self.handle.expect("onos>")
+                
+                handle = self.handle.before
+
+            return handle
+        
+        except pexpect.EOF:
+            main.log.error(self.name + ": EOF exception found")
+            main.log.error(self.name + ":    " + self.handle.before)
+            main.cleanup()
+            main.exit()
+        except:
+            main.log.info(self.name+" ::::::")
+            main.log.error( traceback.print_exc())
+            main.log.info(self.name+" ::::::")
+            main.cleanup()
+            main.exit()
+
     #Wrapper functions ****************
     #Wrapper functions use existing driver
     #functions and extends their use case.
@@ -999,4 +1077,35 @@
             main.cleanup()
             main.exit()
 
+    def get_device(self, dpid=None):
+        '''
+        Return the first device from the devices api whose 'id' contains 'dpid'
+        Return None if there is no match
+        '''
+        import json
+        try:
+            if dpid == None:
+                return None
+            else:
+                dpid = dpid.replace(':', '')
+                raw_devices = self.devices()
+                devices_json = json.loads(raw_devices)
+                #search json for the device with dpid then return the device
+                for device in devices_json:
+                    #print "%s in  %s?" % (dpid, device['id'])
+                    if dpid in device['id']:
+                        return device
+            return None
+        except pexpect.EOF:
+            main.log.error(self.name + ": EOF exception found")
+            main.log.error(self.name + ":    " + self.handle.before)
+            main.cleanup()
+            main.exit()
+        except:
+            main.log.info(self.name+" ::::::")
+            main.log.error( traceback.print_exc())
+            main.log.info(self.name+" ::::::")
+            main.cleanup()
+            main.exit()
+
     #***********************************
diff --git a/TestON/drivers/common/cli/onosdriver.py b/TestON/drivers/common/cli/onosdriver.py
index b3e4c05..f22f064 100644
--- a/TestON/drivers/common/cli/onosdriver.py
+++ b/TestON/drivers/common/cli/onosdriver.py
@@ -82,6 +82,8 @@
         '''
         response = ''
         try:
+            self.handle.sendline("\n")
+            self.handle.expect("\$")
             self.handle.sendline("exit")
             self.handle.expect("closed")
         except pexpect.EOF:
@@ -992,9 +994,9 @@
         '''
         self.handle.sendline("")
         self.handle.expect("\$")
-        self.handle.sendline("\r")
+        self.handle.sendline("")
         self.handle.sendline("tshark -i "+str(interface)+
-                " -t e | grep \""+str(grep)+"\" > "+directory+" &")
+                " -t e | grep --line-buffered \""+str(grep)+"\" > "+directory+" &")
         self.handle.sendline("\r")
         self.handle.expect("Capturing on")
         self.handle.sendline("\r")
@@ -1014,10 +1016,3 @@
 
 
 
-
-
-
-
-
-
-
diff --git a/TestON/tests/LincOETest/LincOETest.params b/TestON/tests/LincOETest/LincOETest.params
new file mode 100755
index 0000000..46e4f19
--- /dev/null
+++ b/TestON/tests/LincOETest/LincOETest.params
@@ -0,0 +1,20 @@
+<PARAMS>
+    
+    <testcases>1,2</testcases>
+
+    #Environment variables
+    <ENV>
+        <cellName>linc_oe_test</cellName>
+    </ENV>
+
+    <CTRL>
+        <ip1>10.128.174.1</ip1>
+        <port1>6633</port1>
+    </CTRL>
+
+    <GIT>
+        <autoPull>off</autoPull>
+        <checkout>master</checkout>
+    </GIT>
+
+</PARAMS>
diff --git a/TestON/tests/LincOETest/LincOETest.py b/TestON/tests/LincOETest/LincOETest.py
new file mode 100755
index 0000000..bb52ca8
--- /dev/null
+++ b/TestON/tests/LincOETest/LincOETest.py
@@ -0,0 +1,114 @@
+#LincOETest
+#
+#Packet-Optical Intent Testing
+#
+#andrew@onlab.us
+
+
+import time
+import sys
+import os
+import re
+
+class LincOETest:
+    def __init__(self):
+        self.default = ''
+
+    def CASE1(self, main):
+        '''
+        Startup sequence:
+        git pull
+        mvn clean install
+        onos-package
+        cell <name>
+        onos-verify-cell
+        onos-install -f
+        onos-wait-for-start
+        '''
+        import time
+
+        cell_name = main.params['ENV']['cellName']
+
+        ONOS1_ip = main.params['CTRL']['ip1']
+        ONOS1_port = main.params['CTRL']['port1']
+        
+        git_pull_trigger = main.params['GIT']['autoPull']
+        git_checkout_branch = main.params['GIT']['checkout']
+
+        main.case("Setting up test environment")
+        
+        main.step("Creating cell file")
+        #params: (bench ip, cell name, mininet ip, *onos ips)
+        cell_file_result = main.ONOSbench.create_cell_file(
+                "10.128.20.10", cell_name, "10.128.10.90",
+                "onos-core-trivial,onos-app-fwd",
+                "10.128.174.1")
+
+        main.step("Applying cell variable to environment")
+        #cell_result = main.ONOSbench.set_cell(cell_name)
+        cell_result = main.ONOSbench.set_cell("temp_cell_2")
+        verify_result = main.ONOSbench.verify_cell()
+       
+        if git_pull_trigger == 'on':
+            main.step("Git checkout and pull master")
+            main.ONOSbench.git_checkout(git_checkout_branch)
+            git_pull_result = main.ONOSbench.git_pull()
+        else:
+            main.log.info("Git checkout and pull skipped by config")
+            git_pull_result = main.TRUE
+
+        main.step("Using mvn clean & install")
+        #clean_install_result = main.ONOSbench.clean_install()
+        clean_install_result = main.TRUE
+
+        main.step("Creating ONOS package")
+        package_result = main.ONOSbench.onos_package()
+
+        main.step("Installing ONOS package")
+        onos_install_result = main.ONOSbench.onos_install()
+        onos1_isup = main.ONOSbench.isup()
+   
+        main.step("Starting ONOS service")
+        start_result = main.ONOSbench.onos_start(ONOS1_ip)
+
+        main.step("Setting cell for ONOScli")
+        main.ONOScli.set_cell(cell_name)
+
+        main.step("Starting ONOScli")
+        main.ONOScli.start_onos_cli(ONOS1_ip)
+
+        case1_result = (clean_install_result and package_result and\
+                cell_result and verify_result and onos_install_result and\
+                onos1_isup and start_result )
+        utilities.assert_equals(expect=main.TRUE, actual=case1_result,
+                onpass="Test startup successful",
+                onfail="Test startup NOT successful")
+
+        time.sleep(10)
+
+    def CASE2(self, main):
+        '''
+        Configure topology
+        '''
+        import time
+
+        ONOS1_ip = main.params['CTRL']['ip1']
+        default_sw_port = main.params['CTRL']['port1'] 
+
+        #Assign packet level switches to controller 
+        main.Mininet1.assign_sw_controller(sw="1",
+                ip1=ONOS1_ip, port1=default_sw_port)
+        main.Mininet1.assign_sw_controller(sw="2",
+                ip1=ONOS1_ip, port1=default_sw_port)
+
+        #Check devices in controller
+        #This should include Linc-OE devices as well
+        devices = main.ONOScli.devices()
+        main.log.info(devices)
+
+    def CASE3(self, main):
+        '''
+        Install multi-layer intents
+        '''
+
+
diff --git a/TestON/tests/LincOETest/LincOETest.topo b/TestON/tests/LincOETest/LincOETest.topo
new file mode 100755
index 0000000..221256e
--- /dev/null
+++ b/TestON/tests/LincOETest/LincOETest.topo
@@ -0,0 +1,55 @@
+<TOPOLOGY>
+    <COMPONENT>
+
+        <ONOSbench>
+            <host>10.128.20.10</host>
+            <user>admin</user>
+            <password>onos_test</password>
+            <type>OnosDriver</type>
+            <connect_order>1</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </ONOSbench>
+
+        <ONOScli>
+            <host>10.128.20.10</host>
+            <user>admin</user>
+            <password>onos_test</password>
+            <type>OnosCliDriver</type>
+            <connect_order>2</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </ONOScli>
+
+        <ONOS1>
+            <host>10.128.174.1</host>
+            <user>sdn</user>
+            <password>rocks</password>
+            <type>OnosDriver</type>
+            <connect_order>3</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </ONOS1>
+
+        <LincOE>
+            <host>10.128.10.90</host>
+            <user>admin</user>
+            <password>onos_test</password>
+            <type>LincOEDriver</type>
+            <connect_order>4</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </LincOE>
+
+        <Mininet1>
+            <host>10.128.10.90</host>
+            <user>admin</user>
+            <password>onos_test</password>
+            <type>MininetCliDriver</type>
+            <connect_order>5</connect_order>
+            <COMPONENTS> 
+                <arg1> --custom optical.py </arg1>
+                <arg2> --arp --mac</arg2>
+                <arg3> --topo optical</arg3>
+                <controller> remote </controller>
+            </COMPONENTS>
+        </Mininet1>
+
+    </COMPONENT>
+</TOPOLOGY>
diff --git a/TestON/tests/ONOSNextTest/ONOSNextTest.params b/TestON/tests/ONOSNextTest/ONOSNextTest.params
index 01c432e..019b746 100755
--- a/TestON/tests/ONOSNextTest/ONOSNextTest.params
+++ b/TestON/tests/ONOSNextTest/ONOSNextTest.params
@@ -12,4 +12,9 @@
         <port1>6633</port1>
     </CTRL>
 
+    <GIT>
+        <autoPull>off</autoPull>
+        <checkout>master</checkout>
+    </GIT>
+
 </PARAMS>
diff --git a/TestON/tests/ONOSNextTest/ONOSNextTest.py b/TestON/tests/ONOSNextTest/ONOSNextTest.py
index f01446c..de441ba 100755
--- a/TestON/tests/ONOSNextTest/ONOSNextTest.py
+++ b/TestON/tests/ONOSNextTest/ONOSNextTest.py
@@ -25,9 +25,13 @@
         import time
 
         cell_name = main.params['ENV']['cellName']
+
         ONOS1_ip = main.params['CTRL']['ip1']
         ONOS1_port = main.params['CTRL']['port1']
         
+        git_pull_trigger = main.params['GIT']['autoPull']
+        git_checkout_branch = main.params['GIT']['branch']
+
         main.case("Setting up test environment")
         
         main.step("Creating cell file")
@@ -38,14 +42,18 @@
                 "10.128.20.11")
 
         main.step("Applying cell variable to environment")
-        cell_result = main.ONOSbench.set_cell(cell_name)
-        #cell_result = main.ONOSbench.set_cell("temp_cell_2")
+        #cell_result = main.ONOSbench.set_cell(cell_name)
+        cell_result = main.ONOSbench.set_cell("temp_cell_2")
         verify_result = main.ONOSbench.verify_cell()
-        
-        main.step("Git checkout and pull master")
-        #main.ONOSbench.git_checkout("master")
-        #git_pull_result = main.ONOSbench.git_pull()
-        
+       
+        if git_pull_trigger == 'on':
+            main.step("Git checkout and pull master")
+            main.ONOSbench.git_checkout(git_checkout_branch)
+            git_pull_result = main.ONOSbench.git_pull()
+        else:
+            main.log.info("Git checkout and pull skipped by config")
+            git_pull_result = main.TRUE
+
         main.step("Using mvn clean & install")
         #clean_install_result = main.ONOSbench.clean_install()
         clean_install_result = main.TRUE
diff --git a/TestON/tests/TopoPerfNext/TopoPerfNext.params b/TestON/tests/TopoPerfNext/TopoPerfNext.params
index d8d8b37..463ec02 100644
--- a/TestON/tests/TopoPerfNext/TopoPerfNext.params
+++ b/TestON/tests/TopoPerfNext/TopoPerfNext.params
@@ -12,12 +12,12 @@
     </GIT>
 
     <CTRL>
-        <user>sdn</user>
-        <ip1>10.128.20.11</ip1>
+        <user>admin</user>
+        <ip1>10.128.174.1</ip1>
         <port1>6633</port1>
-        <ip2>10.128.20.12</ip2>
+        <ip2>10.128.174.2</ip2>
         <port2>6633</port2>
-        <ip3>10.128.20.13</ip3>
+        <ip3>10.128.174.3</ip3>
         <port3>6633</port3>
     </CTRL>
 
diff --git a/TestON/tests/TopoPerfNext/TopoPerfNext.py b/TestON/tests/TopoPerfNext/TopoPerfNext.py
index 2fe521b..eb49669 100644
--- a/TestON/tests/TopoPerfNext/TopoPerfNext.py
+++ b/TestON/tests/TopoPerfNext/TopoPerfNext.py
@@ -50,7 +50,8 @@
             main.log.info("Skipped git checkout and pull")
 
         main.step("Using mvn clean & install")
-        mvn_result = main.ONOSbench.clean_install()
+        #mvn_result = main.ONOSbench.clean_install()
+        mvn_result = main.TRUE
 
         main.step("Creating ONOS package")
         package_result = main.ONOSbench.onos_package()
@@ -61,13 +62,28 @@
         main.step("Starting ONOS service")
         start_result = main.ONOSbench.onos_start(ONOS1_ip)
 
+        main.step("Set cell for ONOS cli env")
+        main.ONOS1cli.set_cell(cell_name)
+        main.ONOS2cli.set_cell(cell_name)
+        main.ONOS3cli.set_cell(cell_name)
+
+        main.step("Start onos cli")
+        main.ONOS1cli.start_onos_cli(ONOS1_ip)
+        main.ONOS2cli.start_onos_cli(ONOS2_ip)
+        main.ONOS3cli.start_onos_cli(ONOS3_ip)
+
+        main.step("Enable metrics feature")
+        main.ONOS1cli.feature_install("onos-app-metrics-topology")
+        main.ONOS2cli.feature_install("onos-app-metrics-topology")
+        main.ONOS3cli.feature_install("onos-app-metrics-topology")
+
         utilities.assert_equals(expect=main.TRUE,
                 actual= cell_file_result and cell_apply_result and\
                         verify_cell_result and checkout_result and\
                         pull_result and mvn_result and\
                         install_result and start_result,
-                onpass="Cell file created successfully",
-                onfail="Failed to create cell file")
+                onpass="ONOS started successfully",
+                onfail="Failed to start ONOS")
 
     def CASE2(self, main):
         '''
@@ -127,7 +143,7 @@
 
             #Wait and ensure switch is assigned
             #before stopping tshark
-            time.sleep(10)
+            time.sleep(30)
     
             main.ONOS1.stop_tshark()
 
@@ -136,31 +152,36 @@
             main.log.info("Copying over tshark files")
             
             #TCP CAPTURE ****
-            ssh_tcp_file = subprocess.Popen(['ssh',
-                ONOS_user+"@"+ONOS1_ip, 'cat', 
-                tshark_tcp_output], stdout=subprocess.PIPE)
-            temp_text = ssh_tcp_file.stdout.readline()
+            #Copy the tshark output from ONOS machine to
+            #TestON machine in tshark_tcp_output directory>file
+            os.system("scp "+ONOS_user+"@"+ONOS1_ip+":"+
+                    tshark_tcp_output+" /tmp/") 
+            tcp_file = open(tshark_tcp_output, 'r')
+            temp_text = tcp_file.readline()
             temp_text = temp_text.split(" ")
 
             main.log.info("Object read in from TCP capture: "+
                     str(temp_text))
-            if len(temp_text) > 0:
+            if len(temp_text) > 1:
                 t0_tcp = int(float(temp_text[1])*1000)
             else:
                 main.log.error("Tshark output file for TCP"+
                         " returned unexpected results")
                 t0_tcp = 0
                 assertion = main.FALSE
+            
+            tcp_file.close()
             #****************
 
             #OF CAPTURE ****
-            ssh_of_file = subprocess.Popen(['ssh',
-                ONOS_user+"@"+ONOS1_ip, 'cat',
-                tshark_of_output], stdout=subprocess.PIPE)
-
+            os.system("scp "+ONOS_user+"@"+ONOS1_ip+":"+
+                    tshark_of_output+" /tmp/")
+            of_file = open(tshark_of_output, 'r')
+           
+            line_ofp = ""
             while True:
-                temp_text = ssh_of_file.stdout.readline()
-                if line !='':
+                temp_text = of_file.readline()
+                if temp_text !='':
                     line_ofp = temp_text
                 else:
                     break 
@@ -169,18 +190,36 @@
             main.log.info("Object read in from OFP capture: "+
                     str(line_ofp))
     
-            if len(line_ofp) > 0:
+            if len(line_ofp) > 1:
                 t0_ofp = int(float(obj[1])*1000)
             else:
                 main.log.error("Tshark output file for OFP"+
                         " returned unexpected results")
                 t0_ofp = 0
                 assertion = main.FALSE
+            
+            of_file.close()
             #****************
            
             #TODO: 
             #Get json object from all 3 ONOS instances
-            
+            json_str_1 = main.ONOS1cli.topology_events_metrics()
+            json_str_2 = main.ONOS2cli.topology_events_metrics()
+            json_str_3 = main.ONOS3cli.topology_events_metrics()
+    
+            #TESTING:
+            main.log.info(json_str_1)
+            main.log.info(json_str_2)
+            main.log.info(json_str_3)
+
+            json_obj_1 = json.loads(json_str_1)
+            json_obj_2 = json.loads(json_str_2)
+            json_obj_3 = json.loads(json_str_3)
+
+            main.log.info(json_obj_1)
+            main.log.info(json_obj_2)
+            main.log.info(json_obj_3)
+
             #TODO:
             #Parse json object for timestamp
             topo_timestamp_1 = 0
@@ -208,7 +247,153 @@
             main.log.info("ONOS2 delta TCP: "+str(delta_tcp_2))
             main.log.info("ONOS3 delta TCP: "+str(delta_tcp_3))
             
+            main.step("Remove switch from controller")
+            main.Mininet1.delete_sw_controller("s1")
 
+            time.sleep(5)
 
+        utilities.assert_equals(expect=main.TRUE, actual=assertion,
+                onpass="Switch latency test successful",
+                onfail="Switch latency test failed")
+        
 
+    def CASE3(self, main):
+        '''
+        Bring port up / down and measure latency.
+        Port enable / disable is simulated by ifconfig up / down
+        '''
+        import time
+        import subprocess
+        import os
+        import requests
+        import json
 
+        ONOS1_ip = main.params['CTRL']['ip1']
+        default_sw_port = main.params['CTRL']['port1']
+        ONOS_user = main.params['CTRL']['user']
+        num_iter = main.params['TEST']['numIter']
+
+        tshark_port_status = "OFP 130 Port Status"
+
+        tshark_port_up = "/tmp/tshark_port_up.txt"
+        tshark_port_down = "/tmp/tshark_port_down.txt"
+
+        main.log.report("Port enable / disable latency")
+
+        main.step("Assign switch to controller")
+        main.Mininet1.assign_sw_controller(sw="1",ip1=ONOS1_ip,
+                port1=default_sw_port)
+
+        main.step("Verify switch is assigned correctly")
+        result_s1 = main.Mininet1.get_sw_controller(sw="s1")
+        if result_s1 == main.FALSE:
+            main.log.info("Switch s1 was not assigned correctly")
+            assertion = main.FALSE
+        else:
+            main.log.info("Switch s1 was assigned correctly")
+
+        for i in range(0, int(num_iter)):
+            main.step("Starting wireshark capture for port status down")
+            main.ONOS1.tshark_grep(tshark_port_status,
+                    tshark_port_down)
+            
+            time.sleep(10)
+
+            main.step("Disable port (interface s1-eth2)")
+            main.Mininet2.handle.sendline("sudo ifconfig s1-eth2 down")
+            main.Mininet2.handle.expect("\$")
+            time.sleep(20)
+
+            main.ONOS1.tshark_stop()
+            time.sleep(5)
+            
+            #Copy tshark output file from ONOS to TestON instance
+            #/tmp directory
+            os.system("scp "+ONOS_user+"@"+ONOS1_ip+":"+
+                    tshark_port_down+" /tmp/")
+
+            f_port_down = open(tshark_port_down, 'r')
+            f_line = f_port_down.readline()
+            obj_down = f_line.split(" ")
+            if len(f_line) > 0:
+                timestamp_begin_pt_down = int(float(obj_down[1])*1000)
+            else:
+                main.log.info("Tshark output file returned unexpected"+
+                        " results")
+                timestamp_begin_pt_down = 0
+
+            main.step("Obtain t1 by REST call")
+            #TODO: Implement json object parsing here
+
+            timestamp_end_pt_down_1 = 0
+            timestamp_end_pt_down_2 = 0
+            timestamp_end_pt_down_3 = 0
+
+            delta_pt_down_1 = int(timestamp_end_pt_down_1) - \
+                    int(timestamp_begin_pt_down)
+            delta_pt_down_2 = int(timestamp_end_pt_down_2) - \
+                    int(timestamp_begin_pt_down)
+            delta_pt_down_3 = int(timestamp_end_pt_down_3) - \
+                    int(timestamp_begin_pt_down)
+           
+            #TODO: Remove these logs. For test purposes only
+            main.log.info("Delta1: "+str(delta_pt_down_1))
+            main.log.info("Delta2: "+str(delta_pt_down_2)) 
+            main.log.info("Delta3: "+str(delta_pt_down_3)) 
+        
+            #Port up events 
+            main.step("Enable port and obtain timestamp")
+            main.step("Starting wireshark capture for port status up")
+            main.ONOS1.tshark_grep("OFP 130 Port Status", tshark_port_up)
+            time.sleep(10)
+
+            main.Mininet2.handle.sendline("sudo ifconfig s1-eth2 up")
+            main.Mininet2.handle.expect("\$")
+            time.sleep(20)
+
+            os.system("scp "+ONOS_user+"@"+ONOS1_ip+":"+
+                    tshark_port_up+" /tmp/")
+
+            f_port_up = open(tshark_port_up, 'r')
+            f_line = f_port_down.readline()
+            obj_up = f_line.split(" ")
+            if len(f_line) > 0:
+                timestamp_begin_pt_up = int(float(obj_up[1])*1000)
+            else:
+                main.log.info("Tshark output file returned unexpected"+
+                        " results.")
+                timestamp_begin_pt_up = 0
+            
+            main.step("Obtain t1 by REST call")
+            #TODO: Implement json object parsing here
+
+            timestamp_end_pt_up_1 = 0
+            timestamp_end_pt_up_2 = 0
+            timestamp_end_pt_up_3 = 0
+
+            delta_pt_up_1 = int(timestamp_end_pt_up_1) - \
+                    int(timestamp_begin_pt_up)
+            delta_pt_up_2 = int(timestamp_end_pt_up_2) - \
+                    int(timestamp_begin_pt_up)
+            delta_pt_up_3 = int(timestamp_end_pt_up_3) - \
+                    int(timestamp_begin_pt_up)
+           
+            #TODO: Remove these logs. For test purposes only
+            main.log.info("Delta1: "+str(delta_pt_up_1))
+            main.log.info("Delta2: "+str(delta_pt_up_2)) 
+            main.log.info("Delta3: "+str(delta_pt_up_3)) 
+             
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
+            
diff --git a/TestON/tests/TopoPerfNext/TopoPerfNext.topo b/TestON/tests/TopoPerfNext/TopoPerfNext.topo
index 7d65d18..9ff8136 100644
--- a/TestON/tests/TopoPerfNext/TopoPerfNext.topo
+++ b/TestON/tests/TopoPerfNext/TopoPerfNext.topo
@@ -10,19 +10,37 @@
             <COMPONENTS> </COMPONENTS>
         </ONOSbench>
 
-        <ONOScli>
+        <ONOS1cli>
             <host>10.128.20.10</host>
             <user>admin</user>
             <password>onos_test</password>
             <type>OnosCliDriver</type>
             <connect_order>2</connect_order>
             <COMPONENTS> </COMPONENTS>
-        </ONOScli>
+        </ONOS1cli>
+
+        <ONOS2cli>
+            <host>10.128.20.10</host>
+            <user>admin</user>
+            <password>onos_test</password>
+            <type>OnosCliDriver</type>
+            <connect_order>2</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </ONOS2cli>
+        
+        <ONOS3cli>
+            <host>10.128.20.10</host>
+            <user>admin</user>
+            <password>onos_test</password>
+            <type>OnosCliDriver</type>
+            <connect_order>2</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </ONOS3cli>
 
         <ONOS1>
-            <host>10.128.20.11</host>
-            <user>sdn</user>
-            <password>sdn</password>
+            <host>10.128.174.1</host>
+            <user>admin</user>
+            <password>onos_test</password>
             <type>OnosDriver</type>
             <connect_order>3</connect_order>
             <COMPONENTS> </COMPONENTS>
@@ -36,11 +54,20 @@
             <connect_order>4</connect_order>
             <COMPONENTS>
                 <arg1> --custom topo-4fan.py </arg1>
-                <arg2> --arp --mac</arg2>
-                <arg3> --topo mytopo </arg3>
+                <arg2> --arp --mac --topo mytopo</arg2>
+                <arg3> </arg3>
                 <controller> remote </controller>
             </COMPONENTS>
         </Mininet1>
 
+        <Mininet2>
+            <host>10.128.10.90</host>
+            <user>admin</user>
+            <password>onos_test</password>
+            <type>RemoteMininetDriver</type>
+            <connect_order>5</connect_order>
+            <COMPONENTS> </COMPONENTS>
+        </Mininet2>
+
     </COMPONENT>
 </TOPOLOGY>