blob: f1b72cfd838da31c8d54538c52ce1997fc34eacb [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 Gaonker3533faa2016-04-25 17:50:14 -070022import fcntl, socket, struct
23
24def get_mac(iface = 'ovsbr0', pad = 4):
25 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
Chetan Gaonkerfb3cb5e2016-05-06 11:55:44 -070026 try:
27 info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', iface[:15]))
28 except:
29 info = ['0'] * 24
A R Karthick8cf29ac2016-06-30 16:25:14 -070030 s.close()
31 sep = ''
32 if pad == 0:
33 sep = ':'
34 return '0'*pad + sep.join(['%02x' %ord(char) for char in info[18:24]])
Chetan Gaonker7ab338c2016-04-15 17:23:17 -070035
36class OnosFlowCtrl:
37
38 auth = ('karaf', 'karaf')
39 controller = os.getenv('ONOS_CONTROLLER_IP') or 'localhost'
40 cfg_url = 'http://%s:8181/onos/v1/flows/' %(controller)
ChetanGaonker720ea612016-06-21 17:54:25 -070041
Chetan Gaonker7ab338c2016-04-15 17:23:17 -070042 def __init__( self,
43 deviceId,
44 appId=0,
45 ingressPort="",
46 egressPort="",
47 ethType="",
48 ethSrc="",
49 ethDst="",
50 vlan="",
51 ipProto="",
52 ipSrc=(),
53 ipDst=(),
54 tcpSrc="",
55 tcpDst="",
56 udpDst="",
57 udpSrc="",
ChetanGaonker720ea612016-06-21 17:54:25 -070058 mpls="",
59 dscp="",
60 icmpv4_type="",
61 icmpv4_code="",
62 icmpv6_type="",
63 icmpv6_code="",
64 ipv6flow_label="",
65 ecn="",
66 ipv6_target="",
67 ipv6_sll="",
68 ipv6_tll="",
69 ipv6_extension=""):
Chetan Gaonker7ab338c2016-04-15 17:23:17 -070070 self.deviceId = deviceId
71 self.appId = appId
72 self.ingressPort = ingressPort
73 self.egressPort = egressPort
74 self.ethType = ethType
75 self.ethSrc = ethSrc
76 self.ethDst = ethDst
77 self.vlan = vlan
78 self.ipProto = ipProto
79 self.ipSrc = ipSrc
80 self.ipDst = ipDst
81 self.tcpSrc = tcpSrc
82 self.tcpDst = tcpDst
83 self.udpDst = udpDst
84 self.udpSrc = udpSrc
85 self.mpls = mpls
ChetanGaonker720ea612016-06-21 17:54:25 -070086 self.dscp = dscp
87 self.icmpv4_type = icmpv4_type
88 self.icmpv4_code = icmpv4_code
89 self.icmpv6_type = icmpv6_type
90 self.icmpv6_code = icmpv6_code
91 self.ipv6flow_label = ipv6flow_label
92 self.ecn = ecn
93 self.ipv6_target = ipv6_target
94 self.ipv6_sll = ipv6_sll
95 self.ipv6_tll = ipv6_tll
96 self.ipv6_extension = ipv6_extension
Chetan Gaonker7ab338c2016-04-15 17:23:17 -070097
98 @classmethod
99 def get_flows(cls, device_id):
100 return OnosCtrl.get_flows(device_id)
101
102 def addFlow(self):
103 """
104 Description:
105 Creates a single flow in the specified device
106 Required:
107 * deviceId: id of the device
108 Optional:
109 * ingressPort: port ingress device
110 * egressPort: port of egress device
111 * ethType: specify ethType
112 * ethSrc: specify ethSrc ( i.e. src mac addr )
113 * ethDst: specify ethDst ( i.e. dst mac addr )
114 * ipProto: specify ip protocol
115 * ipSrc: specify ip source address with mask eg. ip#/24
116 as a tuple (type, ip#)
117 * ipDst: specify ip destination address eg. ip#/24
118 as a tuple (type, ip#)
119 * tcpSrc: specify tcp source port
120 * tcpDst: specify tcp destination port
121 Returns:
122 True for successful requests;
123 False for failure/error on requests
124 """
125 flowJson = { "priority":100,
126 "isPermanent":"true",
127 "timeout":0,
128 "deviceId":self.deviceId,
129 "treatment":{"instructions":[]},
130 "selector": {"criteria":[]}}
131 if self.appId:
132 flowJson[ "appId" ] = self.appId
ChetanGaonker720ea612016-06-21 17:54:25 -0700133
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700134 if self.egressPort:
135 flowJson[ 'treatment' ][ 'instructions' ].append( {
136 "type":"OUTPUT",
137 "port":self.egressPort } )
138 if self.ingressPort:
139 flowJson[ 'selector' ][ 'criteria' ].append( {
140 "type":"IN_PORT",
141 "port":self.ingressPort } )
142 if self.ethType:
143 flowJson[ 'selector' ][ 'criteria' ].append( {
144 "type":"ETH_TYPE",
145 "ethType":self.ethType } )
146 if self.ethSrc:
147 flowJson[ 'selector' ][ 'criteria' ].append( {
148 "type":"ETH_SRC",
149 "mac":self.ethSrc } )
150 if self.ethDst:
151 flowJson[ 'selector' ][ 'criteria' ].append( {
152 "type":"ETH_DST",
153 "mac":self.ethDst } )
154 if self.vlan:
155 flowJson[ 'selector' ][ 'criteria' ].append( {
156 "type":"VLAN_VID",
157 "vlanId":self.vlan } )
158 if self.mpls:
159 flowJson[ 'selector' ][ 'criteria' ].append( {
160 "type":"MPLS_LABEL",
161 "label":self.mpls } )
162 if self.ipSrc:
163 flowJson[ 'selector' ][ 'criteria' ].append( {
164 "type":self.ipSrc[0],
165 "ip":self.ipSrc[1] } )
166 if self.ipDst:
167 flowJson[ 'selector' ][ 'criteria' ].append( {
168 "type":self.ipDst[0],
169 "ip":self.ipDst[1] } )
170 if self.tcpSrc:
171 flowJson[ 'selector' ][ 'criteria' ].append( {
172 "type":"TCP_SRC",
173 "tcpPort": self.tcpSrc } )
174 if self.tcpDst:
175 flowJson[ 'selector' ][ 'criteria' ].append( {
176 "type":"TCP_DST",
177 "tcpPort": self.tcpDst } )
178 if self.udpSrc:
179 flowJson[ 'selector' ][ 'criteria' ].append( {
180 "type":"UDP_SRC",
181 "udpPort": self.udpSrc } )
182 if self.udpDst:
183 flowJson[ 'selector' ][ 'criteria' ].append( {
184 "type":"UDP_DST",
185 "udpPort": self.udpDst } )
186 if self.ipProto:
187 flowJson[ 'selector' ][ 'criteria' ].append( {
188 "type":"IP_PROTO",
189 "protocol": self.ipProto } )
ChetanGaonker720ea612016-06-21 17:54:25 -0700190 if self.dscp:
191 flowJson[ 'selector' ][ 'criteria' ].append( {
192 "type":"IP_DSCP",
193 "ipDscp": self.dscp } )
194
195 if self.icmpv4_type:
196 flowJson[ 'selector' ][ 'criteria' ].append( {
197 "type":'ICMPV4_TYPE',
198 "icmpType":self.icmpv4_type } )
199
200 if self.icmpv6_type:
201 flowJson[ 'selector' ][ 'criteria' ].append( {
202 "type":'ICMPV6_TYPE',
203 "icmpv6Type":self.icmpv6_type } )
204
205 if self.icmpv4_code:
206 flowJson[ 'selector' ][ 'criteria' ].append( {
207 "type":'ICMPV4_CODE',
208 "icmpCode": self.icmpv4_code } )
209
210 if self.icmpv6_code:
211 flowJson[ 'selector' ][ 'criteria' ].append( {
212 "type":'ICMPV6_CODE',
213 "icmpv6Code": self.icmpv6_code } )
214
215 if self.ipv6flow_label:
216 flowJson[ 'selector' ][ 'criteria' ].append( {
217 "type":'IPV6_FLABEL',
218 "flowLabel": self.ipv6flow_label } )
219
220 if self.ecn:
221 flowJson[ 'selector' ][ 'criteria' ].append( {
222 "type":"IP_ECN",
223 "ipEcn": self.ecn } )
224
225 if self.ipv6_target:
226 flowJson[ 'selector' ][ 'criteria' ].append( {
227 "type":'IPV6_ND_TARGET',
228 "targetAddress": self.ipv6_target } )
229
230 if self.ipv6_sll:
231 flowJson[ 'selector' ][ 'criteria' ].append( {
232 "type":'IPV6_ND_SLL',
233 "mac": self.ipv6_sll } )
234
235 if self.ipv6_tll:
236 flowJson[ 'selector' ][ 'criteria' ].append( {
237 "type":'IPV6_ND_TLL',
238 "mac": self.ipv6_tll } )
239
240
241 if self.ipv6_extension:
242 flowJson[ 'selector' ][ 'criteria' ].append( {
243 "type":'IPV6_EXTHDR',
244 "exthdrFlags": self.ipv6_extension } )
245
246
247
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700248
249 return self.sendFlow( deviceId=self.deviceId, flowJson=flowJson)
250
251 def removeFlow(self, deviceId, flowId):
252 """
253 Description:
254 Remove specific device flow
255 Required:
256 str deviceId - id of the device
257 str flowId - id of the flow
258 Return:
259 Returns True if successfully deletes flows, otherwise False
260 """
261 # NOTE: REST url requires the intent id to be in decimal form
262 query = self.cfg_url + str( deviceId ) + '/' + str( int( flowId ) )
263 response = requests.delete(query, auth = self.auth)
264 if response:
265 if 200 <= response.status_code <= 299:
266 return True
267 else:
268 return False
269
270 return True
271
272 def findFlow(self, deviceId, **criterias):
273 flows = self.get_flows(deviceId)
274 match_keys = criterias.keys()
275 matches = len(match_keys)
276 num_matched = 0
277 for f in flows:
278 criteria = f['selector']['criteria']
279 for c in criteria:
280 if c['type'] not in match_keys:
281 continue
282 match_key, match_val = criterias.get(c['type'])
283 val = c[match_key]
284 if val == match_val:
285 num_matched += 1
ChetanGaonker720ea612016-06-21 17:54:25 -0700286 if num_matched == matches:
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700287 return f['id']
288 return None
ChetanGaonker720ea612016-06-21 17:54:25 -0700289
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700290 def sendFlow(self, deviceId, flowJson):
291 """
292 Description:
293 Sends a single flow to the specified device. This function exists
294 so you can bypass the addFLow driver and send your own custom flow.
295 Required:
296 * The flow in json
297 * the device id to add the flow to
298 Returns:
299 True for successful requests
300 False for error on requests;
301 """
302 url = self.cfg_url + str(deviceId)
303 response = requests.post(url, auth = self.auth, data = json.dumps(flowJson) )
304 if response.ok:
305 if response.status_code in [200, 201]:
306 log.info('Successfully POSTED flow for device %s' %str(deviceId))
307 return True
308 else:
ChetanGaonker720ea612016-06-21 17:54:25 -0700309 log.info('Post flow for device %s failed with status %d' %(str(deviceId),
Chetan Gaonker7ab338c2016-04-15 17:23:17 -0700310 response.status_code))
311 return False
312 else:
313 log.error('Flow post request returned with status %d' %response.status_code)
314
315 return False
ChetanGaonker720ea612016-06-21 17:54:25 -0700316