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