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