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