blob: 1956392124002b87d5f534c92a55c40a7a7eca90 [file] [log] [blame]
Chetan Gaonker7ab338c2016-04-15 17:23:17 -07001import json
2import requests
3import os,sys,time
4from nose.tools import *
5from scapy.all import *
6from OnosCtrl import OnosCtrl
7
8class OnosFlowCtrl:
9
10 auth = ('karaf', 'karaf')
11 controller = os.getenv('ONOS_CONTROLLER_IP') or 'localhost'
12 cfg_url = 'http://%s:8181/onos/v1/flows/' %(controller)
13
14 def __init__( self,
15 deviceId,
16 appId=0,
17 ingressPort="",
18 egressPort="",
19 ethType="",
20 ethSrc="",
21 ethDst="",
22 vlan="",
23 ipProto="",
24 ipSrc=(),
25 ipDst=(),
26 tcpSrc="",
27 tcpDst="",
28 udpDst="",
29 udpSrc="",
30 mpls=""):
31 self.deviceId = deviceId
32 self.appId = appId
33 self.ingressPort = ingressPort
34 self.egressPort = egressPort
35 self.ethType = ethType
36 self.ethSrc = ethSrc
37 self.ethDst = ethDst
38 self.vlan = vlan
39 self.ipProto = ipProto
40 self.ipSrc = ipSrc
41 self.ipDst = ipDst
42 self.tcpSrc = tcpSrc
43 self.tcpDst = tcpDst
44 self.udpDst = udpDst
45 self.udpSrc = udpSrc
46 self.mpls = mpls
47
48 @classmethod
49 def get_flows(cls, device_id):
50 return OnosCtrl.get_flows(device_id)
51
52 def addFlow(self):
53 """
54 Description:
55 Creates a single flow in the specified device
56 Required:
57 * deviceId: id of the device
58 Optional:
59 * ingressPort: port ingress device
60 * egressPort: port of egress device
61 * ethType: specify ethType
62 * ethSrc: specify ethSrc ( i.e. src mac addr )
63 * ethDst: specify ethDst ( i.e. dst mac addr )
64 * ipProto: specify ip protocol
65 * ipSrc: specify ip source address with mask eg. ip#/24
66 as a tuple (type, ip#)
67 * ipDst: specify ip destination address eg. ip#/24
68 as a tuple (type, ip#)
69 * tcpSrc: specify tcp source port
70 * tcpDst: specify tcp destination port
71 Returns:
72 True for successful requests;
73 False for failure/error on requests
74 """
75 flowJson = { "priority":100,
76 "isPermanent":"true",
77 "timeout":0,
78 "deviceId":self.deviceId,
79 "treatment":{"instructions":[]},
80 "selector": {"criteria":[]}}
81 if self.appId:
82 flowJson[ "appId" ] = self.appId
83
84 if self.egressPort:
85 flowJson[ 'treatment' ][ 'instructions' ].append( {
86 "type":"OUTPUT",
87 "port":self.egressPort } )
88 if self.ingressPort:
89 flowJson[ 'selector' ][ 'criteria' ].append( {
90 "type":"IN_PORT",
91 "port":self.ingressPort } )
92 if self.ethType:
93 flowJson[ 'selector' ][ 'criteria' ].append( {
94 "type":"ETH_TYPE",
95 "ethType":self.ethType } )
96 if self.ethSrc:
97 flowJson[ 'selector' ][ 'criteria' ].append( {
98 "type":"ETH_SRC",
99 "mac":self.ethSrc } )
100 if self.ethDst:
101 flowJson[ 'selector' ][ 'criteria' ].append( {
102 "type":"ETH_DST",
103 "mac":self.ethDst } )
104 if self.vlan:
105 flowJson[ 'selector' ][ 'criteria' ].append( {
106 "type":"VLAN_VID",
107 "vlanId":self.vlan } )
108 if self.mpls:
109 flowJson[ 'selector' ][ 'criteria' ].append( {
110 "type":"MPLS_LABEL",
111 "label":self.mpls } )
112 if self.ipSrc:
113 flowJson[ 'selector' ][ 'criteria' ].append( {
114 "type":self.ipSrc[0],
115 "ip":self.ipSrc[1] } )
116 if self.ipDst:
117 flowJson[ 'selector' ][ 'criteria' ].append( {
118 "type":self.ipDst[0],
119 "ip":self.ipDst[1] } )
120 if self.tcpSrc:
121 flowJson[ 'selector' ][ 'criteria' ].append( {
122 "type":"TCP_SRC",
123 "tcpPort": self.tcpSrc } )
124 if self.tcpDst:
125 flowJson[ 'selector' ][ 'criteria' ].append( {
126 "type":"TCP_DST",
127 "tcpPort": self.tcpDst } )
128 if self.udpSrc:
129 flowJson[ 'selector' ][ 'criteria' ].append( {
130 "type":"UDP_SRC",
131 "udpPort": self.udpSrc } )
132 if self.udpDst:
133 flowJson[ 'selector' ][ 'criteria' ].append( {
134 "type":"UDP_DST",
135 "udpPort": self.udpDst } )
136 if self.ipProto:
137 flowJson[ 'selector' ][ 'criteria' ].append( {
138 "type":"IP_PROTO",
139 "protocol": self.ipProto } )
140
141 return self.sendFlow( deviceId=self.deviceId, flowJson=flowJson)
142
143 def removeFlow(self, deviceId, flowId):
144 """
145 Description:
146 Remove specific device flow
147 Required:
148 str deviceId - id of the device
149 str flowId - id of the flow
150 Return:
151 Returns True if successfully deletes flows, otherwise False
152 """
153 # NOTE: REST url requires the intent id to be in decimal form
154 query = self.cfg_url + str( deviceId ) + '/' + str( int( flowId ) )
155 response = requests.delete(query, auth = self.auth)
156 if response:
157 if 200 <= response.status_code <= 299:
158 return True
159 else:
160 return False
161
162 return True
163
164 def findFlow(self, deviceId, **criterias):
165 flows = self.get_flows(deviceId)
166 match_keys = criterias.keys()
167 matches = len(match_keys)
168 num_matched = 0
169 for f in flows:
170 criteria = f['selector']['criteria']
171 for c in criteria:
172 if c['type'] not in match_keys:
173 continue
174 match_key, match_val = criterias.get(c['type'])
175 val = c[match_key]
176 if val == match_val:
177 num_matched += 1
178 if num_matched == matches:
179 return f['id']
180 return None
181
182 def sendFlow(self, deviceId, flowJson):
183 """
184 Description:
185 Sends a single flow to the specified device. This function exists
186 so you can bypass the addFLow driver and send your own custom flow.
187 Required:
188 * The flow in json
189 * the device id to add the flow to
190 Returns:
191 True for successful requests
192 False for error on requests;
193 """
194 url = self.cfg_url + str(deviceId)
195 response = requests.post(url, auth = self.auth, data = json.dumps(flowJson) )
196 if response.ok:
197 if response.status_code in [200, 201]:
198 log.info('Successfully POSTED flow for device %s' %str(deviceId))
199 return True
200 else:
201 log.info('Post flow for device %s failed with status %d' %(str(deviceId),
202 response.status_code))
203 return False
204 else:
205 log.error('Flow post request returned with status %d' %response.status_code)
206
207 return False