Merge "Added more functionality to flow test suite - Added MPLS class - Testing MPLS selector - Testing TCP selector - Testing UDP selector - Checks flow tables in Mininet"
diff --git a/TestON/drivers/common/api/controller/onosrestdriver.py b/TestON/drivers/common/api/controller/onosrestdriver.py
index 8b648b8..aae0d56 100644
--- a/TestON/drivers/common/api/controller/onosrestdriver.py
+++ b/TestON/drivers/common/api/controller/onosrestdriver.py
@@ -1161,6 +1161,9 @@
                  ipDst=(),
                  tcpSrc="",
                  tcpDst="",
+                 udpDst="",
+                 udpSrc="",
+                 mpls="",
                  ip="DEFAULT",
                  port="DEFAULT",
                  debug=False ):
@@ -1223,6 +1226,10 @@
                 flowJson[ 'selector' ][ 'criteria' ].append( {
                                                         "type":"VLAN_VID",
                                                         "vlanId":vlan } )
+            if mpls:
+                flowJson[ 'selector' ][ 'criteria' ].append( {
+                                                        "type":"MPLS_LABEL",
+                                                        "label":mpls } )
             if ipSrc:
                 flowJson[ 'selector' ][ 'criteria' ].append( {
                                                         "type":ipSrc[0],
@@ -1239,6 +1246,14 @@
                 flowJson[ 'selector' ][ 'criteria' ].append( {
                                                         "type":"TCP_DST",
                                                         "tcpPort": tcpDst } )
+            if udpSrc:
+                flowJson[ 'selector' ][ 'criteria' ].append( {
+                                                        "type":"UDP_SRC",
+                                                        "udpPort": udpSrc } )
+            if udpDst:
+                flowJson[ 'selector' ][ 'criteria' ].append( {
+                                                        "type":"UDP_DST",
+                                                        "udpPort": udpDst } )
             if ipProto:
                 flowJson[ 'selector' ][ 'criteria' ].append( {
                                                         "type":"IP_PROTO",
diff --git a/TestON/drivers/common/cli/emulator/mininetclidriver.py b/TestON/drivers/common/cli/emulator/mininetclidriver.py
index ff14fbe..7afcfa8 100644
--- a/TestON/drivers/common/cli/emulator/mininetclidriver.py
+++ b/TestON/drivers/common/cli/emulator/mininetclidriver.py
@@ -1900,65 +1900,6 @@
         else:
             main.log.error( "Connection failed to the Mininet host" )
 
-    def checkFlows( self, sw, dumpFormat=None ):
-        if dumpFormat:
-            command = "sh ovs-ofctl -F " + \
-                dumpFormat + " dump-flows " + str( sw )
-        else:
-            command = "sh ovs-ofctl dump-flows " + str( sw )
-        try:
-            response = self.execute(
-                cmd=command,
-                prompt="mininet>",
-                timeout=10 )
-            return response
-        except pexpect.EOF:
-            main.log.error( self.name + ": EOF exception found" )
-            main.log.error( self.name + ":     " + self.handle.before )
-            main.cleanup()
-            main.exit()
-
-    def getFlowTable( self, protoVersion, sw ):
-        """
-        Returns certain fields of an OVS flow table. Will force output to
-        either OF 1.0 or 1.3 format for consistency.
-
-        TODO add option to look at cookies. ignoring them for now
-
-         NOTE: Use format to force consistent flow table output across
-         versions
-        """
-        try:
-            self.handle.sendline( "" )
-            self.handle.expect( "mininet>" )
-            command = "sh ovs-ofctl dump-flows " + sw
-            if protoVersion == 1.0:
-                command += " -F OpenFlow10-table_id | awk '{OFS=\",\" ;" +\
-                           " print $1  $3  $6  $7  $8}' | "
-            elif protoVersion == 1.3:
-                command += " -O OpenFlow13 | awk '{OFS=\",\" ;" +\
-                           " print $1  $3  $6  $7}' | "
-            else:
-                main.log.error(
-                    "Unknown protoVersion in getFlowTable(). given: (" +
-                    str( type( protoVersion ) ) +
-                    ") '" + str( protoVersion ) + "'" )
-                return None
-            command += "cut -d ',' -f 2- | sort -n -k1 -r"
-            self.handle.sendline( command )
-            self.handle.expect( "sort" )
-            self.handle.expect( "OFPST_FLOW" )
-            response = self.handle.before
-            return response
-        except pexpect.EOF:
-            main.log.error( self.name + ": EOF exception found" )
-            main.log.error( self.name + ":     " + self.handle.before )
-            main.cleanup()
-            main.exit()
-        except pexpect.TIMEOUT:
-            main.log.exception( self.name + ": Timeout exception: " )
-            return None
-
     def flowComp( self, flow1, flow2 ):
         if flow1 == flow2:
             return main.TRUE
@@ -1970,6 +1911,145 @@
             main.log.info( flow2 )
             return main.FALSE
 
+    def parseFlowTable( self, flows, debug=True ):
+        '''
+        Discription: Parses flows into json format.
+        NOTE: this can parse any string thats separated with commas
+        Arguments:
+            Required:
+                flows: a list of strings that represnt flows
+            Optional:
+                version: The version of OpenFlow. Currently, 1.3 and 1.0 are supported.
+                debug: prints out the final result
+        returns: A list of flows in json format
+        '''
+        # Parse the flows
+        jsonFlows = []
+        for flow in flows:
+            # split on the comma
+            flow = flow.split(",")
+            # get rid of empty elements
+            flow = [f for f in flow if f != ""]
+            jsonFlow = {}
+            for f in flow:
+                # separate the key and the value
+                if "=" in f:
+                    f = f.split("=")
+                    key = f[0]
+                    # get rid of unwanted spaces
+                    if key[0] == " ": key = key[1:]
+                    val = f[1]
+                    jsonFlow.update( {key:val} )
+            jsonFlows.append( jsonFlow )
+
+        if debug: print "jsonFlows:\n{}\n\n".format(jsonFlows)
+
+        return jsonFlows
+
+    def getFlowTable( self, sw, version="1.3", debug=True):
+        '''
+        Discription: Returns the flow table(s) on a switch or switches in a list.
+            Each element is a flow.
+        Arguments:
+            Required:
+                sw: The switch name ("s1") to retrive the flow table. Can also be
+                    a list of switches.
+            Optional:
+                version: The version of OpenFlow. Currently, 1.3 and 1.0 are supported.
+                debug: prints out the final result
+        '''
+        try:
+            switches = []
+            if type(sw) is list:
+                switches.extends(sw)
+            else: switches.append(sw)
+
+            flows = []
+            for s in switches:
+                cmd = "sh ovs-ofctl dump-flows " + s
+
+                if "1.3" in version:
+                    cmd += " -O OpenFlow13"
+                else: cmd += " -F OpenFlow10-table_id"
+
+                main.log.info( "Sending: " + cmd )
+                self.handle.sendline( cmd )
+                self.handle.expect( "mininet>" )
+                response = self.handle.before
+                response = response.split( "\r\n" )
+                # dump the first two elements and the last
+                # the first element is the command that was sent
+                # the second is the table header
+                # the last element is empty
+                response = response[2:-1]
+                flows.extend( response )
+
+            if debug: print "Flows:\n{}\n\n".format(flows)
+
+            return self.parseFlowTable( flows, debug )
+
+        except pexpect.TIMEOUT:
+            main.log.exception( self.name + ": Command timed out" )
+            return None
+        except pexpect.EOF:
+            main.log.exception( self.name + ": connection closed." )
+            main.cleanup()
+            main.exit()
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.cleanup()
+            main.exit()
+
+    def checkFlowId( self, sw, flowId, version="1.3", debug=True ):
+        '''
+        Discription: Checks whether the ID provided matches a flow ID in Mininet
+        Arguments:
+            Required:
+                sw: The switch name ("s1") to retrive the flow table. Can also be
+                    a list of switches.
+                flowId: the flow ID in hex format. Can also be a list of IDs
+            Optional:
+                version: The version of OpenFlow. Currently, 1.3 and 1.0 are supported.
+                debug: prints out the final result
+        returns: main.TRUE if all IDs are present, otherwise returns main.FALSE
+        NOTE: prints out IDs that are not present
+        '''
+        try:
+            main.log.info( "Getting flows from Mininet" )
+            flows = self.getFlowTable( sw, version, debug )
+
+            if debug: print "flow ids:\n{}\n\n".format(flowId)
+
+            # Check flowId is a list or a string
+            if type( flowId ) is str:
+                result = False
+                for f in flows:
+                    if flowId in f.get( 'cookie' ):
+                        result = True
+                        break
+            # flowId is a list
+            else:
+                result = True
+                # Get flow IDs from Mininet
+                mnFlowIds = [ f.get( 'cookie' ) for f in flows ]
+                # Save the IDs that are not in Mininet
+                absentIds = [ x for x in flowId if x not in mnFlowIds ]
+
+                if debug: print "mn flow ids:\n{}\n\n".format(mnFlowIds)
+
+                # Print out the IDs that are not in Mininet
+                if absentIds:
+                    main.log.warn( "Absent ids: {}".format( absentIds ) )
+                    result = False
+
+            return main.TRUE if result else main.FALSE
+
+        except Exception:
+            main.log.exception( self.name + ": Uncaught exception!" )
+            main.cleanup()
+            main.exit()
+
+
     def startTcpdump( self, filename, intf="eth0", port="port 6653" ):
         """
            Runs tpdump on an interface and saves the file
@@ -2734,15 +2814,32 @@
             main.cleanup()
             main.exit()
 
-    def startScapy( self ):
+    def startScapy( self, mplsPath="" ):
         """
         Start the Scapy cli
+        optional:
+            mplsPath - The path where the MPLS class is located
+            NOTE: This can be a relative path from the user's home dir
         """
+        mplsLines = ['import imp',
+            'imp.load_source( "mplsClass", "{}mplsClass.py" )'.format(mplsPath),
+            'from mplsClass import MPLS',
+            'bind_layers(Ether, MPLS, type = 0x8847)',
+            'bind_layers(MPLS, MPLS, bottom_of_label_stack = 0)',
+            'bind_layers(MPLS, IP)']
+
         try:
             self.handle.sendline( "scapy" )
             self.handle.expect( self.scapyPrompt )
             self.handle.sendline( "conf.color_theme = NoTheme()" )
             self.handle.expect( self.scapyPrompt )
+            if mplsPath:
+                main.log.info( "Adding MPLS class" )
+                main.log.info( "MPLS class path: " + mplsPath )
+                for line in mplsLines:
+                    main.log.info( "sending line: " + line )
+                    self.handle.sendline( line )
+                    self.handle.expect( self.scapyPrompt )
             return main.TRUE
         except pexpect.TIMEOUT:
             main.log.exception( self.name + ": Command timed out" )
@@ -2949,13 +3046,17 @@
         left blank it will default to the below value unless it is
         overwritten by the next frame.
 
+        NOTE: Some arguments require quotes around them. It's up to you to
+        know which ones and to add them yourself. Arguments with an asterisk
+        do not need quotes.
+
         Options:
         ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
                     frame to use to encapsulate into
         Default frame:
         ###[ TCP ]###
-          sport= ftp_data
-          dport= http
+          sport= ftp_data *
+          dport= http *
           seq= 0
           ack= 0
           dataofs= None
@@ -2973,8 +3074,6 @@
             cmd = 'tcp = TCP( '
             options = []
             for key, value in kwargs.iteritems():
-                if isinstance( value, str ):
-                    value = '"' + value + '"'
                 options.append( str( key ) + "=" + str( value ) )
             cmd += ", ".join( options )
             cmd += ' )'
@@ -3018,13 +3117,17 @@
         left blank it will default to the below value unless it is
         overwritten by the next frame.
 
+        NOTE: Some arguments require quotes around them. It's up to you to
+        know which ones and to add them yourself. Arguments with an asterisk
+        do not need quotes.
+
         Options:
         ipVersion - Either 4 (default) or 6, indicates what Internet Protocol
                     frame to use to encapsulate into
         Default frame:
         ###[ UDP ]###
-          sport= domain
-          dport= domain
+          sport= domain *
+          dport= domain *
           len= None
           chksum= None
 
@@ -3035,8 +3138,6 @@
             cmd = 'udp = UDP( '
             options = []
             for key, value in kwargs.iteritems():
-                if isinstance( value, str ):
-                    value = '"' + value + '"'
                 options.append( str( key ) + "=" + str( value ) )
             cmd += ", ".join( options )
             cmd += ' )'
diff --git a/TestON/tests/FUNCflow/Dependency/mplsClass.py b/TestON/tests/FUNCflow/Dependency/mplsClass.py
new file mode 100644
index 0000000..30b27e8
--- /dev/null
+++ b/TestON/tests/FUNCflow/Dependency/mplsClass.py
@@ -0,0 +1,10 @@
+import scapy
+
+class MPLS(Packet):
+        name = "MPLS"
+        fields_desc =  [
+                BitField("label", 3, 20),
+                BitField("experimental_bits", 0, 3),
+                BitField("bottom_of_label_stack", 1, 1), # Now we're at the bottom
+                ByteField("TTL", 255)
+        ]
diff --git a/TestON/tests/FUNCflow/FUNCflow.params b/TestON/tests/FUNCflow/FUNCflow.params
index 7353e69..d1a3c58 100755
--- a/TestON/tests/FUNCflow/FUNCflow.params
+++ b/TestON/tests/FUNCflow/FUNCflow.params
@@ -8,17 +8,22 @@
     # 9 - Report logs
     # 10 - Start mininet and verify topology
     # 66 - Testing Scapy
-    # 1000 - Add flows with MAC selectors
-    # 1100 - Add flows with IPv4 selectors
-    # 1200 - Add flows with vlan selector
+    # 1000 - Add flows with MAC selector
+    # 1100 - Add flows with IPv4 selector
+    # 1200 - Add flows with VLAN selector
+    # 1300 - Add flows with MPLS selector
+    # 1400 - Add flows with TCP selectors
+    # 1500 - Add flows with UDP selectors
     # 2000 - Delete flows
 
-    <testcases>1,2,10,1000,2,1100,2,1200,100</testcases>
+    <testcases>1,2,10,1000,2000,1200,2000,1300,2000,1400,2000,1500,100</testcases>
 
     <SCALE>
         <max>1</max>
     </SCALE>
 
+    <DEBUG>on</DEBUG>
+
     <DEPENDENCY>
         <path>/tests/FUNCflow/Dependency/</path>
         <wrapper1>startUp</wrapper1>
@@ -42,9 +47,14 @@
 
     <TEST>
         <vlan>10</vlan>
+        <mpls>22</mpls>
+        <tcpDst>40001</tcpDst>
+        <udpDst>40051</udpDst>
         <ip4Type>2048</ip4Type>
-        <ip6Type>34525</ip6Type>
+        <tcpProto>6</tcpProto>
+        <udpProto>17</udpProto>
         <vlanType>33024</vlanType>
+        <mplsType>34887</mplsType>
         <swDPID>of:0000000000000001</swDPID>
     </TEST>
 
diff --git a/TestON/tests/FUNCflow/FUNCflow.py b/TestON/tests/FUNCflow/FUNCflow.py
index 0fa77a2..929596c 100644
--- a/TestON/tests/FUNCflow/FUNCflow.py
+++ b/TestON/tests/FUNCflow/FUNCflow.py
@@ -39,11 +39,14 @@
         main.startMNSleep = int( main.params[ 'SLEEP' ][ 'startMN' ] )
         main.addFlowSleep = int( main.params[ 'SLEEP' ][ 'addFlow' ] )
         main.delFlowSleep = int( main.params[ 'SLEEP' ][ 'delFlow' ] )
+        main.debug = main.params['DEBUG']
         main.swDPID = main.params[ 'TEST' ][ 'swDPID' ]
         main.cellData = {} # for creating cell file
         main.CLIs = []
         main.ONOSip = []
 
+        main.debug = True if "on" in main.debug else False
+
         main.ONOSip = main.ONOSbench.getOnosIps()
 
         # Assigning ONOS cli handles to a list
@@ -61,6 +64,7 @@
                                      wrapperFile2 +
                                      ".py" )
 
+
         copyResult = main.ONOSbench.scp( main.Mininet1,
                                          main.dependencyPath+main.topology,
                                          main.Mininet1.home+'/custom/',
@@ -398,7 +402,7 @@
                                             ingressPort=ingress,
                                             ethSrc=main.h1.hostMac,
                                             ethDst=main.h2.hostMac,
-                                            debug=True )
+                                            debug=main.debug )
 
         utilities.assert_equals( expect=main.TRUE,
                                  actual=stepResult,
@@ -410,7 +414,6 @@
 
         main.step( "Check flows are in the ADDED state" )
 
-        #TODO: We should check mininet if flows are added as well
         main.log.info( "Get the flows from ONOS" )
         flows = json.loads( main.ONOSrest.flows() )
 
@@ -426,6 +429,22 @@
                                  onpass="All flows are in the ADDED state",
                                  onfail="All flows are NOT in the ADDED state" )
 
+        main.step( "Check flows are in Mininet's flow table" )
+
+        # get the flow IDs that were added through rest
+        main.log.info( "Getting the flow IDs from ONOS" )
+        flowIds = [ f.get("id") for f in flows if "rest" in f.get("appId") ]
+        # convert the flowIDs to ints then hex and finally back to strings
+        flowIds = [str(hex(int(x))) for x in flowIds]
+        main.log.info( "ONOS flow IDs: {}".format(flowIds) )
+
+        stepResult = main.Mininet1.checkFlowId( "s1", flowIds, debug=False )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="All flows are in mininet",
+                                 onfail="All flows are NOT in mininet" )
+
         main.step( "Send a packet to verify the flows are correct" )
 
         # Specify the src and dst MAC addr
@@ -435,7 +454,7 @@
         # Filter for packets with the correct host name. Otherwise,
         # the filter we catch any packet that is sent to host2
         # NOTE: I believe it doesn't matter which host name it is,
-        # as long as its host1 or host2
+        # as long as the src and dst are both specified
         main.log.info( "Starting filter on host2" )
         main.h2.startFilter( pktFilter="ether host %s" % main.h1.hostMac)
 
@@ -499,7 +518,7 @@
                                             ethType=IPv4,
                                             ipSrc=("IPV4_SRC", main.h1.hostIp+"/32"),
                                             ipDst=("IPV4_DST", main.h2.hostIp+"/32"),
-                                            debug=True )
+                                            debug=main.debug )
 
         utilities.assert_equals( expect=main.TRUE,
                                  actual=stepResult,
@@ -526,6 +545,22 @@
                                  onpass="All flows are in the ADDED state",
                                  onfail="All flows are NOT in the ADDED state" )
 
+        main.step( "Check flows are in Mininet's flow table" )
+
+        # get the flow IDs that were added through rest
+        main.log.info( "Getting the flow IDs from ONOS" )
+        flowIds = [ f.get("id") for f in flows if "rest" in f.get("appId") ]
+        # convert the flowIDs to ints then hex and finally back to strings
+        flowIds = [str(hex(int(x))) for x in flowIds]
+        main.log.info( "ONOS flow IDs: {}".format(flowIds) )
+
+        stepResult = main.Mininet1.checkFlowId( "s1", flowIds, debug=False )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="All flows are in mininet",
+                                 onfail="All flows are NOT in mininet" )
+
         main.step( "Send a packet to verify the flow is correct" )
 
         main.log.info( "Constructing packet" )
@@ -598,7 +633,7 @@
                                             ingressPort=ingress,
                                             ethType=ethType,
                                             vlan=vlan,
-                                            debug=True )
+                                            debug=main.debug )
 
 
         utilities.assert_equals( expect=main.TRUE,
@@ -626,6 +661,22 @@
                                  onpass="All flows are in the ADDED state",
                                  onfail="All flows are NOT in the ADDED state" )
 
+        main.step( "Check flows are in Mininet's flow table" )
+
+        # get the flow IDs that were added through rest
+        main.log.info( "Getting the flow IDs from ONOS" )
+        flowIds = [ f.get("id") for f in flows if "rest" in f.get("appId") ]
+        # convert the flowIDs to ints then hex and finally back to strings
+        flowIds = [str(hex(int(x))) for x in flowIds]
+        main.log.info( "ONOS flow IDs: {}".format(flowIds) )
+
+        stepResult = main.Mininet1.checkFlowId( "s1", flowIds, debug=False )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="All flows are in mininet",
+                                 onfail="All flows are NOT in mininet" )
+
         main.step( "Send a packet to verify the flow are correct" )
 
         # The receiving interface
@@ -636,10 +687,10 @@
 
         # Broadcast the packet on the vlan interface. We only care if the flow forwards
         # the packet with the correct vlan tag, not if the mac addr is correct
-        BROADCAST = "FF:FF:FF:FF:FF:FF"
         sendIface = "{}-eth0.{}".format(main.h3.name, vlan)
         main.log.info( "Broadcasting the packet with a vlan tag" )
-        main.h3.sendPacket( iface=sendIface, packet="Ether(dst='{}')/Dot1Q(vlan={})".format(BROADCAST, vlan))
+        main.h3.sendPacket( iface=sendIface,
+                            packet="Ether()/Dot1Q(vlan={})".format(vlan) )
 
         main.log.info( "Checking filter for our packet" )
         stepResult = main.h4.checkFilter()
@@ -658,6 +709,369 @@
                                  onpass="Successfully sent a packet",
                                  onfail="Failed to send a packet" )
 
+    def CASE1300( self, main ):
+        '''
+            Add flows with MPLS selector and verify the flows
+        '''
+        import json
+        import time
+
+        main.case( "Verify the MPLS selector is correctly compiled on the flow." )
+        main.caseExplanation = "Install one flow with an MPLS selector, " +\
+                               "verify the flow is added in ONOS, and finally "+\
+                               "send a packet via scapy that has a MPLS label."
+
+        main.step( "Add a flow with a MPLS selector" )
+
+        main.log.info( "Creating host components" )
+        main.Mininet1.createHostComponent( "h1" )
+        main.Mininet1.createHostComponent( "h2" )
+        hosts = [main.h1, main.h2]
+        stepResult = main.TRUE
+        for host in hosts:
+            host.startHostCli()
+            host.startScapy( main.dependencyPath )
+            host.updateSelf()
+
+        # ports
+        egress = 2
+        ingress = 1
+        # MPLS etherType
+        ethType = main.params[ 'TEST' ][ 'mplsType' ]
+        # MPLS label
+        mplsLabel = main.params[ 'TEST' ][ 'mpls' ]
+
+        # Add a flow that connects host1 on port1 to host2 on port2
+        main.log.info( "Adding flow with MPLS selector" )
+        stepResult = main.ONOSrest.addFlow( deviceId=main.swDPID,
+                                            egressPort=egress,
+                                            ingressPort=ingress,
+                                            ethType=ethType,
+                                            mpls=mplsLabel,
+                                            debug=main.debug )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Successfully added flow",
+                                 onfail="Failed add flow" )
+
+        # Giving ONOS time to add the flow
+        time.sleep( main.addFlowSleep )
+
+        main.step( "Check flow is in the ADDED state" )
+
+        main.log.info( "Get the flows from ONOS" )
+        flows = json.loads( main.ONOSrest.flows() )
+
+        stepResult = main.TRUE
+        for f in flows:
+            if "rest" in f.get("appId"):
+                if "ADDED" not in f.get("state"):
+                    stepResult = main.FALSE
+                    main.log.error( "Flow: %s in state: %s" % (f.get("id"), f.get("state")) )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="All flows are in the ADDED state",
+                                 onfail="All flows are NOT in the ADDED state" )
+
+        main.step( "Check flows are in Mininet's flow table" )
+
+        # get the flow IDs that were added through rest
+        main.log.info( "Getting the flow IDs from ONOS" )
+        flowIds = [ f.get("id") for f in flows if "rest" in f.get("appId") ]
+        # convert the flowIDs to ints then hex and finally back to strings
+        flowIds = [str(hex(int(x))) for x in flowIds]
+        main.log.info( "ONOS flow IDs: {}".format(flowIds) )
+
+        stepResult = main.Mininet1.checkFlowId( "s1", flowIds, debug=True )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="All flows are in mininet",
+                                 onfail="All flows are NOT in mininet" )
+
+        main.step( "Send a packet to verify the flow is correct" )
+
+        main.log.info( "Starting filter on host2" )
+        main.h2.startFilter( pktFilter="mpls" )
+
+        main.log.info( "Constructing packet" )
+        main.log.info( "Sending packet to host2" )
+        main.h1.sendPacket( packet='Ether()/MPLS(label={})'.format(mplsLabel) )
+
+        main.log.info( "Checking filter for our packet" )
+        stepResult = main.h2.checkFilter()
+        if stepResult:
+            main.log.info( "Packet: %s" % main.h2.readPackets() )
+        else: main.h2.killFilter()
+
+        main.log.info( "Clean up host components" )
+        for host in hosts:
+            host.stopScapy()
+        main.Mininet1.removeHostComponent("h1")
+        main.Mininet1.removeHostComponent("h2")
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Successfully sent a packet",
+                                 onfail="Failed to send a packet" )
+
+    def CASE1400( self, main ):
+        '''
+            Add flows with a TCP selector and verify the flow
+        '''
+        import json
+        import time
+
+        main.case( "Verify the TCP selector is correctly compiled on the flow" )
+        main.caseExplanation = "Install a flow with only the TCP selector " +\
+                "specified, verify the flow is added in ONOS, and finally "+\
+                "send a TCP packet to verify the TCP selector is compiled correctly."
+
+        main.step( "Add a flow with a TCP selector" )
+
+        main.log.info( "Creating host components" )
+        main.Mininet1.createHostComponent( "h1" )
+        main.Mininet1.createHostComponent( "h2" )
+        hosts = [main.h1, main.h2]
+        stepResult = main.TRUE
+        for host in hosts:
+            host.startHostCli()
+            host.startScapy()
+            host.updateSelf()
+
+        # Add a flow that connects host1 on port1 to host2 on port2
+        egress = 2
+        ingress = 1
+        # IPv4 etherType
+        ethType = main.params[ 'TEST' ][ 'ip4Type' ]
+        # IP protocol
+        ipProto = main.params[ 'TEST' ][ 'tcpProto' ]
+        # TCP port destination
+        tcpDst = main.params[ 'TEST' ][ 'tcpDst' ]
+
+        main.log.info( "Add a flow that connects host1 on port1 to host2 on port2" )
+        stepResult = main.ONOSrest.addFlow( deviceId=main.swDPID,
+                                            egressPort=egress,
+                                            ingressPort=ingress,
+                                            ethType=ethType,
+                                            ipProto=ipProto,
+                                            tcpDst=tcpDst,
+                                            debug=main.debug )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Successfully added flows",
+                                 onfail="Failed add flows" )
+
+        # Giving ONOS time to add the flow
+        time.sleep( main.addFlowSleep )
+
+        main.step( "Check flow is in the ADDED state" )
+
+        main.log.info( "Get the flows from ONOS" )
+        flows = json.loads( main.ONOSrest.flows() )
+
+        stepResult = main.TRUE
+        for f in flows:
+            if "rest" in f.get("appId"):
+                if "ADDED" not in f.get("state"):
+                    stepResult = main.FALSE
+                    main.log.error( "Flow: %s in state: %s" % (f.get("id"), f.get("state")) )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="All flows are in the ADDED state",
+                                 onfail="All flows are NOT in the ADDED state" )
+
+        main.step( "Check flows are in Mininet's flow table" )
+
+        # get the flow IDs that were added through rest
+        main.log.info( "Getting the flow IDs from ONOS" )
+        flowIds = [ f.get("id") for f in flows if "rest" in f.get("appId") ]
+        # convert the flowIDs to ints then hex and finally back to strings
+        flowIds = [str(hex(int(x))) for x in flowIds]
+        main.log.info( "ONOS flow IDs: {}".format(flowIds) )
+
+        stepResult = main.Mininet1.checkFlowId( "s1", flowIds, debug=False )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="All flows are in mininet",
+                                 onfail="All flows are NOT in mininet" )
+
+        main.step( "Send a packet to verify the flow is correct" )
+
+        main.log.info( "Constructing packet" )
+        # No need for the MAC src dst
+        main.h1.buildEther( dst=main.h2.hostMac )
+        main.h1.buildIP( dst=main.h2.hostIp )
+        main.h1.buildTCP( dport=tcpDst )
+
+        main.log.info( "Starting filter on host2" )
+        # Defaults to ip
+        main.h2.startFilter( pktFilter="tcp" )
+
+        main.log.info( "Sending packet to host2" )
+        main.h1.sendPacket()
+
+        main.log.info( "Checking filter for our packet" )
+        stepResult = main.h2.checkFilter()
+        if stepResult:
+            main.log.info( "Packet: %s" % main.h2.readPackets() )
+        else: main.h2.killFilter()
+
+        main.log.info( "Clean up host components" )
+        for host in hosts:
+            host.stopScapy()
+        main.Mininet1.removeHostComponent("h1")
+        main.Mininet1.removeHostComponent("h2")
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Successfully sent a packet",
+                                 onfail="Failed to send a packet" )
+
+    def CASE1500( self, main ):
+        '''
+            Add flows with a UDP selector and verify the flow
+        '''
+        import json
+        import time
+
+        main.case( "Verify the UDP selector is correctly compiled on the flow" )
+        main.caseExplanation = "Install a flow with only the UDP selector " +\
+                "specified, verify the flow is added in ONOS, and finally "+\
+                "send a UDP packet to verify the UDP selector is compiled correctly."
+
+        main.step( "Add a flow with a UDP selector" )
+
+        main.log.info( "Creating host components" )
+        main.Mininet1.createHostComponent( "h1" )
+        main.Mininet1.createHostComponent( "h2" )
+        hosts = [main.h1, main.h2]
+        stepResult = main.TRUE
+        for host in hosts:
+            host.startHostCli()
+            host.startScapy()
+            host.updateSelf()
+
+        # Add a flow that connects host1 on port1 to host2 on port2
+        egress = 2
+        ingress = 1
+        # IPv4 etherType
+        ethType = main.params[ 'TEST' ][ 'ip4Type' ]
+        # IP protocol
+        ipProto = main.params[ 'TEST' ][ 'udpProto' ]
+        # UDP port destination
+        udpDst = main.params[ 'TEST' ][ 'udpDst' ]
+
+        main.log.info( "Add a flow that connects host1 on port1 to host2 on port2" )
+        stepResult = main.ONOSrest.addFlow( deviceId=main.swDPID,
+                                            egressPort=egress,
+                                            ingressPort=ingress,
+                                            ethType=ethType,
+                                            ipProto=ipProto,
+                                            udpDst=udpDst,
+                                            debug=main.debug )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Successfully added flows",
+                                 onfail="Failed add flows" )
+
+        # Giving ONOS time to add the flow
+        time.sleep( main.addFlowSleep )
+
+        main.step( "Check flow is in the ADDED state" )
+
+        main.log.info( "Get the flows from ONOS" )
+        flows = json.loads( main.ONOSrest.flows() )
+
+        stepResult = main.TRUE
+        for f in flows:
+            if "rest" in f.get("appId"):
+                if "ADDED" not in f.get("state"):
+                    stepResult = main.FALSE
+                    main.log.error( "Flow: %s in state: %s" % (f.get("id"), f.get("state")) )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="All flows are in the ADDED state",
+                                 onfail="All flows are NOT in the ADDED state" )
+
+        main.step( "Check flows are in Mininet's flow table" )
+
+        # get the flow IDs that were added through rest
+        main.log.info( "Getting the flow IDs from ONOS" )
+        flowIds = [ f.get("id") for f in flows if "rest" in f.get("appId") ]
+        # convert the flowIDs to ints then hex and finally back to strings
+        flowIds = [str(hex(int(x))) for x in flowIds]
+        main.log.info( "ONOS flow IDs: {}".format(flowIds) )
+
+        stepResult = main.Mininet1.checkFlowId( "s1", flowIds, debug=False )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="All flows are in mininet",
+                                 onfail="All flows are NOT in mininet" )
+
+        main.step( "Send a packet to verify the flow is correct" )
+
+        main.log.info( "Constructing packet" )
+        # No need for the MAC src dst
+        main.h1.buildEther( dst=main.h2.hostMac )
+        main.h1.buildIP( dst=main.h2.hostIp )
+        main.h1.buildUDP( dport=udpDst )
+
+        main.log.info( "Starting filter on host2" )
+        # Defaults to ip
+        main.h2.startFilter( pktFilter="udp" )
+
+        main.log.info( "Sending packet to host2" )
+        main.h1.sendPacket()
+
+        main.log.info( "Checking filter for our packet" )
+        stepResult = main.h2.checkFilter()
+        if stepResult:
+            main.log.info( "Packet: %s" % main.h2.readPackets() )
+        else: main.h2.killFilter()
+
+        main.log.info( "Clean up host components" )
+        for host in hosts:
+            host.stopScapy()
+        main.Mininet1.removeHostComponent("h1")
+        main.Mininet1.removeHostComponent("h2")
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Successfully sent a packet",
+                                 onfail="Failed to send a packet" )
+
+
+    def CASE2000( self, main ):
+        import json
+
+        main.case( "Delete flows that were added through rest" )
+        main.step("Deleting flows")
+
+        main.log.info( "Getting flows" )
+        flows = json.loads( main.ONOSrest.flows() )
+
+        stepResult = main.TRUE
+        for f in flows:
+            if "rest" in f.get("appId"):
+                if main.debug: main.log.debug( "Flow to be deleted:\n{}".format( main.ONOSrest.pprint(f) ) )
+                stepResult = stepResult and main.ONOSrest.removeFlow( f.get("deviceId"), f.get("id") )
+
+        utilities.assert_equals( expect=main.TRUE,
+                                 actual=stepResult,
+                                 onpass="Successfully deleting flows",
+                                 onfail="Failed to delete flows" )
+
+        time.sleep( main.delFlowSleep )
+
     def CASE100( self, main ):
         '''
             Report errors/warnings/exceptions
@@ -671,4 +1085,3 @@
                                     "ERROR",
                                     "Except" ],
                                   "s" )
-