blob: dda7fbd090ae12641c868d12b090ecfeecdc996c [file] [log] [blame]
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +00001#! /usr/bin/env python
2# -*- Mode: python; py-indent-offset: 4; tab-width: 8; indent-tabs-mode: t; -*-
3
4import copy
5import pprint
6import os
7import sys
8import subprocess
9import json
10import argparse
11import io
12import time
13
14from flask import Flask, json, Response, render_template, make_response, request
15
16## Global Var ##
17ControllerIP = "127.0.0.1"
18ControllerPort = 8080
19ReadFromFile = ""
20
21DEBUG=0
22pp = pprint.PrettyPrinter(indent=4)
23
24app = Flask(__name__)
25
26## Worker Functions ##
27def log_error(txt):
28 print '%s' % (txt)
29
30def debug(txt):
31 if DEBUG:
32 print '%s' % (txt)
33
34def measurement_store_path_flow(flow_path):
35 flow_path_json = json.dumps(flow_path)
36
37 try:
38 command = "curl -s -H 'Content-Type: application/json' -d '%s' http://%s:%s/wm/flow/measurement-store-path/json" % (flow_path_json, ControllerIP, ControllerPort)
39 debug("measurement_store_path_flow %s" % command)
40 result = os.popen(command).read()
41 debug("result %s" % result)
42 # parsedResult = json.loads(result)
43 # debug("parsed %s" % parsedResult)
44 except:
45 log_error("Controller IF has issue")
46 exit(1)
47
48def extract_flow_args(my_args):
49 # Check the arguments
50 if len(my_args) < 6:
51 log_error(usage_msg)
52 exit(1)
53
54 # Extract the mandatory arguments
55 my_flow_id = my_args[0]
56 my_installer_id = my_args[1]
57 my_src_dpid = my_args[2]
58 my_src_port = my_args[3]
59 my_dst_dpid = my_args[4]
60 my_dst_port = my_args[5]
61
62 #
63 # Extract the "match" and "action" arguments
64 #
65 match = {}
66 matchInPortEnabled = True # NOTE: Enabled by default
67 actions = []
68 actionOutputEnabled = True # NOTE: Enabled by default
69 idx = 6
70 while idx < len(my_args):
71 action = {}
72 arg1 = my_args[idx]
73 idx = idx + 1
74 # Extract the second argument
75 if idx >= len(my_args):
76 error_arg = "ERROR: Missing or invalid '" + arg1 + "' argument"
77 log_error(error_arg)
78 log_error(usage_msg)
79 exit(1)
80 arg2 = my_args[idx]
81 idx = idx + 1
82
83 if arg1 == "matchInPort":
84 # Just mark whether inPort matching is enabled
85 matchInPortEnabled = arg2 in ['True', 'true']
86 # inPort = {}
87 # inPort['value'] = int(arg2, 0)
88 # match['inPort'] = inPort
89 ## match['matchInPort'] = True
90 elif arg1 == "matchSrcMac":
91 srcMac = {}
92 srcMac['value'] = arg2
93 match['srcMac'] = srcMac
94 # match['matchSrcMac'] = True
95 elif arg1 == "matchDstMac":
96 dstMac = {}
97 dstMac['value'] = arg2
98 match['dstMac'] = dstMac
99 # match['matchDstMac'] = True
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700100 elif arg1 == "matchEthernetFrameType":
101 match['ethernetFrameType'] = int(arg2, 0)
102 # match['matchEthernetFrameType'] = True
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000103 elif arg1 == "matchVlanId":
104 match['vlanId'] = int(arg2, 0)
105 # match['matchVlanId'] = True
106 elif arg1 == "matchVlanPriority":
107 match['vlanPriority'] = int(arg2, 0)
108 # match['matchVlanPriority'] = True
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000109 elif arg1 == "matchSrcIPv4Net":
110 srcIPv4Net = {}
111 srcIPv4Net['value'] = arg2
112 match['srcIPv4Net'] = srcIPv4Net
113 # match['matchSrcIPv4Net'] = True
114 elif arg1 == "matchDstIPv4Net":
115 dstIPv4Net = {}
116 dstIPv4Net['value'] = arg2
117 match['dstIPv4Net'] = dstIPv4Net
118 # match['matchDstIPv4Net'] = True
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700119 elif arg1 == "matchIpProto":
120 match['ipProto'] = int(arg2, 0)
121 # match['matchIpProto'] = True
122 elif arg1 == "matchIpToS":
123 match['ipToS'] = int(arg2, 0)
124 # match['matchIpToS'] = True
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000125 elif arg1 == "matchSrcTcpUdpPort":
126 match['srcTcpUdpPort'] = int(arg2, 0)
127 # match['matchSrcTcpUdpPort'] = True
128 elif arg1 == "matchDstTcpUdpPort":
129 match['dstTcpUdpPort'] = int(arg2, 0)
130 # match['matchDstTcpUdpPort'] = True
131 elif arg1 == "actionOutput":
132 # Just mark whether ACTION_OUTPUT action is enabled
133 actionOutputEnabled = arg2 in ['True', 'true']
134 #
135 # TODO: Complete the implementation for ACTION_OUTPUT
136 # actionOutput = {}
137 # outPort = {}
138 # outPort['value'] = int(arg2, 0)
139 # actionOutput['port'] = outPort
140 # actionOutput['maxLen'] = int(arg3, 0)
141 # action['actionOutput'] = actionOutput
142 # # action['actionType'] = 'ACTION_OUTPUT'
143 # actions.append(action)
144 #
145 elif arg1 == "actionSetVlanId":
146 vlanId = {}
147 vlanId['vlanId'] = int(arg2, 0)
148 action['actionSetVlanId'] = vlanId
149 # action['actionType'] = 'ACTION_SET_VLAN_VID'
150 actions.append(copy.deepcopy(action))
151 elif arg1 == "actionSetVlanPriority":
152 vlanPriority = {}
153 vlanPriority['vlanPriority'] = int(arg2, 0)
154 action['actionSetVlanPriority'] = vlanPriority
155 # action['actionType'] = 'ACTION_SET_VLAN_PCP'
156 actions.append(copy.deepcopy(action))
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000157 elif arg1 == "actionStripVlan":
158 stripVlan = {}
159 stripVlan['stripVlan'] = arg2 in ['True', 'true']
160 action['actionStripVlan'] = stripVlan
161 # action['actionType'] = 'ACTION_STRIP_VLAN'
162 actions.append(copy.deepcopy(action))
163 elif arg1 == "actionSetEthernetSrcAddr":
164 ethernetSrcAddr = {}
165 ethernetSrcAddr['value'] = arg2
166 setEthernetSrcAddr = {}
167 setEthernetSrcAddr['addr'] = ethernetSrcAddr
168 action['actionSetEthernetSrcAddr'] = setEthernetSrcAddr
169 # action['actionType'] = 'ACTION_SET_DL_SRC'
170 actions.append(copy.deepcopy(action))
171 elif arg1 == "actionSetEthernetDstAddr":
172 ethernetDstAddr = {}
173 ethernetDstAddr['value'] = arg2
174 setEthernetDstAddr = {}
175 setEthernetDstAddr['addr'] = ethernetDstAddr
176 action['actionSetEthernetDstAddr'] = setEthernetDstAddr
177 # action['actionType'] = 'ACTION_SET_DL_DST'
178 actions.append(copy.deepcopy(action))
179 elif arg1 == "actionSetIPv4SrcAddr":
180 IPv4SrcAddr = {}
181 IPv4SrcAddr['value'] = arg2
182 setIPv4SrcAddr = {}
183 setIPv4SrcAddr['addr'] = IPv4SrcAddr
184 action['actionSetIPv4SrcAddr'] = setIPv4SrcAddr
185 # action['actionType'] = 'ACTION_SET_NW_SRC'
186 actions.append(copy.deepcopy(action))
187 elif arg1 == "actionSetIPv4DstAddr":
188 IPv4DstAddr = {}
189 IPv4DstAddr['value'] = arg2
190 setIPv4DstAddr = {}
191 setIPv4DstAddr['addr'] = IPv4DstAddr
192 action['actionSetIPv4DstAddr'] = setIPv4DstAddr
193 # action['actionType'] = 'ACTION_SET_NW_DST'
194 actions.append(copy.deepcopy(action))
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700195 elif arg1 == "actionSetIpToS":
196 ipToS = {}
197 ipToS['ipToS'] = int(arg2, 0)
198 action['actionSetIpToS'] = ipToS
199 # action['actionType'] = 'ACTION_SET_NW_TOS'
200 actions.append(copy.deepcopy(action))
201 elif arg1 == "actionSetTcpUdpSrcPort":
202 tcpUdpSrcPort = {}
203 tcpUdpSrcPort['port'] = int(arg2, 0)
204 action['actionSetTcpUdpSrcPort'] = tcpUdpSrcPort
205 # action['actionType'] = 'ACTION_SET_TP_SRC'
206 actions.append(copy.deepcopy(action))
207 elif arg1 == "actionSetTcpUdpDstPort":
208 tcpUdpDstPort = {}
209 tcpUdpDstPort['port'] = int(arg2, 0)
210 action['actionSetTcpUdpDstPort'] = tcpUdpDstPort
211 # action['actionType'] = 'ACTION_SET_TP_DST'
212 actions.append(copy.deepcopy(action))
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000213 elif arg1 == "actionEnqueue":
214 # TODO: Implement ACTION_ENQUEUE
215 actionEnqueue = {}
216 # actionEnqueue['queueId'] = int(arg2, 0)
217 # enqueuePort = {}
218 # enqueuePort['value'] = int(arg3, 0)
219 # actionEnqueue['port'] = enqueuePort
220 # action['actionEnqueue'] = actionEnqueue
221 # # action['actionType'] = 'ACTION_ENQUEUE'
222 # actions.append(copy.deepcopy(action))
223 #
224 else:
225 log_error("ERROR: Unknown argument '%s'" % (arg1))
226 log_error(usage_msg)
227 exit(1)
228
229 return {
230 'my_flow_id' : my_flow_id,
231 'my_installer_id' : my_installer_id,
232 'my_src_dpid' : my_src_dpid,
233 'my_src_port' : my_src_port,
234 'my_dst_dpid' : my_dst_dpid,
235 'my_dst_port' : my_dst_port,
236 'match' : match,
237 'matchInPortEnabled' : matchInPortEnabled,
238 'actions' : actions,
239 'actionOutputEnabled' : actionOutputEnabled
240 }
241
242def compute_flow_path(parsed_args, data_path):
243
244 my_flow_id = parsed_args['my_flow_id']
245 my_installer_id = parsed_args['my_installer_id']
246 match = parsed_args['match']
247 matchInPortEnabled = parsed_args['matchInPortEnabled']
248 actions = parsed_args['actions']
249 actionOutputEnabled = parsed_args['actionOutputEnabled']
250 my_data_path = copy.deepcopy(data_path)
251
252 flow_id = {}
253 flow_id['value'] = my_flow_id
254 installer_id = {}
255 installer_id['value'] = my_installer_id
256
257 flow_path = {}
258 flow_path['flowId'] = flow_id
259 flow_path['installerId'] = installer_id
260
261 if (len(match) > 0):
262 flow_path['flowEntryMatch'] = copy.deepcopy(match)
263
264 #
265 # Add the match conditions to each flow entry
266 #
267 if (len(match) > 0) or matchInPortEnabled:
268 idx = 0
269 while idx < len(my_data_path['flowEntries']):
270 if matchInPortEnabled:
271 inPort = my_data_path['flowEntries'][idx]['inPort']
272 match['inPort'] = copy.deepcopy(inPort)
273 # match['matchInPort'] = True
274 my_data_path['flowEntries'][idx]['flowEntryMatch'] = copy.deepcopy(match)
275 idx = idx + 1
276
277 #
278 # Set the actions for each flow entry
279 # NOTE: The actions from the command line are aplied
280 # ONLY to the first flow entry.
281 #
282 # If ACTION_OUTPUT action is enabled, then apply it
283 # to each flow entry.
284 #
285 if (len(actions) > 0) or actionOutputEnabled:
286 idx = 0
287 while idx < len(my_data_path['flowEntries']):
288 if idx > 0:
289 actions = [] # Reset the actions for all but first entry
290 action = {}
291 outPort = my_data_path['flowEntries'][idx]['outPort']
292 actionOutput = {}
293 actionOutput['port'] = copy.deepcopy(outPort)
294 # actionOutput['maxLen'] = 0 # TODO: not used for now
295 action['actionOutput'] = copy.deepcopy(actionOutput)
296 # action['actionType'] = 'ACTION_OUTPUT'
297 actions.append(copy.deepcopy(action))
298
299 my_data_path['flowEntries'][idx]['flowEntryActions'] = copy.deepcopy(actions)
300 idx = idx + 1
301
302
303 flow_path['dataPath'] = my_data_path
304 debug("Flow Path: %s" % flow_path)
305 return flow_path
306
307def measurement_store_paths(parsed_args):
308 idx = 0
309 while idx < len(parsed_args):
310 data_path = {}
311 src_dpid = {}
312 src_port = {}
313 dst_dpid = {}
314 dst_port = {}
315 src_switch_port = {}
316 dst_switch_port = {}
317 flow_entries = []
318
319 src_dpid['value'] = parsed_args[idx]['my_src_dpid']
320 src_port['value'] = parsed_args[idx]['my_src_port']
321 dst_dpid['value'] = parsed_args[idx]['my_dst_dpid']
322 dst_port['value'] = parsed_args[idx]['my_dst_port']
323 src_switch_port['dpid'] = src_dpid
324 src_switch_port['port'] = src_port
325 dst_switch_port['dpid'] = dst_dpid
326 dst_switch_port['port'] = dst_port
327
328 data_path['srcPort'] = copy.deepcopy(src_switch_port)
329 data_path['dstPort'] = copy.deepcopy(dst_switch_port)
330 data_path['flowEntries'] = copy.deepcopy(flow_entries)
331
332 #
333 # XXX: Explicitly disable the InPort matching, and
334 # the Output action, because they get in the way
335 # during the compute_flow_path() processing.
336 #
337 parsed_args[idx]['matchInPortEnabled'] = False
338 parsed_args[idx]['actionOutputEnabled'] = False
339
340 flow_path = compute_flow_path(parsed_args[idx], data_path)
341 measurement_store_path_flow(flow_path)
342
343 idx = idx + 1
344
345
346if __name__ == "__main__":
347 usage_msg = "Store Flow Paths into ONOS for measurement purpose.\n"
348 usage_msg = usage_msg + "\n"
349 usage_msg = usage_msg + "Usage: %s [Flags] <flow-id> <installer-id> <src-dpid> <src-port> <dest-dpid> <dest-port> [Match Conditions] [Actions]\n" % (sys.argv[0])
350 usage_msg = usage_msg + "\n"
351 usage_msg = usage_msg + " Flags:\n"
352 usage_msg = usage_msg + " -f <filename> Read the flow(s) to install from a file\n"
353 usage_msg = usage_msg + " File format: one line per flow starting with <flow-id>\n"
354 usage_msg = usage_msg + "\n"
355 usage_msg = usage_msg + " Match Conditions:\n"
356 usage_msg = usage_msg + " matchInPort <True|False> (default to True)\n"
357 usage_msg = usage_msg + " matchSrcMac <source MAC address>\n"
358 usage_msg = usage_msg + " matchDstMac <destination MAC address>\n"
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000359 usage_msg = usage_msg + " matchEthernetFrameType <Ethernet frame type>\n"
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000360 usage_msg = usage_msg + " matchVlanId <VLAN ID>\n"
361 usage_msg = usage_msg + " matchVlanPriority <VLAN priority>\n"
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700362 usage_msg = usage_msg + " matchSrcIPv4Net <source IPv4 network address>\n"
363 usage_msg = usage_msg + " matchDstIPv4Net <destination IPv4 network address>\n"
364 usage_msg = usage_msg + "\n"
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000365 usage_msg = usage_msg + " matchIpProto <IP protocol>\n"
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700366 usage_msg = usage_msg + " matchIpToS <IP ToS (DSCP field, 6 bits)>\n"
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000367 usage_msg = usage_msg + " matchSrcTcpUdpPort <source TCP/UDP port>\n"
368 usage_msg = usage_msg + " matchDstTcpUdpPort <destination TCP/UDP port>\n"
369 usage_msg = usage_msg + "\n"
370 usage_msg = usage_msg + " Actions:\n"
371 usage_msg = usage_msg + " actionOutput <True|False> (default to True)\n"
372 usage_msg = usage_msg + " actionSetEthernetSrcAddr <source MAC address>\n"
373 usage_msg = usage_msg + " actionSetEthernetDstAddr <destination MAC address>\n"
374 usage_msg = usage_msg + " actionSetIPv4SrcAddr <source IPv4 address>\n"
375 usage_msg = usage_msg + " actionSetIPv4DstAddr <destination IPv4 address>\n"
376 usage_msg = usage_msg + "\n"
377 usage_msg = usage_msg + " Actions (not implemented yet):\n"
378 usage_msg = usage_msg + " actionSetVlanId <VLAN ID>\n"
379 usage_msg = usage_msg + " actionSetVlanPriority <VLAN priority>\n"
380 usage_msg = usage_msg + " actionSetIpToS <IP ToS (DSCP field, 6 bits)>\n"
381 usage_msg = usage_msg + " actionSetTcpUdpSrcPort <source TCP/UDP port>\n"
382 usage_msg = usage_msg + " actionSetTcpUdpDstPort <destination TCP/UDP port>\n"
383 usage_msg = usage_msg + " actionStripVlan <True|False>\n"
384 usage_msg = usage_msg + " actionEnqueue <dummy argument>\n"
385
386 # app.debug = False;
387
388 # Usage info
389 if len(sys.argv) > 1 and (sys.argv[1] == "-h" or sys.argv[1] == "--help"):
390 print(usage_msg)
391 exit(0)
392
393 #
394 # Check the flags
395 #
396 start_argv_index = 1
397 idx = 1
398 while idx < len(sys.argv):
399 arg1 = sys.argv[idx]
400 idx = idx + 1
401 if arg1 == "-f":
402 if idx >= len(sys.argv):
403 error_arg = "ERROR: Missing or invalid '" + arg1 + "' argument"
404 log_error(error_arg)
405 log_error(usage_msg)
406 exit(1)
407 ReadFromFile = sys.argv[idx]
408 idx = idx + 1
409 start_argv_index = idx
410 else:
411 break;
412
413 #
414 # Read the arguments from a file or from the remaining command line options
415 #
416 my_lines = []
417 if len(ReadFromFile) > 0:
418 f = open(ReadFromFile, "rt")
419 my_line = f.readline()
420 while my_line:
421 if len(my_line.rstrip()) > 0 and my_line[0] != "#":
422 my_token_line = my_line.rstrip().split()
423 my_lines.append(my_token_line)
424 my_line = f.readline()
425 else:
426 my_lines.append(copy.deepcopy(sys.argv[start_argv_index:]))
427
428 #
429 # Initialization
430 #
431 last_data_paths = []
432 parsed_args = []
433 idx = 0
434 while idx < len(my_lines):
435 last_data_path = []
436 last_data_paths.append(copy.deepcopy(last_data_path))
437 #
438 # Parse the flow arguments
439 #
440 my_args = my_lines[idx]
441 parsed_args.append(copy.deepcopy(extract_flow_args(my_args)))
442
443 idx = idx + 1
444
445 #
446 measurement_store_paths(parsed_args)