blob: 0e394654658bae29f154e10532a6cc50fbc28854 [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 #
Pavlin Radoslavov204b2862013-07-12 14:15:36 -070063 # Extract the "flowPathFlags", "match" and "action" arguments
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +000064 #
Pavlin Radoslavov204b2862013-07-12 14:15:36 -070065 flowPathFlags = 0L
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +000066 match = {}
67 matchInPortEnabled = True # NOTE: Enabled by default
68 actions = []
69 actionOutputEnabled = True # NOTE: Enabled by default
70 idx = 6
71 while idx < len(my_args):
72 action = {}
73 arg1 = my_args[idx]
74 idx = idx + 1
75 # Extract the second argument
76 if idx >= len(my_args):
77 error_arg = "ERROR: Missing or invalid '" + arg1 + "' argument"
78 log_error(error_arg)
79 log_error(usage_msg)
80 exit(1)
81 arg2 = my_args[idx]
82 idx = idx + 1
83
Pavlin Radoslavov204b2862013-07-12 14:15:36 -070084 if arg1 == "flowPathFlags":
85 if "DISCARD_FIRST_HOP_ENTRY" in arg2:
86 flowPathFlags = flowPathFlags + 0x1
87 if "KEEP_ONLY_FIRST_HOP_ENTRY" in arg2:
88 flowPathFlags = flowPathFlags + 0x2
89 elif arg1 == "matchInPort":
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -070090 # Mark whether ACTION_OUTPUT action is enabled
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +000091 matchInPortEnabled = arg2 in ['True', 'true']
92 # inPort = {}
93 # inPort['value'] = int(arg2, 0)
94 # match['inPort'] = inPort
95 ## match['matchInPort'] = True
96 elif arg1 == "matchSrcMac":
97 srcMac = {}
98 srcMac['value'] = arg2
99 match['srcMac'] = srcMac
100 # match['matchSrcMac'] = True
101 elif arg1 == "matchDstMac":
102 dstMac = {}
103 dstMac['value'] = arg2
104 match['dstMac'] = dstMac
105 # match['matchDstMac'] = True
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700106 elif arg1 == "matchEthernetFrameType":
107 match['ethernetFrameType'] = int(arg2, 0)
108 # match['matchEthernetFrameType'] = True
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000109 elif arg1 == "matchVlanId":
110 match['vlanId'] = int(arg2, 0)
111 # match['matchVlanId'] = True
112 elif arg1 == "matchVlanPriority":
113 match['vlanPriority'] = int(arg2, 0)
114 # match['matchVlanPriority'] = True
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000115 elif arg1 == "matchSrcIPv4Net":
116 srcIPv4Net = {}
117 srcIPv4Net['value'] = arg2
118 match['srcIPv4Net'] = srcIPv4Net
119 # match['matchSrcIPv4Net'] = True
120 elif arg1 == "matchDstIPv4Net":
121 dstIPv4Net = {}
122 dstIPv4Net['value'] = arg2
123 match['dstIPv4Net'] = dstIPv4Net
124 # match['matchDstIPv4Net'] = True
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700125 elif arg1 == "matchIpProto":
126 match['ipProto'] = int(arg2, 0)
127 # match['matchIpProto'] = True
128 elif arg1 == "matchIpToS":
129 match['ipToS'] = int(arg2, 0)
130 # match['matchIpToS'] = True
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000131 elif arg1 == "matchSrcTcpUdpPort":
132 match['srcTcpUdpPort'] = int(arg2, 0)
133 # match['matchSrcTcpUdpPort'] = True
134 elif arg1 == "matchDstTcpUdpPort":
135 match['dstTcpUdpPort'] = int(arg2, 0)
136 # match['matchDstTcpUdpPort'] = True
137 elif arg1 == "actionOutput":
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700138 # Mark whether ACTION_OUTPUT action is enabled
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000139 actionOutputEnabled = arg2 in ['True', 'true']
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700140 # If ACTION_OUTPUT is explicitly enabled, add an entry with a fake
141 # port number. We need this entry to preserve the action ordering.
142 if actionOutputEnabled == True:
143 actionOutput = {}
144 outPort = {}
145 outPort['value'] = 0xffff
146 actionOutput['port'] = outPort
147 actionOutput['maxLen'] = 0
148 action['actionOutput'] = actionOutput
149 # action['actionType'] = 'ACTION_OUTPUT'
150 actions.append(action)
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000151 #
152 elif arg1 == "actionSetVlanId":
153 vlanId = {}
154 vlanId['vlanId'] = int(arg2, 0)
155 action['actionSetVlanId'] = vlanId
156 # action['actionType'] = 'ACTION_SET_VLAN_VID'
157 actions.append(copy.deepcopy(action))
158 elif arg1 == "actionSetVlanPriority":
159 vlanPriority = {}
160 vlanPriority['vlanPriority'] = int(arg2, 0)
161 action['actionSetVlanPriority'] = vlanPriority
162 # action['actionType'] = 'ACTION_SET_VLAN_PCP'
163 actions.append(copy.deepcopy(action))
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000164 elif arg1 == "actionStripVlan":
165 stripVlan = {}
166 stripVlan['stripVlan'] = arg2 in ['True', 'true']
167 action['actionStripVlan'] = stripVlan
168 # action['actionType'] = 'ACTION_STRIP_VLAN'
169 actions.append(copy.deepcopy(action))
170 elif arg1 == "actionSetEthernetSrcAddr":
171 ethernetSrcAddr = {}
172 ethernetSrcAddr['value'] = arg2
173 setEthernetSrcAddr = {}
174 setEthernetSrcAddr['addr'] = ethernetSrcAddr
175 action['actionSetEthernetSrcAddr'] = setEthernetSrcAddr
176 # action['actionType'] = 'ACTION_SET_DL_SRC'
177 actions.append(copy.deepcopy(action))
178 elif arg1 == "actionSetEthernetDstAddr":
179 ethernetDstAddr = {}
180 ethernetDstAddr['value'] = arg2
181 setEthernetDstAddr = {}
182 setEthernetDstAddr['addr'] = ethernetDstAddr
183 action['actionSetEthernetDstAddr'] = setEthernetDstAddr
184 # action['actionType'] = 'ACTION_SET_DL_DST'
185 actions.append(copy.deepcopy(action))
186 elif arg1 == "actionSetIPv4SrcAddr":
187 IPv4SrcAddr = {}
188 IPv4SrcAddr['value'] = arg2
189 setIPv4SrcAddr = {}
190 setIPv4SrcAddr['addr'] = IPv4SrcAddr
191 action['actionSetIPv4SrcAddr'] = setIPv4SrcAddr
192 # action['actionType'] = 'ACTION_SET_NW_SRC'
193 actions.append(copy.deepcopy(action))
194 elif arg1 == "actionSetIPv4DstAddr":
195 IPv4DstAddr = {}
196 IPv4DstAddr['value'] = arg2
197 setIPv4DstAddr = {}
198 setIPv4DstAddr['addr'] = IPv4DstAddr
199 action['actionSetIPv4DstAddr'] = setIPv4DstAddr
200 # action['actionType'] = 'ACTION_SET_NW_DST'
201 actions.append(copy.deepcopy(action))
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700202 elif arg1 == "actionSetIpToS":
203 ipToS = {}
204 ipToS['ipToS'] = int(arg2, 0)
205 action['actionSetIpToS'] = ipToS
206 # action['actionType'] = 'ACTION_SET_NW_TOS'
207 actions.append(copy.deepcopy(action))
208 elif arg1 == "actionSetTcpUdpSrcPort":
209 tcpUdpSrcPort = {}
210 tcpUdpSrcPort['port'] = int(arg2, 0)
211 action['actionSetTcpUdpSrcPort'] = tcpUdpSrcPort
212 # action['actionType'] = 'ACTION_SET_TP_SRC'
213 actions.append(copy.deepcopy(action))
214 elif arg1 == "actionSetTcpUdpDstPort":
215 tcpUdpDstPort = {}
216 tcpUdpDstPort['port'] = int(arg2, 0)
217 action['actionSetTcpUdpDstPort'] = tcpUdpDstPort
218 # action['actionType'] = 'ACTION_SET_TP_DST'
219 actions.append(copy.deepcopy(action))
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000220 elif arg1 == "actionEnqueue":
221 # TODO: Implement ACTION_ENQUEUE
222 actionEnqueue = {}
223 # actionEnqueue['queueId'] = int(arg2, 0)
224 # enqueuePort = {}
225 # enqueuePort['value'] = int(arg3, 0)
226 # actionEnqueue['port'] = enqueuePort
227 # action['actionEnqueue'] = actionEnqueue
228 # # action['actionType'] = 'ACTION_ENQUEUE'
229 # actions.append(copy.deepcopy(action))
230 #
231 else:
232 log_error("ERROR: Unknown argument '%s'" % (arg1))
233 log_error(usage_msg)
234 exit(1)
235
236 return {
237 'my_flow_id' : my_flow_id,
238 'my_installer_id' : my_installer_id,
239 'my_src_dpid' : my_src_dpid,
240 'my_src_port' : my_src_port,
241 'my_dst_dpid' : my_dst_dpid,
242 'my_dst_port' : my_dst_port,
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700243 'flowPathFlags' : flowPathFlags,
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000244 'match' : match,
245 'matchInPortEnabled' : matchInPortEnabled,
246 'actions' : actions,
247 'actionOutputEnabled' : actionOutputEnabled
248 }
249
250def compute_flow_path(parsed_args, data_path):
251
252 my_flow_id = parsed_args['my_flow_id']
253 my_installer_id = parsed_args['my_installer_id']
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700254 myFlowPathFlags = parsed_args['flowPathFlags']
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000255 match = parsed_args['match']
256 matchInPortEnabled = parsed_args['matchInPortEnabled']
257 actions = parsed_args['actions']
258 actionOutputEnabled = parsed_args['actionOutputEnabled']
259 my_data_path = copy.deepcopy(data_path)
260
261 flow_id = {}
262 flow_id['value'] = my_flow_id
263 installer_id = {}
264 installer_id['value'] = my_installer_id
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700265 flowPathFlags = {}
266 flowPathFlags['flags'] = myFlowPathFlags
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000267
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700268 flowEntryActions = {}
269
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000270 flow_path = {}
271 flow_path['flowId'] = flow_id
272 flow_path['installerId'] = installer_id
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700273 flow_path['flowPathFlags'] = flowPathFlags
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000274
275 if (len(match) > 0):
276 flow_path['flowEntryMatch'] = copy.deepcopy(match)
277
278 #
279 # Add the match conditions to each flow entry
280 #
281 if (len(match) > 0) or matchInPortEnabled:
282 idx = 0
283 while idx < len(my_data_path['flowEntries']):
284 if matchInPortEnabled:
285 inPort = my_data_path['flowEntries'][idx]['inPort']
286 match['inPort'] = copy.deepcopy(inPort)
287 # match['matchInPort'] = True
288 my_data_path['flowEntries'][idx]['flowEntryMatch'] = copy.deepcopy(match)
289 idx = idx + 1
290
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700291
292 if (len(actions) > 0):
293 flowEntryActions['actions'] = copy.deepcopy(actions)
294 flow_path['flowEntryActions'] = flowEntryActions
295
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000296 #
297 # Set the actions for each flow entry
298 # NOTE: The actions from the command line are aplied
299 # ONLY to the first flow entry.
300 #
301 # If ACTION_OUTPUT action is enabled, then apply it
302 # to each flow entry.
303 #
304 if (len(actions) > 0) or actionOutputEnabled:
305 idx = 0
306 while idx < len(my_data_path['flowEntries']):
307 if idx > 0:
308 actions = [] # Reset the actions for all but first entry
309 action = {}
310 outPort = my_data_path['flowEntries'][idx]['outPort']
311 actionOutput = {}
312 actionOutput['port'] = copy.deepcopy(outPort)
313 # actionOutput['maxLen'] = 0 # TODO: not used for now
314 action['actionOutput'] = copy.deepcopy(actionOutput)
315 # action['actionType'] = 'ACTION_OUTPUT'
316 actions.append(copy.deepcopy(action))
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700317 flowEntryActions = {}
318 flowEntryActions['actions'] = copy.deepcopy(actions)
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000319
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700320 my_data_path['flowEntries'][idx]['flowEntryActions'] = flowEntryActions
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000321 idx = idx + 1
322
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000323 flow_path['dataPath'] = my_data_path
324 debug("Flow Path: %s" % flow_path)
325 return flow_path
326
327def measurement_store_paths(parsed_args):
328 idx = 0
329 while idx < len(parsed_args):
330 data_path = {}
331 src_dpid = {}
332 src_port = {}
333 dst_dpid = {}
334 dst_port = {}
335 src_switch_port = {}
336 dst_switch_port = {}
337 flow_entries = []
338
339 src_dpid['value'] = parsed_args[idx]['my_src_dpid']
340 src_port['value'] = parsed_args[idx]['my_src_port']
341 dst_dpid['value'] = parsed_args[idx]['my_dst_dpid']
342 dst_port['value'] = parsed_args[idx]['my_dst_port']
343 src_switch_port['dpid'] = src_dpid
344 src_switch_port['port'] = src_port
345 dst_switch_port['dpid'] = dst_dpid
346 dst_switch_port['port'] = dst_port
347
348 data_path['srcPort'] = copy.deepcopy(src_switch_port)
349 data_path['dstPort'] = copy.deepcopy(dst_switch_port)
350 data_path['flowEntries'] = copy.deepcopy(flow_entries)
351
352 #
353 # XXX: Explicitly disable the InPort matching, and
354 # the Output action, because they get in the way
355 # during the compute_flow_path() processing.
356 #
357 parsed_args[idx]['matchInPortEnabled'] = False
358 parsed_args[idx]['actionOutputEnabled'] = False
359
360 flow_path = compute_flow_path(parsed_args[idx], data_path)
361 measurement_store_path_flow(flow_path)
362
363 idx = idx + 1
364
365
366if __name__ == "__main__":
367 usage_msg = "Store Flow Paths into ONOS for measurement purpose.\n"
368 usage_msg = usage_msg + "\n"
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700369 usage_msg = usage_msg + "Usage: %s [Flags] <flow-id> <installer-id> <src-dpid> <src-port> <dest-dpid> <dest-port> [Flow Path Flags] [Match Conditions] [Actions]\n" % (sys.argv[0])
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000370 usage_msg = usage_msg + "\n"
371 usage_msg = usage_msg + " Flags:\n"
372 usage_msg = usage_msg + " -f <filename> Read the flow(s) to install from a file\n"
373 usage_msg = usage_msg + " File format: one line per flow starting with <flow-id>\n"
374 usage_msg = usage_msg + "\n"
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700375 usage_msg = usage_msg + " Flow Path Flags:\n"
376 usage_msg = usage_msg + " flowPathFlags <Flags> (flag names separated by ',')\n"
377 usage_msg = usage_msg + "\n"
378 usage_msg = usage_msg + " Known flags:\n"
379 usage_msg = usage_msg + " DISCARD_FIRST_HOP_ENTRY : Discard the first-hop flow entry\n"
380 usage_msg = usage_msg + " KEEP_ONLY_FIRST_HOP_ENTRY : Keep only the first-hop flow entry\n"
381 usage_msg = usage_msg + "\n"
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000382 usage_msg = usage_msg + " Match Conditions:\n"
383 usage_msg = usage_msg + " matchInPort <True|False> (default to True)\n"
384 usage_msg = usage_msg + " matchSrcMac <source MAC address>\n"
385 usage_msg = usage_msg + " matchDstMac <destination MAC address>\n"
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000386 usage_msg = usage_msg + " matchEthernetFrameType <Ethernet frame type>\n"
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000387 usage_msg = usage_msg + " matchVlanId <VLAN ID>\n"
388 usage_msg = usage_msg + " matchVlanPriority <VLAN priority>\n"
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700389 usage_msg = usage_msg + " matchSrcIPv4Net <source IPv4 network address>\n"
390 usage_msg = usage_msg + " matchDstIPv4Net <destination IPv4 network address>\n"
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000391 usage_msg = usage_msg + " matchIpProto <IP protocol>\n"
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700392 usage_msg = usage_msg + " matchIpToS <IP ToS (DSCP field, 6 bits)>\n"
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000393 usage_msg = usage_msg + " matchSrcTcpUdpPort <source TCP/UDP port>\n"
394 usage_msg = usage_msg + " matchDstTcpUdpPort <destination TCP/UDP port>\n"
395 usage_msg = usage_msg + "\n"
396 usage_msg = usage_msg + " Actions:\n"
397 usage_msg = usage_msg + " actionOutput <True|False> (default to True)\n"
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700398 usage_msg = usage_msg + " actionSetVlanId <VLAN ID>\n"
399 usage_msg = usage_msg + " actionSetVlanPriority <VLAN priority>\n"
400 usage_msg = usage_msg + " actionStripVlan <True|False>\n"
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000401 usage_msg = usage_msg + " actionSetEthernetSrcAddr <source MAC address>\n"
402 usage_msg = usage_msg + " actionSetEthernetDstAddr <destination MAC address>\n"
403 usage_msg = usage_msg + " actionSetIPv4SrcAddr <source IPv4 address>\n"
404 usage_msg = usage_msg + " actionSetIPv4DstAddr <destination IPv4 address>\n"
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000405 usage_msg = usage_msg + " actionSetIpToS <IP ToS (DSCP field, 6 bits)>\n"
406 usage_msg = usage_msg + " actionSetTcpUdpSrcPort <source TCP/UDP port>\n"
407 usage_msg = usage_msg + " actionSetTcpUdpDstPort <destination TCP/UDP port>\n"
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700408 usage_msg = usage_msg + " Actions (not implemented yet):\n"
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000409 usage_msg = usage_msg + " actionEnqueue <dummy argument>\n"
410
411 # app.debug = False;
412
413 # Usage info
414 if len(sys.argv) > 1 and (sys.argv[1] == "-h" or sys.argv[1] == "--help"):
415 print(usage_msg)
416 exit(0)
417
418 #
419 # Check the flags
420 #
421 start_argv_index = 1
422 idx = 1
423 while idx < len(sys.argv):
424 arg1 = sys.argv[idx]
425 idx = idx + 1
426 if arg1 == "-f":
427 if idx >= len(sys.argv):
428 error_arg = "ERROR: Missing or invalid '" + arg1 + "' argument"
429 log_error(error_arg)
430 log_error(usage_msg)
431 exit(1)
432 ReadFromFile = sys.argv[idx]
433 idx = idx + 1
434 start_argv_index = idx
435 else:
436 break;
437
438 #
439 # Read the arguments from a file or from the remaining command line options
440 #
441 my_lines = []
442 if len(ReadFromFile) > 0:
443 f = open(ReadFromFile, "rt")
444 my_line = f.readline()
445 while my_line:
446 if len(my_line.rstrip()) > 0 and my_line[0] != "#":
447 my_token_line = my_line.rstrip().split()
448 my_lines.append(my_token_line)
449 my_line = f.readline()
450 else:
451 my_lines.append(copy.deepcopy(sys.argv[start_argv_index:]))
452
453 #
454 # Initialization
455 #
456 last_data_paths = []
457 parsed_args = []
458 idx = 0
459 while idx < len(my_lines):
460 last_data_path = []
461 last_data_paths.append(copy.deepcopy(last_data_path))
462 #
463 # Parse the flow arguments
464 #
465 my_args = my_lines[idx]
466 parsed_args.append(copy.deepcopy(extract_flow_args(my_args)))
467
468 idx = idx + 1
469
470 #
471 measurement_store_paths(parsed_args)