blob: ad0eadf33335a4873477be4bb15ee4fcc0b9618d [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 Radoslavovcdda1f72013-05-07 23:19:38 +000090 # Just mark whether inPort matching is enabled
91 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":
138 # Just mark whether ACTION_OUTPUT action is enabled
139 actionOutputEnabled = arg2 in ['True', 'true']
140 #
141 # TODO: Complete the implementation for ACTION_OUTPUT
142 # actionOutput = {}
143 # outPort = {}
144 # outPort['value'] = int(arg2, 0)
145 # actionOutput['port'] = outPort
146 # actionOutput['maxLen'] = int(arg3, 0)
147 # action['actionOutput'] = actionOutput
148 # # action['actionType'] = 'ACTION_OUTPUT'
149 # actions.append(action)
150 #
151 elif arg1 == "actionSetVlanId":
152 vlanId = {}
153 vlanId['vlanId'] = int(arg2, 0)
154 action['actionSetVlanId'] = vlanId
155 # action['actionType'] = 'ACTION_SET_VLAN_VID'
156 actions.append(copy.deepcopy(action))
157 elif arg1 == "actionSetVlanPriority":
158 vlanPriority = {}
159 vlanPriority['vlanPriority'] = int(arg2, 0)
160 action['actionSetVlanPriority'] = vlanPriority
161 # action['actionType'] = 'ACTION_SET_VLAN_PCP'
162 actions.append(copy.deepcopy(action))
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000163 elif arg1 == "actionStripVlan":
164 stripVlan = {}
165 stripVlan['stripVlan'] = arg2 in ['True', 'true']
166 action['actionStripVlan'] = stripVlan
167 # action['actionType'] = 'ACTION_STRIP_VLAN'
168 actions.append(copy.deepcopy(action))
169 elif arg1 == "actionSetEthernetSrcAddr":
170 ethernetSrcAddr = {}
171 ethernetSrcAddr['value'] = arg2
172 setEthernetSrcAddr = {}
173 setEthernetSrcAddr['addr'] = ethernetSrcAddr
174 action['actionSetEthernetSrcAddr'] = setEthernetSrcAddr
175 # action['actionType'] = 'ACTION_SET_DL_SRC'
176 actions.append(copy.deepcopy(action))
177 elif arg1 == "actionSetEthernetDstAddr":
178 ethernetDstAddr = {}
179 ethernetDstAddr['value'] = arg2
180 setEthernetDstAddr = {}
181 setEthernetDstAddr['addr'] = ethernetDstAddr
182 action['actionSetEthernetDstAddr'] = setEthernetDstAddr
183 # action['actionType'] = 'ACTION_SET_DL_DST'
184 actions.append(copy.deepcopy(action))
185 elif arg1 == "actionSetIPv4SrcAddr":
186 IPv4SrcAddr = {}
187 IPv4SrcAddr['value'] = arg2
188 setIPv4SrcAddr = {}
189 setIPv4SrcAddr['addr'] = IPv4SrcAddr
190 action['actionSetIPv4SrcAddr'] = setIPv4SrcAddr
191 # action['actionType'] = 'ACTION_SET_NW_SRC'
192 actions.append(copy.deepcopy(action))
193 elif arg1 == "actionSetIPv4DstAddr":
194 IPv4DstAddr = {}
195 IPv4DstAddr['value'] = arg2
196 setIPv4DstAddr = {}
197 setIPv4DstAddr['addr'] = IPv4DstAddr
198 action['actionSetIPv4DstAddr'] = setIPv4DstAddr
199 # action['actionType'] = 'ACTION_SET_NW_DST'
200 actions.append(copy.deepcopy(action))
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700201 elif arg1 == "actionSetIpToS":
202 ipToS = {}
203 ipToS['ipToS'] = int(arg2, 0)
204 action['actionSetIpToS'] = ipToS
205 # action['actionType'] = 'ACTION_SET_NW_TOS'
206 actions.append(copy.deepcopy(action))
207 elif arg1 == "actionSetTcpUdpSrcPort":
208 tcpUdpSrcPort = {}
209 tcpUdpSrcPort['port'] = int(arg2, 0)
210 action['actionSetTcpUdpSrcPort'] = tcpUdpSrcPort
211 # action['actionType'] = 'ACTION_SET_TP_SRC'
212 actions.append(copy.deepcopy(action))
213 elif arg1 == "actionSetTcpUdpDstPort":
214 tcpUdpDstPort = {}
215 tcpUdpDstPort['port'] = int(arg2, 0)
216 action['actionSetTcpUdpDstPort'] = tcpUdpDstPort
217 # action['actionType'] = 'ACTION_SET_TP_DST'
218 actions.append(copy.deepcopy(action))
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000219 elif arg1 == "actionEnqueue":
220 # TODO: Implement ACTION_ENQUEUE
221 actionEnqueue = {}
222 # actionEnqueue['queueId'] = int(arg2, 0)
223 # enqueuePort = {}
224 # enqueuePort['value'] = int(arg3, 0)
225 # actionEnqueue['port'] = enqueuePort
226 # action['actionEnqueue'] = actionEnqueue
227 # # action['actionType'] = 'ACTION_ENQUEUE'
228 # actions.append(copy.deepcopy(action))
229 #
230 else:
231 log_error("ERROR: Unknown argument '%s'" % (arg1))
232 log_error(usage_msg)
233 exit(1)
234
235 return {
236 'my_flow_id' : my_flow_id,
237 'my_installer_id' : my_installer_id,
238 'my_src_dpid' : my_src_dpid,
239 'my_src_port' : my_src_port,
240 'my_dst_dpid' : my_dst_dpid,
241 'my_dst_port' : my_dst_port,
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700242 'flowPathFlags' : flowPathFlags,
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000243 'match' : match,
244 'matchInPortEnabled' : matchInPortEnabled,
245 'actions' : actions,
246 'actionOutputEnabled' : actionOutputEnabled
247 }
248
249def compute_flow_path(parsed_args, data_path):
250
251 my_flow_id = parsed_args['my_flow_id']
252 my_installer_id = parsed_args['my_installer_id']
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700253 myFlowPathFlags = parsed_args['flowPathFlags']
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000254 match = parsed_args['match']
255 matchInPortEnabled = parsed_args['matchInPortEnabled']
256 actions = parsed_args['actions']
257 actionOutputEnabled = parsed_args['actionOutputEnabled']
258 my_data_path = copy.deepcopy(data_path)
259
260 flow_id = {}
261 flow_id['value'] = my_flow_id
262 installer_id = {}
263 installer_id['value'] = my_installer_id
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700264 flowPathFlags = {}
265 flowPathFlags['flags'] = myFlowPathFlags
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000266
267 flow_path = {}
268 flow_path['flowId'] = flow_id
269 flow_path['installerId'] = installer_id
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700270 flow_path['flowPathFlags'] = flowPathFlags
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000271
272 if (len(match) > 0):
273 flow_path['flowEntryMatch'] = copy.deepcopy(match)
274
275 #
276 # Add the match conditions to each flow entry
277 #
278 if (len(match) > 0) or matchInPortEnabled:
279 idx = 0
280 while idx < len(my_data_path['flowEntries']):
281 if matchInPortEnabled:
282 inPort = my_data_path['flowEntries'][idx]['inPort']
283 match['inPort'] = copy.deepcopy(inPort)
284 # match['matchInPort'] = True
285 my_data_path['flowEntries'][idx]['flowEntryMatch'] = copy.deepcopy(match)
286 idx = idx + 1
287
288 #
289 # Set the actions for each flow entry
290 # NOTE: The actions from the command line are aplied
291 # ONLY to the first flow entry.
292 #
293 # If ACTION_OUTPUT action is enabled, then apply it
294 # to each flow entry.
295 #
296 if (len(actions) > 0) or actionOutputEnabled:
297 idx = 0
298 while idx < len(my_data_path['flowEntries']):
299 if idx > 0:
300 actions = [] # Reset the actions for all but first entry
301 action = {}
302 outPort = my_data_path['flowEntries'][idx]['outPort']
303 actionOutput = {}
304 actionOutput['port'] = copy.deepcopy(outPort)
305 # actionOutput['maxLen'] = 0 # TODO: not used for now
306 action['actionOutput'] = copy.deepcopy(actionOutput)
307 # action['actionType'] = 'ACTION_OUTPUT'
308 actions.append(copy.deepcopy(action))
309
310 my_data_path['flowEntries'][idx]['flowEntryActions'] = copy.deepcopy(actions)
311 idx = idx + 1
312
313
314 flow_path['dataPath'] = my_data_path
315 debug("Flow Path: %s" % flow_path)
316 return flow_path
317
318def measurement_store_paths(parsed_args):
319 idx = 0
320 while idx < len(parsed_args):
321 data_path = {}
322 src_dpid = {}
323 src_port = {}
324 dst_dpid = {}
325 dst_port = {}
326 src_switch_port = {}
327 dst_switch_port = {}
328 flow_entries = []
329
330 src_dpid['value'] = parsed_args[idx]['my_src_dpid']
331 src_port['value'] = parsed_args[idx]['my_src_port']
332 dst_dpid['value'] = parsed_args[idx]['my_dst_dpid']
333 dst_port['value'] = parsed_args[idx]['my_dst_port']
334 src_switch_port['dpid'] = src_dpid
335 src_switch_port['port'] = src_port
336 dst_switch_port['dpid'] = dst_dpid
337 dst_switch_port['port'] = dst_port
338
339 data_path['srcPort'] = copy.deepcopy(src_switch_port)
340 data_path['dstPort'] = copy.deepcopy(dst_switch_port)
341 data_path['flowEntries'] = copy.deepcopy(flow_entries)
342
343 #
344 # XXX: Explicitly disable the InPort matching, and
345 # the Output action, because they get in the way
346 # during the compute_flow_path() processing.
347 #
348 parsed_args[idx]['matchInPortEnabled'] = False
349 parsed_args[idx]['actionOutputEnabled'] = False
350
351 flow_path = compute_flow_path(parsed_args[idx], data_path)
352 measurement_store_path_flow(flow_path)
353
354 idx = idx + 1
355
356
357if __name__ == "__main__":
358 usage_msg = "Store Flow Paths into ONOS for measurement purpose.\n"
359 usage_msg = usage_msg + "\n"
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700360 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 +0000361 usage_msg = usage_msg + "\n"
362 usage_msg = usage_msg + " Flags:\n"
363 usage_msg = usage_msg + " -f <filename> Read the flow(s) to install from a file\n"
364 usage_msg = usage_msg + " File format: one line per flow starting with <flow-id>\n"
365 usage_msg = usage_msg + "\n"
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700366 usage_msg = usage_msg + " Flow Path Flags:\n"
367 usage_msg = usage_msg + " flowPathFlags <Flags> (flag names separated by ',')\n"
368 usage_msg = usage_msg + "\n"
369 usage_msg = usage_msg + " Known flags:\n"
370 usage_msg = usage_msg + " DISCARD_FIRST_HOP_ENTRY : Discard the first-hop flow entry\n"
371 usage_msg = usage_msg + " KEEP_ONLY_FIRST_HOP_ENTRY : Keep only the first-hop flow entry\n"
372 usage_msg = usage_msg + "\n"
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000373 usage_msg = usage_msg + " Match Conditions:\n"
374 usage_msg = usage_msg + " matchInPort <True|False> (default to True)\n"
375 usage_msg = usage_msg + " matchSrcMac <source MAC address>\n"
376 usage_msg = usage_msg + " matchDstMac <destination MAC address>\n"
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000377 usage_msg = usage_msg + " matchEthernetFrameType <Ethernet frame type>\n"
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000378 usage_msg = usage_msg + " matchVlanId <VLAN ID>\n"
379 usage_msg = usage_msg + " matchVlanPriority <VLAN priority>\n"
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700380 usage_msg = usage_msg + " matchSrcIPv4Net <source IPv4 network address>\n"
381 usage_msg = usage_msg + " matchDstIPv4Net <destination IPv4 network address>\n"
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000382 usage_msg = usage_msg + " matchIpProto <IP protocol>\n"
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700383 usage_msg = usage_msg + " matchIpToS <IP ToS (DSCP field, 6 bits)>\n"
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000384 usage_msg = usage_msg + " matchSrcTcpUdpPort <source TCP/UDP port>\n"
385 usage_msg = usage_msg + " matchDstTcpUdpPort <destination TCP/UDP port>\n"
386 usage_msg = usage_msg + "\n"
387 usage_msg = usage_msg + " Actions:\n"
388 usage_msg = usage_msg + " actionOutput <True|False> (default to True)\n"
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700389 usage_msg = usage_msg + " actionSetVlanId <VLAN ID>\n"
390 usage_msg = usage_msg + " actionSetVlanPriority <VLAN priority>\n"
391 usage_msg = usage_msg + " actionStripVlan <True|False>\n"
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000392 usage_msg = usage_msg + " actionSetEthernetSrcAddr <source MAC address>\n"
393 usage_msg = usage_msg + " actionSetEthernetDstAddr <destination MAC address>\n"
394 usage_msg = usage_msg + " actionSetIPv4SrcAddr <source IPv4 address>\n"
395 usage_msg = usage_msg + " actionSetIPv4DstAddr <destination IPv4 address>\n"
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000396 usage_msg = usage_msg + " actionSetIpToS <IP ToS (DSCP field, 6 bits)>\n"
397 usage_msg = usage_msg + " actionSetTcpUdpSrcPort <source TCP/UDP port>\n"
398 usage_msg = usage_msg + " actionSetTcpUdpDstPort <destination TCP/UDP port>\n"
Pavlin Radoslavovcdda1f72013-05-07 23:19:38 +0000399 usage_msg = usage_msg + " actionEnqueue <dummy argument>\n"
400
401 # app.debug = False;
402
403 # Usage info
404 if len(sys.argv) > 1 and (sys.argv[1] == "-h" or sys.argv[1] == "--help"):
405 print(usage_msg)
406 exit(0)
407
408 #
409 # Check the flags
410 #
411 start_argv_index = 1
412 idx = 1
413 while idx < len(sys.argv):
414 arg1 = sys.argv[idx]
415 idx = idx + 1
416 if arg1 == "-f":
417 if idx >= len(sys.argv):
418 error_arg = "ERROR: Missing or invalid '" + arg1 + "' argument"
419 log_error(error_arg)
420 log_error(usage_msg)
421 exit(1)
422 ReadFromFile = sys.argv[idx]
423 idx = idx + 1
424 start_argv_index = idx
425 else:
426 break;
427
428 #
429 # Read the arguments from a file or from the remaining command line options
430 #
431 my_lines = []
432 if len(ReadFromFile) > 0:
433 f = open(ReadFromFile, "rt")
434 my_line = f.readline()
435 while my_line:
436 if len(my_line.rstrip()) > 0 and my_line[0] != "#":
437 my_token_line = my_line.rstrip().split()
438 my_lines.append(my_token_line)
439 my_line = f.readline()
440 else:
441 my_lines.append(copy.deepcopy(sys.argv[start_argv_index:]))
442
443 #
444 # Initialization
445 #
446 last_data_paths = []
447 parsed_args = []
448 idx = 0
449 while idx < len(my_lines):
450 last_data_path = []
451 last_data_paths.append(copy.deepcopy(last_data_path))
452 #
453 # Parse the flow arguments
454 #
455 my_args = my_lines[idx]
456 parsed_args.append(copy.deepcopy(extract_flow_args(my_args)))
457
458 idx = idx + 1
459
460 #
461 measurement_store_paths(parsed_args)