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