blob: 844bc3ca3ff13f78916ee8f9bbf5b7911a141314 [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 *
A R Karthick456e9cf2016-10-03 14:37:44 -070021from OnosCtrl import OnosCtrl, get_controller
Chetan Gaonker7ab338c2016-04-15 17:23:17 -070022
23class OnosFlowCtrl:
24
25 auth = ('karaf', 'karaf')
A R Karthick456e9cf2016-10-03 14:37:44 -070026 controller = 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="",
ChetanGaonkerdbd4e4b2016-10-28 17:40:11 -070056 ipv6_extension="",
57 controller=None):
Chetan Gaonker7ab338c2016-04-15 17:23:17 -070058 self.deviceId = deviceId
59 self.appId = appId
60 self.ingressPort = ingressPort
61 self.egressPort = egressPort
62 self.ethType = ethType
63 self.ethSrc = ethSrc
64 self.ethDst = ethDst
65 self.vlan = vlan
66 self.ipProto = ipProto
67 self.ipSrc = ipSrc
68 self.ipDst = ipDst
69 self.tcpSrc = tcpSrc
70 self.tcpDst = tcpDst
71 self.udpDst = udpDst
72 self.udpSrc = udpSrc
73 self.mpls = mpls
ChetanGaonker720ea612016-06-21 17:54:25 -070074 self.dscp = dscp
75 self.icmpv4_type = icmpv4_type
76 self.icmpv4_code = icmpv4_code
77 self.icmpv6_type = icmpv6_type
78 self.icmpv6_code = icmpv6_code
79 self.ipv6flow_label = ipv6flow_label
80 self.ecn = ecn
81 self.ipv6_target = ipv6_target
82 self.ipv6_sll = ipv6_sll
83 self.ipv6_tll = ipv6_tll
84 self.ipv6_extension = ipv6_extension
ChetanGaonkerdbd4e4b2016-10-28 17:40:11 -070085 if controller is not None:
86 self.controller=controller
87 self.cfg_url = 'http://%s:8181/onos/v1/flows/' %(self.controller)
Chetan Gaonker7ab338c2016-04-15 17:23:17 -070088
89 @classmethod
ChetanGaonkerdbd4e4b2016-10-28 17:40:11 -070090 def get_flows(cls, device_id,controller=None):
91 return OnosCtrl.get_flows(device_id,controller=controller)
Chetan Gaonker7ab338c2016-04-15 17:23:17 -070092
93 def addFlow(self):
94 """
95 Description:
96 Creates a single flow in the specified device
97 Required:
98 * deviceId: id of the device
99 Optional:
100 * ingressPort: port ingress device
101 * egressPort: port of egress device
102 * ethType: specify ethType
103 * ethSrc: specify ethSrc ( i.e. src mac addr )
104 * ethDst: specify ethDst ( i.e. dst mac addr )
105 * ipProto: specify ip protocol
106 * ipSrc: specify ip source address with mask eg. ip#/24
107 as a tuple (type, ip#)
108 * ipDst: specify ip destination address eg. ip#/24
109 as a tuple (type, ip#)
110 * tcpSrc: specify tcp source port
111 * tcpDst: specify tcp destination port
112 Returns:
113 True for successful requests;
114 False for failure/error on requests
115 """
116 flowJson = { "priority":100,
117 "isPermanent":"true",
118 "timeout":0,
119 "deviceId":self.deviceId,
120 "treatment":{"instructions":[]},
121 "selector": {"criteria":[]}}
122 if self.appId:
123 flowJson[ "appId" ] = self.appId
ChetanGaonker720ea612016-06-21 17:54:25 -0700124
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700125 if self.egressPort:
126 flowJson[ 'treatment' ][ 'instructions' ].append( {
127 "type":"OUTPUT",
128 "port":self.egressPort } )
129 if self.ingressPort:
130 flowJson[ 'selector' ][ 'criteria' ].append( {
131 "type":"IN_PORT",
132 "port":self.ingressPort } )
133 if self.ethType:
134 flowJson[ 'selector' ][ 'criteria' ].append( {
135 "type":"ETH_TYPE",
136 "ethType":self.ethType } )
137 if self.ethSrc:
138 flowJson[ 'selector' ][ 'criteria' ].append( {
139 "type":"ETH_SRC",
140 "mac":self.ethSrc } )
141 if self.ethDst:
142 flowJson[ 'selector' ][ 'criteria' ].append( {
143 "type":"ETH_DST",
144 "mac":self.ethDst } )
145 if self.vlan:
146 flowJson[ 'selector' ][ 'criteria' ].append( {
147 "type":"VLAN_VID",
148 "vlanId":self.vlan } )
149 if self.mpls:
150 flowJson[ 'selector' ][ 'criteria' ].append( {
151 "type":"MPLS_LABEL",
152 "label":self.mpls } )
153 if self.ipSrc:
154 flowJson[ 'selector' ][ 'criteria' ].append( {
155 "type":self.ipSrc[0],
156 "ip":self.ipSrc[1] } )
157 if self.ipDst:
158 flowJson[ 'selector' ][ 'criteria' ].append( {
159 "type":self.ipDst[0],
160 "ip":self.ipDst[1] } )
161 if self.tcpSrc:
162 flowJson[ 'selector' ][ 'criteria' ].append( {
163 "type":"TCP_SRC",
164 "tcpPort": self.tcpSrc } )
165 if self.tcpDst:
166 flowJson[ 'selector' ][ 'criteria' ].append( {
167 "type":"TCP_DST",
168 "tcpPort": self.tcpDst } )
169 if self.udpSrc:
170 flowJson[ 'selector' ][ 'criteria' ].append( {
171 "type":"UDP_SRC",
172 "udpPort": self.udpSrc } )
173 if self.udpDst:
174 flowJson[ 'selector' ][ 'criteria' ].append( {
175 "type":"UDP_DST",
176 "udpPort": self.udpDst } )
177 if self.ipProto:
178 flowJson[ 'selector' ][ 'criteria' ].append( {
179 "type":"IP_PROTO",
180 "protocol": self.ipProto } )
ChetanGaonker720ea612016-06-21 17:54:25 -0700181 if self.dscp:
182 flowJson[ 'selector' ][ 'criteria' ].append( {
183 "type":"IP_DSCP",
184 "ipDscp": self.dscp } )
185
186 if self.icmpv4_type:
187 flowJson[ 'selector' ][ 'criteria' ].append( {
188 "type":'ICMPV4_TYPE',
189 "icmpType":self.icmpv4_type } )
190
191 if self.icmpv6_type:
192 flowJson[ 'selector' ][ 'criteria' ].append( {
193 "type":'ICMPV6_TYPE',
194 "icmpv6Type":self.icmpv6_type } )
195
196 if self.icmpv4_code:
197 flowJson[ 'selector' ][ 'criteria' ].append( {
198 "type":'ICMPV4_CODE',
199 "icmpCode": self.icmpv4_code } )
200
201 if self.icmpv6_code:
202 flowJson[ 'selector' ][ 'criteria' ].append( {
203 "type":'ICMPV6_CODE',
204 "icmpv6Code": self.icmpv6_code } )
205
206 if self.ipv6flow_label:
207 flowJson[ 'selector' ][ 'criteria' ].append( {
208 "type":'IPV6_FLABEL',
209 "flowLabel": self.ipv6flow_label } )
210
211 if self.ecn:
212 flowJson[ 'selector' ][ 'criteria' ].append( {
213 "type":"IP_ECN",
214 "ipEcn": self.ecn } )
215
216 if self.ipv6_target:
217 flowJson[ 'selector' ][ 'criteria' ].append( {
218 "type":'IPV6_ND_TARGET',
219 "targetAddress": self.ipv6_target } )
220
221 if self.ipv6_sll:
222 flowJson[ 'selector' ][ 'criteria' ].append( {
223 "type":'IPV6_ND_SLL',
224 "mac": self.ipv6_sll } )
225
226 if self.ipv6_tll:
227 flowJson[ 'selector' ][ 'criteria' ].append( {
228 "type":'IPV6_ND_TLL',
229 "mac": self.ipv6_tll } )
230
231
232 if self.ipv6_extension:
233 flowJson[ 'selector' ][ 'criteria' ].append( {
234 "type":'IPV6_EXTHDR',
235 "exthdrFlags": self.ipv6_extension } )
236
237
238
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700239
240 return self.sendFlow( deviceId=self.deviceId, flowJson=flowJson)
241
242 def removeFlow(self, deviceId, flowId):
243 """
244 Description:
245 Remove specific device flow
246 Required:
247 str deviceId - id of the device
248 str flowId - id of the flow
249 Return:
250 Returns True if successfully deletes flows, otherwise False
251 """
252 # NOTE: REST url requires the intent id to be in decimal form
253 query = self.cfg_url + str( deviceId ) + '/' + str( int( flowId ) )
254 response = requests.delete(query, auth = self.auth)
255 if response:
256 if 200 <= response.status_code <= 299:
257 return True
258 else:
259 return False
260
261 return True
262
263 def findFlow(self, deviceId, **criterias):
ChetanGaonkerdbd4e4b2016-10-28 17:40:11 -0700264 flows = self.get_flows(deviceId,controller=self.controller)
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700265 match_keys = criterias.keys()
266 matches = len(match_keys)
267 num_matched = 0
268 for f in flows:
269 criteria = f['selector']['criteria']
270 for c in criteria:
271 if c['type'] not in match_keys:
272 continue
273 match_key, match_val = criterias.get(c['type'])
274 val = c[match_key]
275 if val == match_val:
276 num_matched += 1
ChetanGaonker720ea612016-06-21 17:54:25 -0700277 if num_matched == matches:
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700278 return f['id']
279 return None
ChetanGaonker720ea612016-06-21 17:54:25 -0700280
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700281 def sendFlow(self, deviceId, flowJson):
282 """
283 Description:
284 Sends a single flow to the specified device. This function exists
285 so you can bypass the addFLow driver and send your own custom flow.
286 Required:
287 * The flow in json
288 * the device id to add the flow to
289 Returns:
290 True for successful requests
291 False for error on requests;
292 """
293 url = self.cfg_url + str(deviceId)
294 response = requests.post(url, auth = self.auth, data = json.dumps(flowJson) )
295 if response.ok:
296 if response.status_code in [200, 201]:
297 log.info('Successfully POSTED flow for device %s' %str(deviceId))
298 return True
299 else:
ChetanGaonker720ea612016-06-21 17:54:25 -0700300 log.info('Post flow for device %s failed with status %d' %(str(deviceId),
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700301 response.status_code))
302 return False
303 else:
304 log.error('Flow post request returned with status %d' %response.status_code)
305
306 return False
ChetanGaonker720ea612016-06-21 17:54:25 -0700307