blob: 5a286fe247a238c1acd4d6bc6df00187d97d9574 [file] [log] [blame]
Dan Talaycodba244e2010-02-15 14:08:53 -08001"""
Dan Talayco79f36082010-03-11 16:53:53 -08002Basic protocol and dataplane test cases
Dan Talaycodba244e2010-02-15 14:08:53 -08003
Dan Talayco48370102010-03-03 15:17:33 -08004It is recommended that these definitions be kept in their own
5namespace as different groups of tests will likely define
6similar identifiers.
7
Dan Talaycodba244e2010-02-15 14:08:53 -08008Current Assumptions:
9
Dan Talayco41eae8b2010-03-10 13:57:06 -080010 The function test_set_init is called with a complete configuration
11dictionary prior to the invocation of any tests from this file.
12
Dan Talaycodba244e2010-02-15 14:08:53 -080013 The switch is actively attempting to contact the controller at the address
14indicated oin oft_config
15
16"""
17
Dan Talaycodba244e2010-02-15 14:08:53 -080018import time
Dan Talayco710438c2010-02-18 15:16:07 -080019import signal
Dan Talaycodba244e2010-02-15 14:08:53 -080020import sys
Dan Talayco48370102010-03-03 15:17:33 -080021import logging
Dan Talaycodba244e2010-02-15 14:08:53 -080022
Dan Talayco2c0dba32010-03-06 22:47:06 -080023import unittest
Ken Chiang1bf01602012-04-04 10:48:23 -070024import random
Dan Talayco2c0dba32010-03-06 22:47:06 -080025
26import oftest.controller as controller
27import oftest.cstruct as ofp
28import oftest.message as message
29import oftest.dataplane as dataplane
30import oftest.action as action
31
Dan Talayco6ce963a2010-03-07 21:58:13 -080032from testutils import *
33
34#@var basic_port_map Local copy of the configuration map from OF port
35# numbers to OS interfaces
Dan Talayco48370102010-03-03 15:17:33 -080036basic_port_map = None
Dan Talayco6ce963a2010-03-07 21:58:13 -080037#@var basic_logger Local logger object
Dan Talayco48370102010-03-03 15:17:33 -080038basic_logger = None
Dan Talayco6ce963a2010-03-07 21:58:13 -080039#@var basic_config Local copy of global configuration data
Dan Talayco48370102010-03-03 15:17:33 -080040basic_config = None
41
Dan Talaycoc24aaae2010-07-08 14:05:24 -070042test_prio = {}
43
Dan Talayco48370102010-03-03 15:17:33 -080044def test_set_init(config):
45 """
46 Set up function for basic test classes
47
48 @param config The configuration dictionary; see oft
Dan Talayco48370102010-03-03 15:17:33 -080049 """
50
51 global basic_port_map
52 global basic_logger
53 global basic_config
54
55 basic_logger = logging.getLogger("basic")
56 basic_logger.info("Initializing test set")
57 basic_port_map = config["port_map"]
58 basic_config = config
Dan Talayco48370102010-03-03 15:17:33 -080059
Dan Talayco6ce963a2010-03-07 21:58:13 -080060class SimpleProtocol(unittest.TestCase):
Dan Talaycodba244e2010-02-15 14:08:53 -080061 """
62 Root class for setting up the controller
63 """
64
Dan Talaycoef701f42010-05-07 09:22:35 -070065 def sig_handler(self, v1, v2):
Dan Talayco48370102010-03-03 15:17:33 -080066 basic_logger.critical("Received interrupt signal; exiting")
Dan Talayco710438c2010-02-18 15:16:07 -080067 print "Received interrupt signal; exiting"
Dan Talayco2c0dba32010-03-06 22:47:06 -080068 self.clean_shutdown = False
69 self.tearDown()
Rich Lane58cf05f2012-07-11 16:41:47 -070070 raise KeyboardInterrupt
Dan Talayco710438c2010-02-18 15:16:07 -080071
Dan Talaycodba244e2010-02-15 14:08:53 -080072 def setUp(self):
Dan Talayco551befa2010-07-15 17:05:32 -070073 self.logger = basic_logger
Dan Talayco285a8382010-07-20 14:06:55 -070074 self.config = basic_config
Ed Swierk022d02e2012-08-22 06:26:36 -070075 #@todo Test cases shouldn't monkey with signals; move SIGINT handler
76 # to top-level oft
77 try:
78 signal.signal(signal.SIGINT, self.sig_handler)
79 except ValueError, e:
80 basic_logger.info("Could not set SIGINT handler: %s" % e)
Dan Talayco9f47f4d2010-06-03 13:54:37 -070081 basic_logger.info("** START TEST CASE " + str(self))
Dan Talayco2c0dba32010-03-06 22:47:06 -080082 self.controller = controller.Controller(
83 host=basic_config["controller_host"],
84 port=basic_config["controller_port"])
Dan Talaycof8f41402010-03-12 22:17:39 -080085 # clean_shutdown should be set to False to force quit app
Dan Talayco2c0dba32010-03-06 22:47:06 -080086 self.clean_shutdown = True
Dan Talayco710438c2010-02-18 15:16:07 -080087 self.controller.start()
Dan Talaycoef701f42010-05-07 09:22:35 -070088 #@todo Add an option to wait for a pkt transaction to ensure version
89 # compatibilty?
Dan Talayco710438c2010-02-18 15:16:07 -080090 self.controller.connect(timeout=20)
Dan Talaycoef701f42010-05-07 09:22:35 -070091 if not self.controller.active:
Rich Lane58cf05f2012-07-11 16:41:47 -070092 raise Exception("Controller startup failed")
Dan Talayco677c0b72011-08-23 22:53:38 -070093 if self.controller.switch_addr is None:
Rich Lane58cf05f2012-07-11 16:41:47 -070094 raise Exception("Controller startup failed (no switch addr)")
Dan Talayco48370102010-03-03 15:17:33 -080095 basic_logger.info("Connected " + str(self.controller.switch_addr))
Ed Swierkc7193a22012-08-22 06:51:02 -070096 request = message.features_request()
97 reply, pkt = self.controller.transact(request, timeout=10)
98 self.supported_actions = reply.actions
99 basic_logger.info("Supported actions: " + hex(self.supported_actions))
Dan Talaycodba244e2010-02-15 14:08:53 -0800100
Dan Talayco677cc112012-03-27 10:28:58 -0700101 def inheritSetup(self, parent):
102 """
103 Inherit the setup of a parent
104
105 This allows running at test from within another test. Do the
106 following:
107
108 sub_test = SomeTestClass() # Create an instance of the test class
109 sub_test.inheritSetup(self) # Inherit setup of parent
110 sub_test.runTest() # Run the test
111
112 Normally, only the parent's setUp and tearDown are called and
113 the state after the sub_test is run must be taken into account
114 by subsequent operations.
115 """
116 self.logger = parent.logger
117 self.config = parent.config
118 basic_logger.info("** Setup " + str(self) + " inheriting from "
119 + str(parent))
120 self.controller = parent.controller
Ed Swierk6192e512012-08-22 11:41:40 -0700121 self.supported_actions = parent.supported_actions
Dan Talayco677cc112012-03-27 10:28:58 -0700122
Dan Talaycodba244e2010-02-15 14:08:53 -0800123 def tearDown(self):
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700124 basic_logger.info("** END TEST CASE " + str(self))
Dan Talaycodba244e2010-02-15 14:08:53 -0800125 self.controller.shutdown()
Dan Talayco2c0dba32010-03-06 22:47:06 -0800126 #@todo Review if join should be done on clean_shutdown
Dan Talaycof8f41402010-03-12 22:17:39 -0800127 if self.clean_shutdown:
128 self.controller.join()
Dan Talaycodba244e2010-02-15 14:08:53 -0800129
130 def runTest(self):
Dan Talayco710438c2010-02-18 15:16:07 -0800131 # Just a simple sanity check as illustration
Dan Talayco48370102010-03-03 15:17:33 -0800132 basic_logger.info("Running simple proto test")
Dan Talayco710438c2010-02-18 15:16:07 -0800133 self.assertTrue(self.controller.switch_socket is not None,
Dan Talaycodba244e2010-02-15 14:08:53 -0800134 str(self) + 'No connection to switch')
135
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700136 def assertTrue(self, cond, msg):
137 if not cond:
138 basic_logger.error("** FAILED ASSERTION: " + msg)
139 unittest.TestCase.assertTrue(self, cond, msg)
140
Dan Talaycoc24aaae2010-07-08 14:05:24 -0700141test_prio["SimpleProtocol"] = 1
142
Dan Talayco6ce963a2010-03-07 21:58:13 -0800143class SimpleDataPlane(SimpleProtocol):
Dan Talaycodba244e2010-02-15 14:08:53 -0800144 """
145 Root class that sets up the controller and dataplane
146 """
147 def setUp(self):
Dan Talayco6ce963a2010-03-07 21:58:13 -0800148 SimpleProtocol.setUp(self)
Jeffrey Townsend4d5ca922012-07-11 11:37:35 -0700149 self.dataplane = dataplane.DataPlane(self.config)
Dan Talayco48370102010-03-03 15:17:33 -0800150 for of_port, ifname in basic_port_map.items():
Dan Talaycodba244e2010-02-15 14:08:53 -0800151 self.dataplane.port_add(ifname, of_port)
152
Dan Talayco677cc112012-03-27 10:28:58 -0700153 def inheritSetup(self, parent):
154 """
155 Inherit the setup of a parent
156
157 See SimpleProtocol.inheritSetup
158 """
159 SimpleProtocol.inheritSetup(self, parent)
160 self.dataplane = parent.dataplane
161
Dan Talaycodba244e2010-02-15 14:08:53 -0800162 def tearDown(self):
Dan Talayco48370102010-03-03 15:17:33 -0800163 basic_logger.info("Teardown for simple dataplane test")
Dan Talayco6ce963a2010-03-07 21:58:13 -0800164 SimpleProtocol.tearDown(self)
Rich Lane58cf05f2012-07-11 16:41:47 -0700165 if hasattr(self, 'dataplane'):
166 self.dataplane.kill(join_threads=self.clean_shutdown)
Dan Talayco48370102010-03-03 15:17:33 -0800167 basic_logger.info("Teardown done")
Dan Talaycodba244e2010-02-15 14:08:53 -0800168
169 def runTest(self):
Dan Talayco710438c2010-02-18 15:16:07 -0800170 self.assertTrue(self.controller.switch_socket is not None,
Dan Talaycodba244e2010-02-15 14:08:53 -0800171 str(self) + 'No connection to switch')
172 # self.dataplane.show()
173 # Would like an assert that checks the data plane
174
Dan Talayco551befa2010-07-15 17:05:32 -0700175class DataPlaneOnly(unittest.TestCase):
176 """
177 Root class that sets up only the dataplane
178 """
179
180 def sig_handler(self, v1, v2):
181 basic_logger.critical("Received interrupt signal; exiting")
182 print "Received interrupt signal; exiting"
183 self.clean_shutdown = False
184 self.tearDown()
Rich Lane58cf05f2012-07-11 16:41:47 -0700185 raise KeyboardInterrupt
Dan Talayco551befa2010-07-15 17:05:32 -0700186
187 def setUp(self):
Shudong Zhoue3582a52012-08-03 20:46:50 -0700188 self.clean_shutdown = True
Dan Talayco551befa2010-07-15 17:05:32 -0700189 self.logger = basic_logger
Dan Talayco285a8382010-07-20 14:06:55 -0700190 self.config = basic_config
Ed Swierk022d02e2012-08-22 06:26:36 -0700191 #@todo Test cases shouldn't monkey with signals; move SIGINT handler
192 # to top-level oft
193 try:
194 signal.signal(signal.SIGINT, self.sig_handler)
195 except ValueError, e:
196 basic_logger.info("Could not set SIGINT handler: %s" % e)
Dan Talayco551befa2010-07-15 17:05:32 -0700197 basic_logger.info("** START DataPlaneOnly CASE " + str(self))
Jeffrey Townsend4d5ca922012-07-11 11:37:35 -0700198 self.dataplane = dataplane.DataPlane(self.config)
Dan Talayco551befa2010-07-15 17:05:32 -0700199 for of_port, ifname in basic_port_map.items():
200 self.dataplane.port_add(ifname, of_port)
201
202 def tearDown(self):
203 basic_logger.info("Teardown for simple dataplane test")
204 self.dataplane.kill(join_threads=self.clean_shutdown)
205 basic_logger.info("Teardown done")
206
207 def runTest(self):
Dan Talaycoba4fd4f2010-07-21 21:49:41 -0700208 basic_logger.info("DataPlaneOnly")
Dan Talayco285a8382010-07-20 14:06:55 -0700209 # self.dataplane.show()
Dan Talayco551befa2010-07-15 17:05:32 -0700210 # Would like an assert that checks the data plane
211
Dan Talayco6ce963a2010-03-07 21:58:13 -0800212class Echo(SimpleProtocol):
Dan Talaycodba244e2010-02-15 14:08:53 -0800213 """
214 Test echo response with no data
215 """
216 def runTest(self):
Dan Talayco2c0dba32010-03-06 22:47:06 -0800217 request = message.echo_request()
Dan Talaycoe226eb12010-02-18 23:06:30 -0800218 response, pkt = self.controller.transact(request)
Dan Talayco2c0dba32010-03-06 22:47:06 -0800219 self.assertEqual(response.header.type, ofp.OFPT_ECHO_REPLY,
Dan Talaycoa92e75b2010-02-16 20:53:56 -0800220 'response is not echo_reply')
Dan Talaycodba244e2010-02-15 14:08:53 -0800221 self.assertEqual(request.header.xid, response.header.xid,
222 'response xid != request xid')
223 self.assertEqual(len(response.data), 0, 'response data non-empty')
224
Dan Talayco6ce963a2010-03-07 21:58:13 -0800225class EchoWithData(SimpleProtocol):
Dan Talaycodba244e2010-02-15 14:08:53 -0800226 """
227 Test echo response with short string data
228 """
229 def runTest(self):
Dan Talayco2c0dba32010-03-06 22:47:06 -0800230 request = message.echo_request()
Dan Talaycodba244e2010-02-15 14:08:53 -0800231 request.data = 'OpenFlow Will Rule The World'
Dan Talaycoe226eb12010-02-18 23:06:30 -0800232 response, pkt = self.controller.transact(request)
Dan Talayco2c0dba32010-03-06 22:47:06 -0800233 self.assertEqual(response.header.type, ofp.OFPT_ECHO_REPLY,
Dan Talaycoa92e75b2010-02-16 20:53:56 -0800234 'response is not echo_reply')
Dan Talaycodba244e2010-02-15 14:08:53 -0800235 self.assertEqual(request.header.xid, response.header.xid,
236 'response xid != request xid')
237 self.assertEqual(request.data, response.data,
238 'response data does not match request')
239
Dan Talayco6ce963a2010-03-07 21:58:13 -0800240class PacketIn(SimpleDataPlane):
Dan Talaycodba244e2010-02-15 14:08:53 -0800241 """
242 Test packet in function
Dan Talayco6ce963a2010-03-07 21:58:13 -0800243
244 Send a packet to each dataplane port and verify that a packet
245 in message is received from the controller for each
Dan Talaycodba244e2010-02-15 14:08:53 -0800246 """
247 def runTest(self):
248 # Construct packet to send to dataplane
Dan Talaycoe226eb12010-02-18 23:06:30 -0800249 # Send packet to dataplane, once to each port
Dan Talaycodba244e2010-02-15 14:08:53 -0800250 # Poll controller with expect message type packet in
Dan Talaycoe226eb12010-02-18 23:06:30 -0800251
Dan Talayco6ce963a2010-03-07 21:58:13 -0800252 rc = delete_all_flows(self.controller, basic_logger)
253 self.assertEqual(rc, 0, "Failed to delete all flows")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700254 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco6ce963a2010-03-07 21:58:13 -0800255
Dan Talayco48370102010-03-03 15:17:33 -0800256 for of_port in basic_port_map.keys():
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700257 for pkt, pt in [
258 (simple_tcp_packet(), "simple TCP packet"),
259 (simple_eth_packet(), "simple Ethernet packet"),
260 (simple_eth_packet(pktlen=40), "tiny Ethernet packet")]:
Dan Talaycodba244e2010-02-15 14:08:53 -0800261
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700262 basic_logger.info("PKT IN test with %s, port %s" % (pt, of_port))
263 self.dataplane.send(of_port, str(pkt))
264 #@todo Check for unexpected messages?
265 count = 0
266 while True:
267 (response, raw) = self.controller.poll(ofp.OFPT_PACKET_IN, 2)
268 if not response: # Timeout
269 break
Ed Swierk506614a2012-03-29 08:16:59 -0700270 if dataplane.match_exp_pkt(pkt, response.data): # Got match
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700271 break
272 if not basic_config["relax"]: # Only one attempt to match
273 break
274 count += 1
275 if count > 10: # Too many tries
276 break
Dan Talayco48370102010-03-03 15:17:33 -0800277
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700278 self.assertTrue(response is not None,
279 'Packet in message not received on port ' +
280 str(of_port))
Ed Swierk506614a2012-03-29 08:16:59 -0700281 if not dataplane.match_exp_pkt(pkt, response.data):
Dan Talayco2baf8b52012-03-30 09:55:42 -0700282 basic_logger.debug("Sent %s" % format_packet(pkt))
283 basic_logger.debug("Resp %s" % format_packet(response.data))
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700284 self.assertTrue(False,
285 'Response packet does not match send packet' +
286 ' for port ' + str(of_port))
Dan Talaycodba244e2010-02-15 14:08:53 -0800287
Ed Swierk3ae7f712012-08-22 06:45:25 -0700288class PacketInDefaultDrop(SimpleDataPlane):
289 """
290 Test packet in function
291
292 Send a packet to each dataplane port and verify that a packet
293 in message is received from the controller for each
294 """
295 def runTest(self):
296 rc = delete_all_flows(self.controller, basic_logger)
297 self.assertEqual(rc, 0, "Failed to delete all flows")
298 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
299
300 for of_port in basic_port_map.keys():
301 pkt = simple_tcp_packet()
302 self.dataplane.send(of_port, str(pkt))
303 count = 0
304 while True:
305 (response, raw) = self.controller.poll(ofp.OFPT_PACKET_IN, 2)
306 if not response: # Timeout
307 break
308 if dataplane.match_exp_pkt(pkt, response.data): # Got match
309 break
310 if not basic_config["relax"]: # Only one attempt to match
311 break
312 count += 1
313 if count > 10: # Too many tries
314 break
315
316 self.assertTrue(response is None,
317 'Packet in message received on port ' +
318 str(of_port))
319
320test_prio["PacketInDefaultDrop"] = -1
321
Jeffrey Townsend4d5ca922012-07-11 11:37:35 -0700322
Dan Talayco1f648cb2012-05-03 09:37:56 -0700323class PacketInBroadcastCheck(SimpleDataPlane):
324 """
325 Check if bcast pkts leak when no flows are present
326
327 Clear the flow table
328 Send in a broadcast pkt
329 Look for the packet on other dataplane ports.
330 """
331 def runTest(self):
332 # Need at least two ports
333 self.assertTrue(len(basic_port_map) > 1, "Too few ports for test")
334
335 rc = delete_all_flows(self.controller, basic_logger)
336 self.assertEqual(rc, 0, "Failed to delete all flows")
337 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
338
339 of_ports = basic_port_map.keys()
340 d_port = of_ports[0]
341 pkt = simple_eth_packet(dl_dst='ff:ff:ff:ff:ff:ff')
342
343 basic_logger.info("BCast Leak Test, send to port %s" % d_port)
344 self.dataplane.send(d_port, str(pkt))
345
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700346 (of_port, pkt_in, pkt_time) = self.dataplane.poll(exp_pkt=pkt)
Dan Talayco1f648cb2012-05-03 09:37:56 -0700347 self.assertTrue(pkt_in is None,
348 'BCast packet received on port ' + str(of_port))
349
350test_prio["PacketInBroadcastCheck"] = -1
351
Dan Talayco6ce963a2010-03-07 21:58:13 -0800352class PacketOut(SimpleDataPlane):
Dan Talaycodba244e2010-02-15 14:08:53 -0800353 """
354 Test packet out function
Dan Talayco6ce963a2010-03-07 21:58:13 -0800355
356 Send packet out message to controller for each dataplane port and
357 verify the packet appears on the appropriate dataplane port
Dan Talaycodba244e2010-02-15 14:08:53 -0800358 """
359 def runTest(self):
360 # Construct packet to send to dataplane
361 # Send packet to dataplane
362 # Poll controller with expect message type packet in
Dan Talayco41eae8b2010-03-10 13:57:06 -0800363
364 rc = delete_all_flows(self.controller, basic_logger)
365 self.assertEqual(rc, 0, "Failed to delete all flows")
Dan Talaycodba244e2010-02-15 14:08:53 -0800366
367 # These will get put into function
Dan Talayco48370102010-03-03 15:17:33 -0800368 of_ports = basic_port_map.keys()
369 of_ports.sort()
370 for dp_port in of_ports:
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700371 for outpkt, opt in [
372 (simple_tcp_packet(), "simple TCP packet"),
373 (simple_eth_packet(), "simple Ethernet packet"),
374 (simple_eth_packet(pktlen=40), "tiny Ethernet packet")]:
Dan Talaycodba244e2010-02-15 14:08:53 -0800375
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700376 basic_logger.info("PKT OUT test with %s, port %s" % (opt, dp_port))
377 msg = message.packet_out()
378 msg.data = str(outpkt)
379 act = action.action_output()
380 act.port = dp_port
381 self.assertTrue(msg.actions.add(act), 'Could not add action to msg')
Dan Talaycodba244e2010-02-15 14:08:53 -0800382
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700383 basic_logger.info("PacketOut to: " + str(dp_port))
384 rv = self.controller.message_send(msg)
385 self.assertTrue(rv == 0, "Error sending out message")
Dan Talaycodba244e2010-02-15 14:08:53 -0800386
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700387 exp_pkt_arg = None
388 exp_port = None
389 if basic_config["relax"]:
390 exp_pkt_arg = outpkt
391 exp_port = dp_port
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700392 (of_port, pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700393 exp_pkt=exp_pkt_arg)
394
395 self.assertTrue(pkt is not None, 'Packet not received')
396 basic_logger.info("PacketOut: got pkt from " + str(of_port))
397 if of_port is not None:
398 self.assertEqual(of_port, dp_port, "Unexpected receive port")
Ed Swierk506614a2012-03-29 08:16:59 -0700399 if not dataplane.match_exp_pkt(outpkt, pkt):
Dan Talayco2baf8b52012-03-30 09:55:42 -0700400 basic_logger.debug("Sent %s" % format_packet(outpkt))
401 basic_logger.debug("Resp %s" % format_packet(
402 str(pkt)[:len(str(outpkt))]))
Dan Talaycodc6fca32012-03-30 10:05:49 -0700403 self.assertEqual(str(outpkt), str(pkt)[:len(str(outpkt))],
404 'Response packet does not match send packet')
Dan Talaycodba244e2010-02-15 14:08:53 -0800405
Ken Chiang1bf01602012-04-04 10:48:23 -0700406class PacketOutMC(SimpleDataPlane):
407 """
408 Test packet out to multiple output ports
409
410 Send packet out message to controller for 1 to N dataplane ports and
411 verify the packet appears on the appropriate ports
412 """
413 def runTest(self):
414 # Construct packet to send to dataplane
415 # Send packet to dataplane
416 # Poll controller with expect message type packet in
417
418 rc = delete_all_flows(self.controller, basic_logger)
419 self.assertEqual(rc, 0, "Failed to delete all flows")
420
421 # These will get put into function
422 of_ports = basic_port_map.keys()
423 random.shuffle(of_ports)
424 for num_ports in range(1,len(of_ports)+1):
425 for outpkt, opt in [
426 (simple_tcp_packet(), "simple TCP packet"),
427 (simple_eth_packet(), "simple Ethernet packet"),
428 (simple_eth_packet(pktlen=40), "tiny Ethernet packet")]:
429
430 dp_ports = of_ports[0:num_ports]
431 basic_logger.info("PKT OUT test with " + opt +
432 ", ports " + str(dp_ports))
433 msg = message.packet_out()
434 msg.data = str(outpkt)
435 act = action.action_output()
436 for i in range(0,num_ports):
437 act.port = dp_ports[i]
438 self.assertTrue(msg.actions.add(act),
439 'Could not add action to msg')
440
441 basic_logger.info("PacketOut to: " + str(dp_ports))
442 rv = self.controller.message_send(msg)
443 self.assertTrue(rv == 0, "Error sending out message")
444
445 receive_pkt_check(self.dataplane, outpkt, dp_ports,
446 set(of_ports).difference(dp_ports),
447 self, basic_logger, basic_config)
448
Dan Talayco6ce963a2010-03-07 21:58:13 -0800449class FlowStatsGet(SimpleProtocol):
450 """
451 Get stats
Dan Talayco2c0dba32010-03-06 22:47:06 -0800452
Dan Talayco6ce963a2010-03-07 21:58:13 -0800453 Simply verify stats get transaction
454 """
455 def runTest(self):
456 basic_logger.info("Running StatsGet")
Dan Talayco41eae8b2010-03-10 13:57:06 -0800457 basic_logger.info("Inserting trial flow")
Dan Talayco677c0b72011-08-23 22:53:38 -0700458 request = flow_mod_gen(basic_port_map, True)
Dan Talayco41eae8b2010-03-10 13:57:06 -0800459 rv = self.controller.message_send(request)
460 self.assertTrue(rv != -1, "Failed to insert test flow")
461
462 basic_logger.info("Sending flow request")
Dan Talayco6ce963a2010-03-07 21:58:13 -0800463 request = message.flow_stats_request()
464 request.out_port = ofp.OFPP_NONE
Dan Talayco41eae8b2010-03-10 13:57:06 -0800465 request.table_id = 0xff
466 request.match.wildcards = 0 # ofp.OFPFW_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700467 response, pkt = self.controller.transact(request)
Dan Talayco6ce963a2010-03-07 21:58:13 -0800468 self.assertTrue(response is not None, "Did not get response")
Dan Talaycob3f43fe2010-05-13 14:24:20 -0700469 basic_logger.debug(response.show())
Dan Talayco6ce963a2010-03-07 21:58:13 -0800470
Dan Talayco677c0b72011-08-23 22:53:38 -0700471test_prio["FlowStatsGet"] = -1
472
Dan Talayco79c6c4d2010-06-08 14:01:53 -0700473class TableStatsGet(SimpleProtocol):
474 """
475 Get table stats
476
477 Simply verify table stats get transaction
478 """
479 def runTest(self):
480 basic_logger.info("Running TableStatsGet")
481 basic_logger.info("Inserting trial flow")
Dan Talayco677c0b72011-08-23 22:53:38 -0700482 request = flow_mod_gen(basic_port_map, True)
Dan Talayco79c6c4d2010-06-08 14:01:53 -0700483 rv = self.controller.message_send(request)
484 self.assertTrue(rv != -1, "Failed to insert test flow")
485
486 basic_logger.info("Sending table stats request")
487 request = message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700488 response, pkt = self.controller.transact(request)
Dan Talayco79c6c4d2010-06-08 14:01:53 -0700489 self.assertTrue(response is not None, "Did not get response")
490 basic_logger.debug(response.show())
491
Ed Swierkae74c362012-04-02 08:21:41 -0700492class DescStatsGet(SimpleProtocol):
493 """
494 Get stats
495
496 Simply verify stats get transaction
497 """
498 def runTest(self):
499 basic_logger.info("Running DescStatsGet")
500
501 basic_logger.info("Sending stats request")
502 request = message.desc_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700503 response, pkt = self.controller.transact(request)
Ed Swierkae74c362012-04-02 08:21:41 -0700504 self.assertTrue(response is not None, "Did not get response")
505 basic_logger.debug(response.show())
506
Dan Talayco6ce963a2010-03-07 21:58:13 -0800507class FlowMod(SimpleProtocol):
508 """
509 Insert a flow
510
511 Simple verification of a flow mod transaction
512 """
513
514 def runTest(self):
515 basic_logger.info("Running " + str(self))
Dan Talayco677c0b72011-08-23 22:53:38 -0700516 request = flow_mod_gen(basic_port_map, True)
Dan Talayco6ce963a2010-03-07 21:58:13 -0800517 rv = self.controller.message_send(request)
Dan Talayco41eae8b2010-03-10 13:57:06 -0800518 self.assertTrue(rv != -1, "Error installing flow mod")
519
Dan Talaycob3f43fe2010-05-13 14:24:20 -0700520class PortConfigMod(SimpleProtocol):
521 """
522 Modify a bit in port config and verify changed
523
524 Get the switch configuration, modify the port configuration
525 and write it back; get the config again and verify changed.
526 Then set it back to the way it was.
527 """
528
529 def runTest(self):
530 basic_logger.info("Running " + str(self))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700531 for of_port, ifname in basic_port_map.items(): # Grab first port
532 break
Dan Talaycob3f43fe2010-05-13 14:24:20 -0700533
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700534 (hw_addr, config, advert) = \
535 port_config_get(self.controller, of_port, basic_logger)
536 self.assertTrue(config is not None, "Did not get port config")
537
538 basic_logger.debug("No flood bit port " + str(of_port) + " is now " +
539 str(config & ofp.OFPPC_NO_FLOOD))
540
541 rv = port_config_set(self.controller, of_port,
542 config ^ ofp.OFPPC_NO_FLOOD, ofp.OFPPC_NO_FLOOD,
543 basic_logger)
Dan Talaycob3f43fe2010-05-13 14:24:20 -0700544 self.assertTrue(rv != -1, "Error sending port mod")
545
546 # Verify change took place with same feature request
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700547 (hw_addr, config2, advert) = \
548 port_config_get(self.controller, of_port, basic_logger)
549 basic_logger.debug("No flood bit port " + str(of_port) + " is now " +
550 str(config2 & ofp.OFPPC_NO_FLOOD))
551 self.assertTrue(config2 is not None, "Did not get port config2")
552 self.assertTrue(config2 & ofp.OFPPC_NO_FLOOD !=
553 config & ofp.OFPPC_NO_FLOOD,
554 "Bit change did not take")
Dan Talaycob3f43fe2010-05-13 14:24:20 -0700555 # Set it back
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700556 rv = port_config_set(self.controller, of_port, config,
557 ofp.OFPPC_NO_FLOOD, basic_logger)
558 self.assertTrue(rv != -1, "Error sending port mod")
Dan Talaycob3f43fe2010-05-13 14:24:20 -0700559
Dan Talaycodba244e2010-02-15 14:08:53 -0800560if __name__ == "__main__":
Dan Talayco2c0dba32010-03-06 22:47:06 -0800561 print "Please run through oft script: ./oft --test_spec=basic"