blob: b1193f597ca41631d128a2c6fbc26fa0cb730e9d [file] [log] [blame]
Matteo Scandolo48d3d2d2017-08-08 13:05:27 -07001
2# Copyright 2017-present Open Networking Foundation
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
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# 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
16
ChetanGaonker720ea612016-06-21 17:54:25 -070017#
Chetan Gaonkercfcce782016-05-10 10:10:42 -070018# Copyright 2016-present Ciena Corporation
19#
20# Licensed under the Apache License, Version 2.0 (the "License");
21# you may not use this file except in compliance with the License.
22# You may obtain a copy of the License at
ChetanGaonker720ea612016-06-21 17:54:25 -070023#
Chetan Gaonkercfcce782016-05-10 10:10:42 -070024# http://www.apache.org/licenses/LICENSE-2.0
ChetanGaonker720ea612016-06-21 17:54:25 -070025#
Chetan Gaonkercfcce782016-05-10 10:10:42 -070026# Unless required by applicable law or agreed to in writing, software
27# distributed under the License is distributed on an "AS IS" BASIS,
28# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29# See the License for the specific language governing permissions and
30# limitations under the License.
31#
Chetan Gaonker7ab338c2016-04-15 17:23:17 -070032import json
33import requests
34import os,sys,time
35from nose.tools import *
A.R Karthick2e99c472017-03-22 19:13:51 -070036import logging
37logging.getLogger('scapy.runtime').setLevel(logging.ERROR)
A R Karthick456e9cf2016-10-03 14:37:44 -070038from OnosCtrl import OnosCtrl, get_controller
A R Karthick76a497a2017-04-12 10:59:39 -070039from CordTestUtils import log_test
Chetan Gaonker7ab338c2016-04-15 17:23:17 -070040
41class OnosFlowCtrl:
42
43 auth = ('karaf', 'karaf')
A R Karthick456e9cf2016-10-03 14:37:44 -070044 controller = get_controller()
Chetan Gaonker7ab338c2016-04-15 17:23:17 -070045 cfg_url = 'http://%s:8181/onos/v1/flows/' %(controller)
ChetanGaonker720ea612016-06-21 17:54:25 -070046
Chetan Gaonker7ab338c2016-04-15 17:23:17 -070047 def __init__( self,
48 deviceId,
49 appId=0,
50 ingressPort="",
51 egressPort="",
52 ethType="",
53 ethSrc="",
54 ethDst="",
55 vlan="",
56 ipProto="",
57 ipSrc=(),
58 ipDst=(),
59 tcpSrc="",
60 tcpDst="",
61 udpDst="",
62 udpSrc="",
ChetanGaonker720ea612016-06-21 17:54:25 -070063 mpls="",
64 dscp="",
65 icmpv4_type="",
66 icmpv4_code="",
67 icmpv6_type="",
68 icmpv6_code="",
69 ipv6flow_label="",
70 ecn="",
71 ipv6_target="",
72 ipv6_sll="",
73 ipv6_tll="",
ChetanGaonkerdbd4e4b2016-10-28 17:40:11 -070074 ipv6_extension="",
75 controller=None):
Chetan Gaonker7ab338c2016-04-15 17:23:17 -070076 self.deviceId = deviceId
77 self.appId = appId
78 self.ingressPort = ingressPort
79 self.egressPort = egressPort
80 self.ethType = ethType
81 self.ethSrc = ethSrc
82 self.ethDst = ethDst
83 self.vlan = vlan
84 self.ipProto = ipProto
85 self.ipSrc = ipSrc
86 self.ipDst = ipDst
87 self.tcpSrc = tcpSrc
88 self.tcpDst = tcpDst
89 self.udpDst = udpDst
90 self.udpSrc = udpSrc
91 self.mpls = mpls
ChetanGaonker720ea612016-06-21 17:54:25 -070092 self.dscp = dscp
93 self.icmpv4_type = icmpv4_type
94 self.icmpv4_code = icmpv4_code
95 self.icmpv6_type = icmpv6_type
96 self.icmpv6_code = icmpv6_code
97 self.ipv6flow_label = ipv6flow_label
98 self.ecn = ecn
99 self.ipv6_target = ipv6_target
100 self.ipv6_sll = ipv6_sll
101 self.ipv6_tll = ipv6_tll
102 self.ipv6_extension = ipv6_extension
ChetanGaonkerdbd4e4b2016-10-28 17:40:11 -0700103 if controller is not None:
104 self.controller=controller
105 self.cfg_url = 'http://%s:8181/onos/v1/flows/' %(self.controller)
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700106
107 @classmethod
ChetanGaonkerdbd4e4b2016-10-28 17:40:11 -0700108 def get_flows(cls, device_id,controller=None):
109 return OnosCtrl.get_flows(device_id,controller=controller)
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700110
111 def addFlow(self):
112 """
113 Description:
114 Creates a single flow in the specified device
115 Required:
116 * deviceId: id of the device
117 Optional:
118 * ingressPort: port ingress device
119 * egressPort: port of egress device
120 * ethType: specify ethType
121 * ethSrc: specify ethSrc ( i.e. src mac addr )
122 * ethDst: specify ethDst ( i.e. dst mac addr )
123 * ipProto: specify ip protocol
124 * ipSrc: specify ip source address with mask eg. ip#/24
125 as a tuple (type, ip#)
126 * ipDst: specify ip destination address eg. ip#/24
127 as a tuple (type, ip#)
128 * tcpSrc: specify tcp source port
129 * tcpDst: specify tcp destination port
130 Returns:
131 True for successful requests;
132 False for failure/error on requests
133 """
134 flowJson = { "priority":100,
135 "isPermanent":"true",
136 "timeout":0,
137 "deviceId":self.deviceId,
138 "treatment":{"instructions":[]},
139 "selector": {"criteria":[]}}
140 if self.appId:
141 flowJson[ "appId" ] = self.appId
ChetanGaonker720ea612016-06-21 17:54:25 -0700142
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700143 if self.egressPort:
144 flowJson[ 'treatment' ][ 'instructions' ].append( {
145 "type":"OUTPUT",
146 "port":self.egressPort } )
147 if self.ingressPort:
148 flowJson[ 'selector' ][ 'criteria' ].append( {
149 "type":"IN_PORT",
150 "port":self.ingressPort } )
151 if self.ethType:
152 flowJson[ 'selector' ][ 'criteria' ].append( {
153 "type":"ETH_TYPE",
154 "ethType":self.ethType } )
155 if self.ethSrc:
156 flowJson[ 'selector' ][ 'criteria' ].append( {
157 "type":"ETH_SRC",
158 "mac":self.ethSrc } )
159 if self.ethDst:
160 flowJson[ 'selector' ][ 'criteria' ].append( {
161 "type":"ETH_DST",
162 "mac":self.ethDst } )
163 if self.vlan:
164 flowJson[ 'selector' ][ 'criteria' ].append( {
165 "type":"VLAN_VID",
166 "vlanId":self.vlan } )
167 if self.mpls:
168 flowJson[ 'selector' ][ 'criteria' ].append( {
169 "type":"MPLS_LABEL",
170 "label":self.mpls } )
171 if self.ipSrc:
172 flowJson[ 'selector' ][ 'criteria' ].append( {
173 "type":self.ipSrc[0],
174 "ip":self.ipSrc[1] } )
175 if self.ipDst:
176 flowJson[ 'selector' ][ 'criteria' ].append( {
177 "type":self.ipDst[0],
178 "ip":self.ipDst[1] } )
179 if self.tcpSrc:
180 flowJson[ 'selector' ][ 'criteria' ].append( {
181 "type":"TCP_SRC",
182 "tcpPort": self.tcpSrc } )
183 if self.tcpDst:
184 flowJson[ 'selector' ][ 'criteria' ].append( {
185 "type":"TCP_DST",
186 "tcpPort": self.tcpDst } )
187 if self.udpSrc:
188 flowJson[ 'selector' ][ 'criteria' ].append( {
189 "type":"UDP_SRC",
190 "udpPort": self.udpSrc } )
191 if self.udpDst:
192 flowJson[ 'selector' ][ 'criteria' ].append( {
193 "type":"UDP_DST",
194 "udpPort": self.udpDst } )
195 if self.ipProto:
196 flowJson[ 'selector' ][ 'criteria' ].append( {
197 "type":"IP_PROTO",
198 "protocol": self.ipProto } )
ChetanGaonker720ea612016-06-21 17:54:25 -0700199 if self.dscp:
200 flowJson[ 'selector' ][ 'criteria' ].append( {
201 "type":"IP_DSCP",
202 "ipDscp": self.dscp } )
203
204 if self.icmpv4_type:
205 flowJson[ 'selector' ][ 'criteria' ].append( {
206 "type":'ICMPV4_TYPE',
207 "icmpType":self.icmpv4_type } )
208
209 if self.icmpv6_type:
210 flowJson[ 'selector' ][ 'criteria' ].append( {
211 "type":'ICMPV6_TYPE',
212 "icmpv6Type":self.icmpv6_type } )
213
214 if self.icmpv4_code:
215 flowJson[ 'selector' ][ 'criteria' ].append( {
216 "type":'ICMPV4_CODE',
217 "icmpCode": self.icmpv4_code } )
218
219 if self.icmpv6_code:
220 flowJson[ 'selector' ][ 'criteria' ].append( {
221 "type":'ICMPV6_CODE',
222 "icmpv6Code": self.icmpv6_code } )
223
224 if self.ipv6flow_label:
225 flowJson[ 'selector' ][ 'criteria' ].append( {
226 "type":'IPV6_FLABEL',
227 "flowLabel": self.ipv6flow_label } )
228
229 if self.ecn:
230 flowJson[ 'selector' ][ 'criteria' ].append( {
231 "type":"IP_ECN",
232 "ipEcn": self.ecn } )
233
234 if self.ipv6_target:
235 flowJson[ 'selector' ][ 'criteria' ].append( {
236 "type":'IPV6_ND_TARGET',
237 "targetAddress": self.ipv6_target } )
238
239 if self.ipv6_sll:
240 flowJson[ 'selector' ][ 'criteria' ].append( {
241 "type":'IPV6_ND_SLL',
242 "mac": self.ipv6_sll } )
243
244 if self.ipv6_tll:
245 flowJson[ 'selector' ][ 'criteria' ].append( {
246 "type":'IPV6_ND_TLL',
247 "mac": self.ipv6_tll } )
248
249
250 if self.ipv6_extension:
251 flowJson[ 'selector' ][ 'criteria' ].append( {
252 "type":'IPV6_EXTHDR',
253 "exthdrFlags": self.ipv6_extension } )
254
255
256
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700257
258 return self.sendFlow( deviceId=self.deviceId, flowJson=flowJson)
259
260 def removeFlow(self, deviceId, flowId):
261 """
262 Description:
263 Remove specific device flow
264 Required:
265 str deviceId - id of the device
266 str flowId - id of the flow
267 Return:
268 Returns True if successfully deletes flows, otherwise False
269 """
270 # NOTE: REST url requires the intent id to be in decimal form
271 query = self.cfg_url + str( deviceId ) + '/' + str( int( flowId ) )
272 response = requests.delete(query, auth = self.auth)
273 if response:
274 if 200 <= response.status_code <= 299:
275 return True
276 else:
277 return False
278
279 return True
280
281 def findFlow(self, deviceId, **criterias):
ChetanGaonkerdbd4e4b2016-10-28 17:40:11 -0700282 flows = self.get_flows(deviceId,controller=self.controller)
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700283 match_keys = criterias.keys()
284 matches = len(match_keys)
285 num_matched = 0
286 for f in flows:
287 criteria = f['selector']['criteria']
288 for c in criteria:
289 if c['type'] not in match_keys:
290 continue
291 match_key, match_val = criterias.get(c['type'])
292 val = c[match_key]
293 if val == match_val:
294 num_matched += 1
ChetanGaonker720ea612016-06-21 17:54:25 -0700295 if num_matched == matches:
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700296 return f['id']
297 return None
ChetanGaonker720ea612016-06-21 17:54:25 -0700298
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700299 def sendFlow(self, deviceId, flowJson):
300 """
301 Description:
302 Sends a single flow to the specified device. This function exists
303 so you can bypass the addFLow driver and send your own custom flow.
304 Required:
305 * The flow in json
306 * the device id to add the flow to
307 Returns:
308 True for successful requests
309 False for error on requests;
310 """
311 url = self.cfg_url + str(deviceId)
312 response = requests.post(url, auth = self.auth, data = json.dumps(flowJson) )
313 if response.ok:
314 if response.status_code in [200, 201]:
A R Karthick76a497a2017-04-12 10:59:39 -0700315 log_test.info('Successfully POSTED flow for device %s' %str(deviceId))
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700316 return True
317 else:
A R Karthick76a497a2017-04-12 10:59:39 -0700318 log_test.info('Post flow for device %s failed with status %d' %(str(deviceId),
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700319 response.status_code))
320 return False
321 else:
A R Karthick76a497a2017-04-12 10:59:39 -0700322 log_test.error('Flow post request returned with status %d' %response.status_code)
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700323
324 return False