blob: 5b2da525583d695cf9c2aab51ee801b22b288bae [file] [log] [blame]
ChetanGaonker720ea612016-06-21 17:54:25 -07001#
Chetan Gaonkercfcce782016-05-10 10:10:42 -07002# Copyright 2016-present Ciena Corporation
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
ChetanGaonker720ea612016-06-21 17:54:25 -07007#
Chetan Gaonkercfcce782016-05-10 10:10:42 -07008# http://www.apache.org/licenses/LICENSE-2.0
ChetanGaonker720ea612016-06-21 17:54:25 -07009#
Chetan Gaonkercfcce782016-05-10 10:10:42 -070010# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
Chetan Gaonker7ab338c2016-04-15 17:23:17 -070016import json
17import requests
18import os,sys,time
19from nose.tools import *
20from scapy.all import *
21from OnosCtrl import OnosCtrl
Chetan Gaonker7ab338c2016-04-15 17:23:17 -070022
23class OnosFlowCtrl:
24
25 auth = ('karaf', 'karaf')
A R Karthick2b93d6a2016-09-06 15:19:09 -070026 controller = OnosCtrl.get_controller()
Chetan Gaonker7ab338c2016-04-15 17:23:17 -070027 cfg_url = 'http://%s:8181/onos/v1/flows/' %(controller)
ChetanGaonker720ea612016-06-21 17:54:25 -070028
Chetan Gaonker7ab338c2016-04-15 17:23:17 -070029 def __init__( self,
30 deviceId,
31 appId=0,
32 ingressPort="",
33 egressPort="",
34 ethType="",
35 ethSrc="",
36 ethDst="",
37 vlan="",
38 ipProto="",
39 ipSrc=(),
40 ipDst=(),
41 tcpSrc="",
42 tcpDst="",
43 udpDst="",
44 udpSrc="",
ChetanGaonker720ea612016-06-21 17:54:25 -070045 mpls="",
46 dscp="",
47 icmpv4_type="",
48 icmpv4_code="",
49 icmpv6_type="",
50 icmpv6_code="",
51 ipv6flow_label="",
52 ecn="",
53 ipv6_target="",
54 ipv6_sll="",
55 ipv6_tll="",
56 ipv6_extension=""):
Chetan Gaonker7ab338c2016-04-15 17:23:17 -070057 self.deviceId = deviceId
58 self.appId = appId
59 self.ingressPort = ingressPort
60 self.egressPort = egressPort
61 self.ethType = ethType
62 self.ethSrc = ethSrc
63 self.ethDst = ethDst
64 self.vlan = vlan
65 self.ipProto = ipProto
66 self.ipSrc = ipSrc
67 self.ipDst = ipDst
68 self.tcpSrc = tcpSrc
69 self.tcpDst = tcpDst
70 self.udpDst = udpDst
71 self.udpSrc = udpSrc
72 self.mpls = mpls
ChetanGaonker720ea612016-06-21 17:54:25 -070073 self.dscp = dscp
74 self.icmpv4_type = icmpv4_type
75 self.icmpv4_code = icmpv4_code
76 self.icmpv6_type = icmpv6_type
77 self.icmpv6_code = icmpv6_code
78 self.ipv6flow_label = ipv6flow_label
79 self.ecn = ecn
80 self.ipv6_target = ipv6_target
81 self.ipv6_sll = ipv6_sll
82 self.ipv6_tll = ipv6_tll
83 self.ipv6_extension = ipv6_extension
Chetan Gaonker7ab338c2016-04-15 17:23:17 -070084
85 @classmethod
86 def get_flows(cls, device_id):
87 return OnosCtrl.get_flows(device_id)
88
89 def addFlow(self):
90 """
91 Description:
92 Creates a single flow in the specified device
93 Required:
94 * deviceId: id of the device
95 Optional:
96 * ingressPort: port ingress device
97 * egressPort: port of egress device
98 * ethType: specify ethType
99 * ethSrc: specify ethSrc ( i.e. src mac addr )
100 * ethDst: specify ethDst ( i.e. dst mac addr )
101 * ipProto: specify ip protocol
102 * ipSrc: specify ip source address with mask eg. ip#/24
103 as a tuple (type, ip#)
104 * ipDst: specify ip destination address eg. ip#/24
105 as a tuple (type, ip#)
106 * tcpSrc: specify tcp source port
107 * tcpDst: specify tcp destination port
108 Returns:
109 True for successful requests;
110 False for failure/error on requests
111 """
112 flowJson = { "priority":100,
113 "isPermanent":"true",
114 "timeout":0,
115 "deviceId":self.deviceId,
116 "treatment":{"instructions":[]},
117 "selector": {"criteria":[]}}
118 if self.appId:
119 flowJson[ "appId" ] = self.appId
ChetanGaonker720ea612016-06-21 17:54:25 -0700120
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700121 if self.egressPort:
122 flowJson[ 'treatment' ][ 'instructions' ].append( {
123 "type":"OUTPUT",
124 "port":self.egressPort } )
125 if self.ingressPort:
126 flowJson[ 'selector' ][ 'criteria' ].append( {
127 "type":"IN_PORT",
128 "port":self.ingressPort } )
129 if self.ethType:
130 flowJson[ 'selector' ][ 'criteria' ].append( {
131 "type":"ETH_TYPE",
132 "ethType":self.ethType } )
133 if self.ethSrc:
134 flowJson[ 'selector' ][ 'criteria' ].append( {
135 "type":"ETH_SRC",
136 "mac":self.ethSrc } )
137 if self.ethDst:
138 flowJson[ 'selector' ][ 'criteria' ].append( {
139 "type":"ETH_DST",
140 "mac":self.ethDst } )
141 if self.vlan:
142 flowJson[ 'selector' ][ 'criteria' ].append( {
143 "type":"VLAN_VID",
144 "vlanId":self.vlan } )
145 if self.mpls:
146 flowJson[ 'selector' ][ 'criteria' ].append( {
147 "type":"MPLS_LABEL",
148 "label":self.mpls } )
149 if self.ipSrc:
150 flowJson[ 'selector' ][ 'criteria' ].append( {
151 "type":self.ipSrc[0],
152 "ip":self.ipSrc[1] } )
153 if self.ipDst:
154 flowJson[ 'selector' ][ 'criteria' ].append( {
155 "type":self.ipDst[0],
156 "ip":self.ipDst[1] } )
157 if self.tcpSrc:
158 flowJson[ 'selector' ][ 'criteria' ].append( {
159 "type":"TCP_SRC",
160 "tcpPort": self.tcpSrc } )
161 if self.tcpDst:
162 flowJson[ 'selector' ][ 'criteria' ].append( {
163 "type":"TCP_DST",
164 "tcpPort": self.tcpDst } )
165 if self.udpSrc:
166 flowJson[ 'selector' ][ 'criteria' ].append( {
167 "type":"UDP_SRC",
168 "udpPort": self.udpSrc } )
169 if self.udpDst:
170 flowJson[ 'selector' ][ 'criteria' ].append( {
171 "type":"UDP_DST",
172 "udpPort": self.udpDst } )
173 if self.ipProto:
174 flowJson[ 'selector' ][ 'criteria' ].append( {
175 "type":"IP_PROTO",
176 "protocol": self.ipProto } )
ChetanGaonker720ea612016-06-21 17:54:25 -0700177 if self.dscp:
178 flowJson[ 'selector' ][ 'criteria' ].append( {
179 "type":"IP_DSCP",
180 "ipDscp": self.dscp } )
181
182 if self.icmpv4_type:
183 flowJson[ 'selector' ][ 'criteria' ].append( {
184 "type":'ICMPV4_TYPE',
185 "icmpType":self.icmpv4_type } )
186
187 if self.icmpv6_type:
188 flowJson[ 'selector' ][ 'criteria' ].append( {
189 "type":'ICMPV6_TYPE',
190 "icmpv6Type":self.icmpv6_type } )
191
192 if self.icmpv4_code:
193 flowJson[ 'selector' ][ 'criteria' ].append( {
194 "type":'ICMPV4_CODE',
195 "icmpCode": self.icmpv4_code } )
196
197 if self.icmpv6_code:
198 flowJson[ 'selector' ][ 'criteria' ].append( {
199 "type":'ICMPV6_CODE',
200 "icmpv6Code": self.icmpv6_code } )
201
202 if self.ipv6flow_label:
203 flowJson[ 'selector' ][ 'criteria' ].append( {
204 "type":'IPV6_FLABEL',
205 "flowLabel": self.ipv6flow_label } )
206
207 if self.ecn:
208 flowJson[ 'selector' ][ 'criteria' ].append( {
209 "type":"IP_ECN",
210 "ipEcn": self.ecn } )
211
212 if self.ipv6_target:
213 flowJson[ 'selector' ][ 'criteria' ].append( {
214 "type":'IPV6_ND_TARGET',
215 "targetAddress": self.ipv6_target } )
216
217 if self.ipv6_sll:
218 flowJson[ 'selector' ][ 'criteria' ].append( {
219 "type":'IPV6_ND_SLL',
220 "mac": self.ipv6_sll } )
221
222 if self.ipv6_tll:
223 flowJson[ 'selector' ][ 'criteria' ].append( {
224 "type":'IPV6_ND_TLL',
225 "mac": self.ipv6_tll } )
226
227
228 if self.ipv6_extension:
229 flowJson[ 'selector' ][ 'criteria' ].append( {
230 "type":'IPV6_EXTHDR',
231 "exthdrFlags": self.ipv6_extension } )
232
233
234
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700235
236 return self.sendFlow( deviceId=self.deviceId, flowJson=flowJson)
237
238 def removeFlow(self, deviceId, flowId):
239 """
240 Description:
241 Remove specific device flow
242 Required:
243 str deviceId - id of the device
244 str flowId - id of the flow
245 Return:
246 Returns True if successfully deletes flows, otherwise False
247 """
248 # NOTE: REST url requires the intent id to be in decimal form
249 query = self.cfg_url + str( deviceId ) + '/' + str( int( flowId ) )
250 response = requests.delete(query, auth = self.auth)
251 if response:
252 if 200 <= response.status_code <= 299:
253 return True
254 else:
255 return False
256
257 return True
258
259 def findFlow(self, deviceId, **criterias):
260 flows = self.get_flows(deviceId)
261 match_keys = criterias.keys()
262 matches = len(match_keys)
263 num_matched = 0
264 for f in flows:
265 criteria = f['selector']['criteria']
266 for c in criteria:
267 if c['type'] not in match_keys:
268 continue
269 match_key, match_val = criterias.get(c['type'])
270 val = c[match_key]
271 if val == match_val:
272 num_matched += 1
ChetanGaonker720ea612016-06-21 17:54:25 -0700273 if num_matched == matches:
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700274 return f['id']
275 return None
ChetanGaonker720ea612016-06-21 17:54:25 -0700276
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700277 def sendFlow(self, deviceId, flowJson):
278 """
279 Description:
280 Sends a single flow to the specified device. This function exists
281 so you can bypass the addFLow driver and send your own custom flow.
282 Required:
283 * The flow in json
284 * the device id to add the flow to
285 Returns:
286 True for successful requests
287 False for error on requests;
288 """
289 url = self.cfg_url + str(deviceId)
290 response = requests.post(url, auth = self.auth, data = json.dumps(flowJson) )
291 if response.ok:
292 if response.status_code in [200, 201]:
293 log.info('Successfully POSTED flow for device %s' %str(deviceId))
294 return True
295 else:
ChetanGaonker720ea612016-06-21 17:54:25 -0700296 log.info('Post flow for device %s failed with status %d' %(str(deviceId),
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700297 response.status_code))
298 return False
299 else:
300 log.error('Flow post request returned with status %d' %response.status_code)
301
302 return False
ChetanGaonker720ea612016-06-21 17:54:25 -0700303