blob: 7adaf986bc6c86c8a5ee4122b25997173bb8c0e8 [file] [log] [blame]
Pavlin Radoslavovf4ad9892013-03-04 14:15:19 -08001#! /usr/bin/env python
2# -*- Mode: python; py-indent-offset: 4; tab-width: 8; indent-tabs-mode: t; -*-
3
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -07004import copy
Pavlin Radoslavovf4ad9892013-03-04 14:15:19 -08005import 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#
17# curl http://127.0.0.1:8080/wm/topology/route/00:00:00:00:00:00:0a:01/1/00:00:00:00:00:00:0a:04/1/json
18#
19
20## Global Var ##
21ControllerIP="127.0.0.1"
22ControllerPort=8080
23
24DEBUG=0
25pp = pprint.PrettyPrinter(indent=4)
26
27app = Flask(__name__)
28
29## Worker Functions ##
30def log_error(txt):
31 print '%s' % (txt)
32
33def debug(txt):
34 if DEBUG:
35 print '%s' % (txt)
36
37# @app.route("/wm/topology/route/<srcdpid>/<srcport>/<destdpid>/<destport>/json")
38#
39# Sample output:
40# {'dstPort': {'port': {'value': 0}, 'dpid': {'value': '00:00:00:00:00:00:00:02'}}, 'srcPort': {'port': {'value': 0}, 'dpid': {'value': '00:00:00:00:00:00:00:01'}}, 'flowEntries': [{'outPort': {'value': 1}, 'flowEntryErrorState': None, 'flowEntryMatch': None, 'flowEntryActions': None, 'inPort': {'value': 0}, 'flowEntryId': None, 'flowEntryUserState': 'FE_USER_UNKNOWN', 'dpid': {'value': '00:00:00:00:00:00:00:01'}, 'flowEntrySwitchState': 'FE_SWITCH_UNKNOWN'}, {'outPort': {'value': 0}, 'flowEntryErrorState': None, 'flowEntryMatch': None, 'flowEntryActions': None, 'inPort': {'value': 9}, 'flowEntryId': None, 'flowEntryUserState': 'FE_USER_UNKNOWN', 'dpid': {'value': '00:00:00:00:00:00:00:02'}, 'flowEntrySwitchState': 'FE_SWITCH_UNKNOWN'}]}
41#
42def shortest_path(v1, p1, v2, p2):
43 try:
44 command = "curl -s http://%s:%s/wm/topology/route/%s/%s/%s/%s/json" % (ControllerIP, ControllerPort, v1, p1, v2, p2)
45 debug("shortest_path %s" % command)
46
47 result = os.popen(command).read()
48 debug("result %s" % result)
49 if len(result) == 0:
50 log_error("No Path found")
51 exit(1);
52
53 parsedResult = json.loads(result)
54 debug("parsed %s" % parsedResult)
55
56 except:
57 log_error("Controller IF has issue")
58 exit(1)
59
60 srcSwitch = parsedResult['srcPort']['dpid']['value'];
61 srcPort = parsedResult['srcPort']['port']['value'];
62 dstSwitch = parsedResult['dstPort']['dpid']['value'];
63 dstPort = parsedResult['dstPort']['port']['value'];
64
65 print "DataPath: (src = %s/%s dst = %s/%s)" % (srcSwitch, srcPort, dstSwitch, dstPort);
66
67 for f in parsedResult['flowEntries']:
68 inPort = f['inPort']['value'];
69 outPort = f['outPort']['value'];
70 dpid = f['dpid']['value']
71 print "FlowEntry: (%s, %s, %s)" % (inPort, dpid, outPort)
72
73 return parsedResult
74
75def add_flow_path(flow_path):
76 try:
77 command = "curl -s -H 'Content-Type: application/json' -d '%s' http://%s:%s/wm/flow/add/json" % (flow_path, ControllerIP, ControllerPort)
78 debug("add_flow_path %s" % command)
79 result = os.popen(command).read()
80 debug("result %s" % result)
81 # parsedResult = json.loads(result)
82 # debug("parsed %s" % parsedResult)
83 except:
84 log_error("Controller IF has issue")
85 exit(1)
86
87if __name__ == "__main__":
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -070088 usage_msg = "Usage: %s <flow-id> <installer-id> <src-dpid> <src-port> <dest-dpid> <dest-port> [Match Conditions] [Actions]\n" % (sys.argv[0])
89 usage_msg = usage_msg + " Match Conditions:\n"
90 usage_msg = usage_msg + " matchInPort <True|False> (default to True)\n"
91 usage_msg = usage_msg + " matchSrcMac <source MAC address>\n"
92 usage_msg = usage_msg + " matchDstMac <destination MAC address>\n"
93 usage_msg = usage_msg + " matchSrcIPv4Net <source IPv4 network address>\n"
94 usage_msg = usage_msg + " matchDstIPv4Net <destination IPv4 network address>\n"
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070095 usage_msg = usage_msg + " matchEthernetFrameType <Ethernet frame type>\n"
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -070096
97 usage_msg = usage_msg + " Match Conditions (not implemented yet):\n"
98 usage_msg = usage_msg + " matchVlanId <VLAN ID>\n"
99 usage_msg = usage_msg + " matchVlanPriority <VLAN priority>\n"
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -0700100 usage_msg = usage_msg + " matchIpToS <IP ToS (DSCP field, 6 bits)>\n"
101 usage_msg = usage_msg + " matchIpProto <IP protocol>\n"
102 usage_msg = usage_msg + " matchSrcTcpUdpPort <source TCP/UDP port>\n"
103 usage_msg = usage_msg + " matchDstTcpUdpPort <destination TCP/UDP port>\n"
104 usage_msg = usage_msg + " Actions:\n"
105 usage_msg = usage_msg + " actionOutput <True|False> (default to True)\n"
106 usage_msg = usage_msg + " actionSetEthernetSrcAddr <source MAC address>\n"
107 usage_msg = usage_msg + " actionSetEthernetDstAddr <destination MAC address>\n"
108 usage_msg = usage_msg + " actionSetIPv4SrcAddr <source IPv4 address>\n"
109 usage_msg = usage_msg + " actionSetIPv4DstAddr <destination IPv4 address>\n"
110 usage_msg = usage_msg + " Actions (not implemented yet):\n"
111 usage_msg = usage_msg + " actionSetVlanId <VLAN ID>\n"
112 usage_msg = usage_msg + " actionSetVlanPriority <VLAN priority>\n"
113 usage_msg = usage_msg + " actionSetIpToS <IP ToS (DSCP field, 6 bits)>\n"
114 usage_msg = usage_msg + " actionSetTcpUdpSrcPort <source TCP/UDP port>\n"
115 usage_msg = usage_msg + " actionSetTcpUdpDstPort <destination TCP/UDP port>\n"
116 usage_msg = usage_msg + " actionStripVlan <True|False>\n"
117 usage_msg = usage_msg + " actionEnqueue <dummy argument>\n"
Pavlin Radoslavovf4ad9892013-03-04 14:15:19 -0800118
119 # app.debug = False;
120
121 # Usage info
122 if len(sys.argv) > 1 and (sys.argv[1] == "-h" or sys.argv[1] == "--help"):
123 print(usage_msg)
124 exit(0)
125
126 # Check arguments
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800127 if len(sys.argv) < 7:
Pavlin Radoslavovf4ad9892013-03-04 14:15:19 -0800128 log_error(usage_msg)
129 exit(1)
130
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -0700131 # Extract the mandatory arguments
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800132 my_flow_id = sys.argv[1]
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -0700133 my_installer_id = sys.argv[2]
134 my_src_dpid = sys.argv[3]
135 my_src_port = sys.argv[4]
136 my_dst_dpid = sys.argv[5]
137 my_dst_port = sys.argv[6]
138
139 # Compute the shortest path
140 data_path = shortest_path(my_src_dpid, my_src_port, my_dst_dpid, my_dst_port)
Pavlin Radoslavovf4ad9892013-03-04 14:15:19 -0800141
142 debug("Data Path: %s" % data_path)
143
144 flow_id = {}
145 flow_id['value'] = my_flow_id
146 installer_id = {}
147 installer_id['value'] = my_installer_id
148
149 flow_path = {}
150 flow_path['flowId'] = flow_id
151 flow_path['installerId'] = installer_id
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -0700152
153 #
154 # Extract the "match" and "action" arguments
155 #
156 idx = 7
157 match = {}
158 matchInPortEnabled = True # NOTE: Enabled by default
159 actions = []
160 actionOutputEnabled = True # NOTE: Enabled by default
161 while idx < len(sys.argv):
162 action = {}
163 arg1 = sys.argv[idx]
164 idx = idx + 1
165 # Extract the second argument
166 if idx >= len(sys.argv):
167 error_arg = "ERROR: Missing or invalid '" + arg1 + "' argument"
168 log_error(error_arg)
169 log_error(usage_msg)
170 exit(1)
171 arg2 = sys.argv[idx]
172 idx = idx + 1
173
174 if arg1 == "matchInPort":
175 # Just mark whether inPort matching is enabled
176 matchInPortEnabled = arg2 in ['True', 'true']
177 # inPort = {}
Pavlin Radoslavov14748912013-03-12 15:44:56 -0700178 # inPort['value'] = int(arg2, 0)
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -0700179 # match['inPort'] = inPort
180 ## match['matchInPort'] = True
181 elif arg1 == "matchSrcMac":
182 srcMac = {}
183 srcMac['value'] = arg2
184 match['srcMac'] = srcMac
185 # match['matchSrcMac'] = True
186 elif arg1 == "matchDstMac":
187 dstMac = {}
188 dstMac['value'] = arg2
189 match['dstMac'] = dstMac
190 # match['matchDstMac'] = True
191 elif arg1 == "matchVlanId":
Pavlin Radoslavov14748912013-03-12 15:44:56 -0700192 match['vlanId'] = int(arg2, 0)
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -0700193 # match['matchVlanId'] = True
194 elif arg1 == "matchVlanPriority":
Pavlin Radoslavov14748912013-03-12 15:44:56 -0700195 match['vlanPriority'] = int(arg2, 0)
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -0700196 # match['matchVlanPriority'] = True
197 elif arg1 == "matchEthernetFrameType":
Pavlin Radoslavov14748912013-03-12 15:44:56 -0700198 match['ethernetFrameType'] = int(arg2, 0)
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -0700199 # match['matchEthernetFrameType'] = True
200 elif arg1 == "matchIpToS":
Pavlin Radoslavov14748912013-03-12 15:44:56 -0700201 match['ipToS'] = int(arg2, 0)
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -0700202 # match['matchIpToS'] = True
203 elif arg1 == "matchIpProto":
Pavlin Radoslavov14748912013-03-12 15:44:56 -0700204 match['ipProto'] = int(arg2, 0)
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -0700205 # match['matchIpProto'] = True
206 elif arg1 == "matchSrcIPv4Net":
207 srcIPv4Net = {}
208 srcIPv4Net['value'] = arg2
209 match['srcIPv4Net'] = srcIPv4Net
210 # match['matchSrcIPv4Net'] = True
211 elif arg1 == "matchDstIPv4Net":
212 dstIPv4Net = {}
213 dstIPv4Net['value'] = arg2
214 match['dstIPv4Net'] = dstIPv4Net
215 # match['matchDstIPv4Net'] = True
216 elif arg1 == "matchSrcTcpUdpPort":
Pavlin Radoslavov14748912013-03-12 15:44:56 -0700217 match['srcTcpUdpPort'] = int(arg2, 0)
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -0700218 # match['matchSrcTcpUdpPort'] = True
219 elif arg1 == "matchDstTcpUdpPort":
Pavlin Radoslavov14748912013-03-12 15:44:56 -0700220 match['dstTcpUdpPort'] = int(arg2, 0)
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -0700221 # match['matchDstTcpUdpPort'] = True
222 elif arg1 == "actionOutput":
223 # Just mark whether ACTION_OUTPUT action is enabled
224 actionOutputEnabled = arg2 in ['True', 'true']
225 #
226 # TODO: Complete the implementation for ACTION_OUTPUT
227 # actionOutput = {}
228 # outPort = {}
Pavlin Radoslavov14748912013-03-12 15:44:56 -0700229 # outPort['value'] = int(arg2, 0)
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -0700230 # actionOutput['port'] = outPort
Pavlin Radoslavov14748912013-03-12 15:44:56 -0700231 # actionOutput['maxLen'] = int(arg3, 0)
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -0700232 # action['actionOutput'] = actionOutput
233 # # action['actionType'] = 'ACTION_OUTPUT'
234 # actions.append(action)
235 #
236 elif arg1 == "actionSetVlanId":
237 vlanId = {}
Pavlin Radoslavov14748912013-03-12 15:44:56 -0700238 vlanId['vlanId'] = int(arg2, 0)
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -0700239 action['actionSetVlanId'] = vlanId
240 # action['actionType'] = 'ACTION_SET_VLAN_VID'
241 actions.append(copy.deepcopy(action))
242 elif arg1 == "actionSetVlanPriority":
243 vlanPriority = {}
Pavlin Radoslavov14748912013-03-12 15:44:56 -0700244 vlanPriority['vlanPriority'] = int(arg2, 0)
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -0700245 action['actionSetVlanPriority'] = vlanPriority
246 # action['actionType'] = 'ACTION_SET_VLAN_PCP'
247 actions.append(copy.deepcopy(action))
248 elif arg1 == "actionSetIpToS":
249 ipToS = {}
Pavlin Radoslavov14748912013-03-12 15:44:56 -0700250 ipToS['ipToS'] = int(arg2, 0)
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -0700251 action['actionSetIpToS'] = ipToS
252 # action['actionType'] = 'ACTION_SET_NW_TOS'
253 actions.append(copy.deepcopy(action))
254 elif arg1 == "actionSetTcpUdpSrcPort":
255 tcpUdpSrcPort = {}
Pavlin Radoslavov14748912013-03-12 15:44:56 -0700256 tcpUdpSrcPort['port'] = int(arg2, 0)
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -0700257 action['actionSetTcpUdpSrcPort'] = tcpUdpSrcPort
258 # action['actionType'] = 'ACTION_SET_TP_SRC'
259 actions.append(copy.deepcopy(action))
260 elif arg1 == "actionSetTcpUdpDstPort":
261 tcpUdpDstPort = {}
Pavlin Radoslavov14748912013-03-12 15:44:56 -0700262 tcpUdpDstPort['port'] = int(arg2, 0)
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -0700263 action['actionSetTcpUdpDstPort'] = tcpUdpDstPort
264 # action['actionType'] = 'ACTION_SET_TP_DST'
265 actions.append(copy.deepcopy(action))
266 elif arg1 == "actionStripVlan":
267 stripVlan = {}
268 stripVlan['stripVlan'] = arg2 in ['True', 'true']
269 action['actionStripVlan'] = stripVlan
270 # action['actionType'] = 'ACTION_STRIP_VLAN'
271 actions.append(copy.deepcopy(action))
272 elif arg1 == "actionSetEthernetSrcAddr":
273 ethernetSrcAddr = {}
274 ethernetSrcAddr['value'] = arg2
275 setEthernetSrcAddr = {}
276 setEthernetSrcAddr['addr'] = ethernetSrcAddr
277 action['actionSetEthernetSrcAddr'] = setEthernetSrcAddr
278 # action['actionType'] = 'ACTION_SET_DL_SRC'
279 actions.append(copy.deepcopy(action))
280 elif arg1 == "actionSetEthernetDstAddr":
281 ethernetDstAddr = {}
282 ethernetDstAddr['value'] = arg2
283 setEthernetDstAddr = {}
284 setEthernetDstAddr['addr'] = ethernetDstAddr
285 action['actionSetEthernetDstAddr'] = setEthernetDstAddr
286 # action['actionType'] = 'ACTION_SET_DL_DST'
287 actions.append(copy.deepcopy(action))
288 elif arg1 == "actionSetIPv4SrcAddr":
289 IPv4SrcAddr = {}
290 IPv4SrcAddr['value'] = arg2
291 setIPv4SrcAddr = {}
292 setIPv4SrcAddr['addr'] = IPv4SrcAddr
293 action['actionSetIPv4SrcAddr'] = setIPv4SrcAddr
294 # action['actionType'] = 'ACTION_SET_NW_SRC'
295 actions.append(copy.deepcopy(action))
296 elif arg1 == "actionSetIPv4DstAddr":
297 IPv4DstAddr = {}
298 IPv4DstAddr['value'] = arg2
299 setIPv4DstAddr = {}
300 setIPv4DstAddr['addr'] = IPv4DstAddr
301 action['actionSetIPv4DstAddr'] = setIPv4DstAddr
302 # action['actionType'] = 'ACTION_SET_NW_DST'
303 actions.append(copy.deepcopy(action))
304 elif arg1 == "actionEnqueue":
305 # TODO: Implement ACTION_ENQUEUE
306 actionEnqueue = {}
Pavlin Radoslavov14748912013-03-12 15:44:56 -0700307 # actionEnqueue['queueId'] = int(arg2, 0)
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -0700308 # enqueuePort = {}
Pavlin Radoslavov14748912013-03-12 15:44:56 -0700309 # enqueuePort['value'] = int(arg3, 0)
Pavlin Radoslavovf13923a2013-03-11 19:42:17 -0700310 # actionEnqueue['port'] = enqueuePort
311 # action['actionEnqueue'] = actionEnqueue
312 # # action['actionType'] = 'ACTION_ENQUEUE'
313 # actions.append(copy.deepcopy(action))
314 #
315 else:
316 log_error("ERROR: Unknown argument '%s'" % (arg1))
317 log_error(usage_msg)
318 exit(1)
319
320
321 #
322 # Add the match conditions to each flow entry
323 #
324 if (len(match) > 0) or matchInPortEnabled:
325 idx = 0
326 while idx < len(data_path['flowEntries']):
327 if matchInPortEnabled:
328 inPort = data_path['flowEntries'][idx]['inPort']
329 match['inPort'] = copy.deepcopy(inPort)
330 # match['matchInPort'] = True
331 data_path['flowEntries'][idx]['flowEntryMatch'] = copy.deepcopy(match)
332 idx = idx + 1
333
334 #
335 # Set the actions for each flow entry
336 # NOTE: The actions from the command line are aplied
337 # ONLY to the first flow entry.
338 #
339 # If ACTION_OUTPUT action is enabled, then apply it
340 # to each flow entry.
341 #
342 if (len(actions) > 0) or actionOutputEnabled:
343 idx = 0
344 while idx < len(data_path['flowEntries']):
345 if idx > 0:
346 actions = [] # Reset the actions for all but first entry
347 action = {}
348 outPort = data_path['flowEntries'][idx]['outPort']
349 actionOutput = {}
350 actionOutput['port'] = copy.deepcopy(outPort)
351 # actionOutput['maxLen'] = 0 # TODO: not used for now
352 action['actionOutput'] = copy.deepcopy(actionOutput)
353 # action['actionType'] = 'ACTION_OUTPUT'
354 actions.append(copy.deepcopy(action))
355
356 data_path['flowEntries'][idx]['flowEntryActions'] = copy.deepcopy(actions)
357 idx = idx + 1
358
359
Pavlin Radoslavovf4ad9892013-03-04 14:15:19 -0800360 flow_path['dataPath'] = data_path
361
362 flow_path_json = json.dumps(flow_path)
363 debug("Flow Path: %s" % flow_path_json)
364
365 add_flow_path(flow_path_json)