Adding new ONOS flow addition test-cases.
Also verifies traffic after adding mac and ipv4 selector flows in ONOS
diff --git a/src/test/utils/OnosFlowCtrl.py b/src/test/utils/OnosFlowCtrl.py
new file mode 100644
index 0000000..1956392
--- /dev/null
+++ b/src/test/utils/OnosFlowCtrl.py
@@ -0,0 +1,207 @@
+import json
+import requests
+import os,sys,time
+from nose.tools import *
+from scapy.all import *
+from OnosCtrl import OnosCtrl
+
+class OnosFlowCtrl:
+
+    auth = ('karaf', 'karaf')
+    controller = os.getenv('ONOS_CONTROLLER_IP') or 'localhost'
+    cfg_url = 'http://%s:8181/onos/v1/flows/' %(controller)
+    
+    def __init__( self,
+                  deviceId,
+                  appId=0,
+                  ingressPort="",
+                  egressPort="",
+                  ethType="",
+                  ethSrc="",
+                  ethDst="",
+                  vlan="",
+                  ipProto="",
+                  ipSrc=(),
+                  ipDst=(),
+                  tcpSrc="",
+                  tcpDst="",
+                  udpDst="",
+                  udpSrc="",
+                  mpls=""):
+        self.deviceId = deviceId
+        self.appId = appId
+        self.ingressPort = ingressPort
+        self.egressPort = egressPort
+        self.ethType = ethType
+        self.ethSrc = ethSrc
+        self.ethDst = ethDst
+        self.vlan = vlan
+        self.ipProto = ipProto
+        self.ipSrc = ipSrc
+        self.ipDst = ipDst
+        self.tcpSrc = tcpSrc
+        self.tcpDst = tcpDst
+        self.udpDst = udpDst
+        self.udpSrc = udpSrc
+        self.mpls = mpls
+
+    @classmethod
+    def get_flows(cls, device_id):
+        return OnosCtrl.get_flows(device_id)
+
+    def addFlow(self):
+        """
+        Description:
+            Creates a single flow in the specified device
+        Required:
+            * deviceId: id of the device
+        Optional:
+            * ingressPort: port ingress device
+            * egressPort: port  of egress device
+            * ethType: specify ethType
+            * ethSrc: specify ethSrc ( i.e. src mac addr )
+            * ethDst: specify ethDst ( i.e. dst mac addr )
+            * ipProto: specify ip protocol
+            * ipSrc: specify ip source address with mask eg. ip#/24
+                as a tuple (type, ip#)
+            * ipDst: specify ip destination address eg. ip#/24
+                as a tuple (type, ip#)
+            * tcpSrc: specify tcp source port
+            * tcpDst: specify tcp destination port
+        Returns:
+            True for successful requests;
+            False for failure/error on requests
+        """
+        flowJson = { "priority":100,
+                     "isPermanent":"true",
+                     "timeout":0,
+                     "deviceId":self.deviceId,
+                     "treatment":{"instructions":[]},
+                     "selector": {"criteria":[]}}
+        if self.appId:
+            flowJson[ "appId" ] = self.appId
+            
+        if self.egressPort:
+            flowJson[ 'treatment' ][ 'instructions' ].append( {
+                    "type":"OUTPUT",
+                    "port":self.egressPort } )
+        if self.ingressPort:
+            flowJson[ 'selector' ][ 'criteria' ].append( {
+                    "type":"IN_PORT",
+                    "port":self.ingressPort } )
+        if self.ethType:
+            flowJson[ 'selector' ][ 'criteria' ].append( {
+                    "type":"ETH_TYPE",
+                    "ethType":self.ethType } )
+        if self.ethSrc:
+            flowJson[ 'selector' ][ 'criteria' ].append( {
+                    "type":"ETH_SRC",
+                    "mac":self.ethSrc } )
+        if self.ethDst:
+            flowJson[ 'selector' ][ 'criteria' ].append( {
+                    "type":"ETH_DST",
+                    "mac":self.ethDst } )
+        if self.vlan:
+            flowJson[ 'selector' ][ 'criteria' ].append( {
+                    "type":"VLAN_VID",
+                    "vlanId":self.vlan } )
+        if self.mpls:
+            flowJson[ 'selector' ][ 'criteria' ].append( {
+                    "type":"MPLS_LABEL",
+                    "label":self.mpls } )
+        if self.ipSrc:
+            flowJson[ 'selector' ][ 'criteria' ].append( {
+                    "type":self.ipSrc[0],
+                    "ip":self.ipSrc[1] } )
+        if self.ipDst:
+            flowJson[ 'selector' ][ 'criteria' ].append( {
+                    "type":self.ipDst[0],
+                    "ip":self.ipDst[1] } )
+        if self.tcpSrc:
+            flowJson[ 'selector' ][ 'criteria' ].append( {
+                    "type":"TCP_SRC",
+                    "tcpPort": self.tcpSrc } )
+        if self.tcpDst:
+            flowJson[ 'selector' ][ 'criteria' ].append( {
+                    "type":"TCP_DST",
+                    "tcpPort": self.tcpDst } )
+        if self.udpSrc:
+            flowJson[ 'selector' ][ 'criteria' ].append( {
+                    "type":"UDP_SRC",
+                    "udpPort": self.udpSrc } )
+        if self.udpDst:
+            flowJson[ 'selector' ][ 'criteria' ].append( {
+                    "type":"UDP_DST",
+                    "udpPort": self.udpDst } )
+        if self.ipProto:
+            flowJson[ 'selector' ][ 'criteria' ].append( {
+                    "type":"IP_PROTO",
+                    "protocol": self.ipProto } )
+
+        return self.sendFlow( deviceId=self.deviceId, flowJson=flowJson)
+
+    def removeFlow(self, deviceId, flowId):
+        """
+        Description:
+            Remove specific device flow
+        Required:
+            str deviceId - id of the device
+            str flowId - id of the flow
+        Return:
+            Returns True if successfully deletes flows, otherwise False
+        """
+        # NOTE: REST url requires the intent id to be in decimal form
+        query = self.cfg_url + str( deviceId ) + '/' + str( int( flowId ) )
+        response = requests.delete(query, auth = self.auth)
+        if response:
+            if 200 <= response.status_code <= 299:
+                return True
+            else:
+                return False
+
+        return True
+
+    def findFlow(self, deviceId, **criterias):
+        flows = self.get_flows(deviceId)
+        match_keys = criterias.keys()
+        matches = len(match_keys)
+        num_matched = 0
+        for f in flows:
+            criteria = f['selector']['criteria']
+            for c in criteria:
+                if c['type'] not in match_keys:
+                    continue
+                match_key, match_val = criterias.get(c['type'])
+                val = c[match_key]
+                if val == match_val:
+                    num_matched += 1
+                if num_matched == matches:    
+                    return f['id']
+        return None
+                    
+    def sendFlow(self, deviceId, flowJson):
+        """
+        Description:
+            Sends a single flow to the specified device. This function exists
+            so you can bypass the addFLow driver and send your own custom flow.
+        Required:
+            * The flow in json
+            * the device id to add the flow to
+        Returns:
+            True for successful requests
+            False for error on requests;
+        """
+        url = self.cfg_url + str(deviceId)
+        response = requests.post(url, auth = self.auth, data = json.dumps(flowJson) )
+        if response.ok:
+            if response.status_code in [200, 201]:
+                log.info('Successfully POSTED flow for device %s' %str(deviceId))
+                return True
+            else:
+                log.info('Post flow for device %s failed with status %d' %(str(deviceId), 
+                                                                           response.status_code))
+                return False
+        else:
+            log.error('Flow post request returned with status %d' %response.status_code)
+
+        return False