blob: e56e02c5e77f8ee4f414c3e3ee334f94571596f8 [file] [log] [blame]
Chetan Gaonkercfcce782016-05-10 10:10:42 -07001#
2# 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
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#
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
Chetan Gaonker3533faa2016-04-25 17:50:14 -070030 return '0'*pad + ''.join(['%02x' %ord(char) for char in info[18:24]])
Chetan Gaonker7ab338c2016-04-15 17:23:17 -070031
32class OnosFlowCtrl:
33
34 auth = ('karaf', 'karaf')
35 controller = os.getenv('ONOS_CONTROLLER_IP') or 'localhost'
36 cfg_url = 'http://%s:8181/onos/v1/flows/' %(controller)
37
38 def __init__( self,
39 deviceId,
40 appId=0,
41 ingressPort="",
42 egressPort="",
43 ethType="",
44 ethSrc="",
45 ethDst="",
46 vlan="",
47 ipProto="",
48 ipSrc=(),
49 ipDst=(),
50 tcpSrc="",
51 tcpDst="",
52 udpDst="",
53 udpSrc="",
54 mpls=""):
55 self.deviceId = deviceId
56 self.appId = appId
57 self.ingressPort = ingressPort
58 self.egressPort = egressPort
59 self.ethType = ethType
60 self.ethSrc = ethSrc
61 self.ethDst = ethDst
62 self.vlan = vlan
63 self.ipProto = ipProto
64 self.ipSrc = ipSrc
65 self.ipDst = ipDst
66 self.tcpSrc = tcpSrc
67 self.tcpDst = tcpDst
68 self.udpDst = udpDst
69 self.udpSrc = udpSrc
70 self.mpls = mpls
71
72 @classmethod
73 def get_flows(cls, device_id):
74 return OnosCtrl.get_flows(device_id)
75
76 def addFlow(self):
77 """
78 Description:
79 Creates a single flow in the specified device
80 Required:
81 * deviceId: id of the device
82 Optional:
83 * ingressPort: port ingress device
84 * egressPort: port of egress device
85 * ethType: specify ethType
86 * ethSrc: specify ethSrc ( i.e. src mac addr )
87 * ethDst: specify ethDst ( i.e. dst mac addr )
88 * ipProto: specify ip protocol
89 * ipSrc: specify ip source address with mask eg. ip#/24
90 as a tuple (type, ip#)
91 * ipDst: specify ip destination address eg. ip#/24
92 as a tuple (type, ip#)
93 * tcpSrc: specify tcp source port
94 * tcpDst: specify tcp destination port
95 Returns:
96 True for successful requests;
97 False for failure/error on requests
98 """
99 flowJson = { "priority":100,
100 "isPermanent":"true",
101 "timeout":0,
102 "deviceId":self.deviceId,
103 "treatment":{"instructions":[]},
104 "selector": {"criteria":[]}}
105 if self.appId:
106 flowJson[ "appId" ] = self.appId
107
108 if self.egressPort:
109 flowJson[ 'treatment' ][ 'instructions' ].append( {
110 "type":"OUTPUT",
111 "port":self.egressPort } )
112 if self.ingressPort:
113 flowJson[ 'selector' ][ 'criteria' ].append( {
114 "type":"IN_PORT",
115 "port":self.ingressPort } )
116 if self.ethType:
117 flowJson[ 'selector' ][ 'criteria' ].append( {
118 "type":"ETH_TYPE",
119 "ethType":self.ethType } )
120 if self.ethSrc:
121 flowJson[ 'selector' ][ 'criteria' ].append( {
122 "type":"ETH_SRC",
123 "mac":self.ethSrc } )
124 if self.ethDst:
125 flowJson[ 'selector' ][ 'criteria' ].append( {
126 "type":"ETH_DST",
127 "mac":self.ethDst } )
128 if self.vlan:
129 flowJson[ 'selector' ][ 'criteria' ].append( {
130 "type":"VLAN_VID",
131 "vlanId":self.vlan } )
132 if self.mpls:
133 flowJson[ 'selector' ][ 'criteria' ].append( {
134 "type":"MPLS_LABEL",
135 "label":self.mpls } )
136 if self.ipSrc:
137 flowJson[ 'selector' ][ 'criteria' ].append( {
138 "type":self.ipSrc[0],
139 "ip":self.ipSrc[1] } )
140 if self.ipDst:
141 flowJson[ 'selector' ][ 'criteria' ].append( {
142 "type":self.ipDst[0],
143 "ip":self.ipDst[1] } )
144 if self.tcpSrc:
145 flowJson[ 'selector' ][ 'criteria' ].append( {
146 "type":"TCP_SRC",
147 "tcpPort": self.tcpSrc } )
148 if self.tcpDst:
149 flowJson[ 'selector' ][ 'criteria' ].append( {
150 "type":"TCP_DST",
151 "tcpPort": self.tcpDst } )
152 if self.udpSrc:
153 flowJson[ 'selector' ][ 'criteria' ].append( {
154 "type":"UDP_SRC",
155 "udpPort": self.udpSrc } )
156 if self.udpDst:
157 flowJson[ 'selector' ][ 'criteria' ].append( {
158 "type":"UDP_DST",
159 "udpPort": self.udpDst } )
160 if self.ipProto:
161 flowJson[ 'selector' ][ 'criteria' ].append( {
162 "type":"IP_PROTO",
163 "protocol": self.ipProto } )
164
165 return self.sendFlow( deviceId=self.deviceId, flowJson=flowJson)
166
167 def removeFlow(self, deviceId, flowId):
168 """
169 Description:
170 Remove specific device flow
171 Required:
172 str deviceId - id of the device
173 str flowId - id of the flow
174 Return:
175 Returns True if successfully deletes flows, otherwise False
176 """
177 # NOTE: REST url requires the intent id to be in decimal form
178 query = self.cfg_url + str( deviceId ) + '/' + str( int( flowId ) )
179 response = requests.delete(query, auth = self.auth)
180 if response:
181 if 200 <= response.status_code <= 299:
182 return True
183 else:
184 return False
185
186 return True
187
188 def findFlow(self, deviceId, **criterias):
189 flows = self.get_flows(deviceId)
190 match_keys = criterias.keys()
191 matches = len(match_keys)
192 num_matched = 0
193 for f in flows:
194 criteria = f['selector']['criteria']
195 for c in criteria:
196 if c['type'] not in match_keys:
197 continue
198 match_key, match_val = criterias.get(c['type'])
199 val = c[match_key]
200 if val == match_val:
201 num_matched += 1
202 if num_matched == matches:
203 return f['id']
204 return None
205
206 def sendFlow(self, deviceId, flowJson):
207 """
208 Description:
209 Sends a single flow to the specified device. This function exists
210 so you can bypass the addFLow driver and send your own custom flow.
211 Required:
212 * The flow in json
213 * the device id to add the flow to
214 Returns:
215 True for successful requests
216 False for error on requests;
217 """
218 url = self.cfg_url + str(deviceId)
219 response = requests.post(url, auth = self.auth, data = json.dumps(flowJson) )
220 if response.ok:
221 if response.status_code in [200, 201]:
222 log.info('Successfully POSTED flow for device %s' %str(deviceId))
223 return True
224 else:
225 log.info('Post flow for device %s failed with status %d' %(str(deviceId),
226 response.status_code))
227 return False
228 else:
229 log.error('Flow post request returned with status %d' %response.status_code)
230
231 return False