2 from flow_config_blaster import FlowConfigBlaster
10 __author__ = "Jan Medved"
11 __copyright__ = "Copyright(c) 2014, Cisco Systems, Inc."
12 __license__ = "New-style BSD"
13 __email__ = "jmedved@cisco.com"
16 class FlowConfigBlasterFLE(FlowConfigBlaster):
18 FlowConfigBlaster, Floodlight Edition; Uses the Floodlight Static Flow Entry Pusher REST API to inject flows.
22 "switch": "00:00:00:00:00:00:00:01",
27 "ipv4_dst": "10.0.0.1/32",
29 "actions": "output=flood",
32 def __init__(self, host, port, ncycles, nthreads, nnodes, nflows, startflow):
33 FlowConfigBlaster.__init__(
34 self, host, port, ncycles, nthreads, 1, nnodes, nflows, startflow, False
37 def create_floodlight_url(self, host):
38 return "http://" + host + ":" + self.port + "/wm/staticflowpusher/json"
40 def get_num_nodes(self, session):
42 Determines the number of nodes in the network. Overrides the get_num_nodes method in FlowConfigBlaster.
51 + "/wm/core/controller/switches/json"
55 r = session.get(url, headers=self.getheaders, stream=False)
57 if r.status_code == 200:
59 nodes = len(json.loads(r.content))
65 def post_flows(self, session, node, flow_list, flow_count):
67 Performs a RESTCONF post of flows passed in the 'flow_list' parameters
68 :param session: 'requests' session on which to perform the POST
69 :param node: The ID of the openflow node to which to post the flows
70 :param flow_list: List of flows (in dictionary form) to POST
71 :param flow_count: Number of flows in flow_list (must be 1)
72 :return: status code from the POST operation
74 flow = copy.deepcopy(self.flow)
75 flow["switch"] = "00:00:00:00:00:00:00:%s" % "{0:02x}".format(node)
76 flow["name"] = flow_list[0]["flow-name"]
77 flow["table"] = flow_list[0]["table_id"]
78 flow["cookie"] = flow_list[0]["cookie"]
79 # flow['cookie_mask'] = flow_list[0]['cookie_mask']
80 flow["idle_timeout"] = flow_list[0]["idle-timeout"]
81 flow["hard_timeout"] = flow_list[0]["hard-timeout"]
82 flow["ipv4_dst"] = flow_list[0]["match"]["ipv4-destination"]
84 flow_data = json.dumps(flow)
86 hosts = self.host.split(",")
87 host = hosts[flow_count % len(hosts)]
88 flow_url = self.create_floodlight_url(host)
91 flow_url, data=flow_data, headers=self.putheaders, stream=False
95 def delete_flow(self, session, node, flow_id, flow_count):
97 Deletes a single flow from the ODL config data store using RESTCONF
98 :param session: 'requests' session on which to perform the POST
99 :param node: Id of the openflow node from which to delete the flow
100 :param flow_id: ID of the to-be-deleted flow
101 :param flow_count: Flow counter for round-robin of delete operations
102 :return: status code from the DELETE operation
105 hosts = self.host.split(",")
106 host = hosts[flow_count % len(hosts)]
107 flow_url = self.create_floodlight_url(host)
108 flow_data = json.dumps({"name": self.create_flow_name(flow_id)})
110 r = session.delete(flow_url, data=flow_data, headers=self.getheaders)
113 def clear_all_flows(self):
119 + "/wm/staticflowpusher/clear/all/json"
121 r = requests.get(clear_url)
122 if r.status_code == 200:
123 print("All flows cleared before the test")
125 print("Failed to clear flows from the controller, your results may vary")
128 if __name__ == "__main__":
130 parser = argparse.ArgumentParser(
131 description="Flow programming performance test for Floodlight: First adds and "
132 "then deletes flows using the Static Flow Entry Pusher REST API."
138 help="Host where the controller is running (default is 127.0.0.1)",
143 help="Port on which the controller's RESTCONF is listening (default is 8080)",
149 help="Number of flow add/delete cycles; default 1. Both Flow Adds and Flow Deletes are "
150 "performed in cycles. <THREADS> worker threads are started in each cycle and the cycle "
151 "ends when all threads finish. Another cycle is started when the previous cycle finished.",
157 help="Number of request worker threads to start in each cycle; default=1. "
158 "Each thread will add/delete <FLOWS> flows.",
164 help="Number of flows that will be added/deleted by each worker thread in each cycle; "
171 help="Number of nodes if mininet is not connected; default=16. If mininet is connected, "
172 "flows will be evenly distributed (programmed) into connected nodes.",
178 help="Time (in seconds) to wait between the add and delete cycles; default=0",
183 action="store_false",
184 help="Do not perform the delete cycle.",
187 "--startflow", type=int, default=0, help="The starting Flow ID; default=0"
190 in_args = parser.parse_args()
192 fct = FlowConfigBlasterFLE(
202 fct.clear_all_flows()
204 # Run through <cycles>, where <threads> are started in each cycle and <flows> are added from each thread
207 print("\n*** Total flows added: %s" % fct.get_ok_flows())
208 print(" HTTP[OK] results: %d\n" % fct.get_ok_rqsts())
210 if in_args.delay > 0:
212 "*** Waiting for %d seconds before the delete cycle ***\n" % in_args.delay
214 time.sleep(in_args.delay)
216 # Run through <cycles>, where <threads> are started in each cycle and <flows> previously added in an add cycle are
217 # deleted in each thread
220 print("\n*** Total flows deleted: %s" % fct.get_ok_flows())
221 print(" HTTP[OK] results: %d\n" % fct.get_ok_rqsts())