blob: a96adc87929e9512a3a8a92f974dbaf38fb41f8e [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
19import sys
Dan Talayco48370102010-03-03 15:17:33 -080020import logging
Dan Talaycodba244e2010-02-15 14:08:53 -080021
Dan Talayco2c0dba32010-03-06 22:47:06 -080022import unittest
Ken Chiang1bf01602012-04-04 10:48:23 -070023import random
Dan Talayco2c0dba32010-03-06 22:47:06 -080024
25import oftest.controller as controller
26import oftest.cstruct as ofp
27import oftest.message as message
28import oftest.dataplane as dataplane
29import oftest.action as action
30
Dan Talaycoe605b1b2012-09-18 06:56:20 -070031import oftest.illegal_message as illegal_message
32
Rich Laneda3b5ad2012-10-03 09:05:32 -070033from oftest.testutils import *
Dan Talayco6ce963a2010-03-07 21:58:13 -080034
35#@var basic_port_map Local copy of the configuration map from OF port
36# numbers to OS interfaces
Dan Talayco48370102010-03-03 15:17:33 -080037basic_port_map = None
Dan Talayco6ce963a2010-03-07 21:58:13 -080038#@var basic_config Local copy of global configuration data
Dan Talayco48370102010-03-03 15:17:33 -080039basic_config = None
40
Ken Chiangaeb23d62012-08-23 21:20:07 -070041TEST_VID_DEFAULT = 2
42
Dan Talayco48370102010-03-03 15:17:33 -080043def test_set_init(config):
44 """
45 Set up function for basic test classes
46
47 @param config The configuration dictionary; see oft
Dan Talayco48370102010-03-03 15:17:33 -080048 """
49
50 global basic_port_map
Dan Talayco48370102010-03-03 15:17:33 -080051 global basic_config
52
Dan Talayco48370102010-03-03 15:17:33 -080053 basic_port_map = config["port_map"]
54 basic_config = config
Dan Talayco48370102010-03-03 15:17:33 -080055
Dan Talayco6ce963a2010-03-07 21:58:13 -080056class SimpleProtocol(unittest.TestCase):
Dan Talaycodba244e2010-02-15 14:08:53 -080057 """
58 Root class for setting up the controller
59 """
60
Rich Laned1d9c282012-10-04 22:07:10 -070061 priority = 1
62
Dan Talaycodba244e2010-02-15 14:08:53 -080063 def setUp(self):
Dan Talayco285a8382010-07-20 14:06:55 -070064 self.config = basic_config
Rich Lane9a003812012-10-04 17:17:59 -070065 logging.info("** START TEST CASE " + str(self))
Dan Talayco2c0dba32010-03-06 22:47:06 -080066 self.controller = controller.Controller(
67 host=basic_config["controller_host"],
68 port=basic_config["controller_port"])
Dan Talaycof8f41402010-03-12 22:17:39 -080069 # clean_shutdown should be set to False to force quit app
Dan Talayco2c0dba32010-03-06 22:47:06 -080070 self.clean_shutdown = True
Dan Talayco710438c2010-02-18 15:16:07 -080071 self.controller.start()
Dan Talaycoef701f42010-05-07 09:22:35 -070072 #@todo Add an option to wait for a pkt transaction to ensure version
73 # compatibilty?
Dan Talayco710438c2010-02-18 15:16:07 -080074 self.controller.connect(timeout=20)
Dan Talayco5d0f7cc2012-09-19 11:28:58 -070075
76 # By default, respond to echo requests
77 self.controller.keep_alive = True
78
Dan Talaycoef701f42010-05-07 09:22:35 -070079 if not self.controller.active:
Rich Lane58cf05f2012-07-11 16:41:47 -070080 raise Exception("Controller startup failed")
Dan Talayco677c0b72011-08-23 22:53:38 -070081 if self.controller.switch_addr is None:
Rich Lane58cf05f2012-07-11 16:41:47 -070082 raise Exception("Controller startup failed (no switch addr)")
Rich Lane9a003812012-10-04 17:17:59 -070083 logging.info("Connected " + str(self.controller.switch_addr))
Ed Swierkc7193a22012-08-22 06:51:02 -070084 request = message.features_request()
Dan Talaycoc689a792012-09-28 14:22:53 -070085 reply, pkt = self.controller.transact(request)
Dan Talayco97d4f362012-09-18 03:22:09 -070086 self.assertTrue(reply is not None,
87 "Did not complete features_request for handshake")
Ed Swierkc7193a22012-08-22 06:51:02 -070088 self.supported_actions = reply.actions
Rich Lane9a003812012-10-04 17:17:59 -070089 logging.info("Supported actions: " + hex(self.supported_actions))
Dan Talaycodba244e2010-02-15 14:08:53 -080090
Dan Talayco677cc112012-03-27 10:28:58 -070091 def inheritSetup(self, parent):
92 """
93 Inherit the setup of a parent
94
95 This allows running at test from within another test. Do the
96 following:
97
98 sub_test = SomeTestClass() # Create an instance of the test class
99 sub_test.inheritSetup(self) # Inherit setup of parent
100 sub_test.runTest() # Run the test
101
102 Normally, only the parent's setUp and tearDown are called and
103 the state after the sub_test is run must be taken into account
104 by subsequent operations.
105 """
Dan Talayco677cc112012-03-27 10:28:58 -0700106 self.config = parent.config
Rich Lane9a003812012-10-04 17:17:59 -0700107 logging.info("** Setup " + str(self) + " inheriting from "
Dan Talayco677cc112012-03-27 10:28:58 -0700108 + str(parent))
109 self.controller = parent.controller
Ed Swierk6192e512012-08-22 11:41:40 -0700110 self.supported_actions = parent.supported_actions
Dan Talayco677cc112012-03-27 10:28:58 -0700111
Dan Talaycodba244e2010-02-15 14:08:53 -0800112 def tearDown(self):
Rich Lane9a003812012-10-04 17:17:59 -0700113 logging.info("** END TEST CASE " + str(self))
Dan Talaycodba244e2010-02-15 14:08:53 -0800114 self.controller.shutdown()
Dan Talayco2c0dba32010-03-06 22:47:06 -0800115 #@todo Review if join should be done on clean_shutdown
Dan Talaycof8f41402010-03-12 22:17:39 -0800116 if self.clean_shutdown:
117 self.controller.join()
Dan Talaycodba244e2010-02-15 14:08:53 -0800118
119 def runTest(self):
Dan Talayco710438c2010-02-18 15:16:07 -0800120 # Just a simple sanity check as illustration
Rich Lane9a003812012-10-04 17:17:59 -0700121 logging.info("Running simple proto test")
Dan Talayco710438c2010-02-18 15:16:07 -0800122 self.assertTrue(self.controller.switch_socket is not None,
Dan Talaycodba244e2010-02-15 14:08:53 -0800123 str(self) + 'No connection to switch')
124
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700125 def assertTrue(self, cond, msg):
126 if not cond:
Rich Lane9a003812012-10-04 17:17:59 -0700127 logging.error("** FAILED ASSERTION: " + msg)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700128 unittest.TestCase.assertTrue(self, cond, msg)
129
Dan Talayco6ce963a2010-03-07 21:58:13 -0800130class SimpleDataPlane(SimpleProtocol):
Dan Talaycodba244e2010-02-15 14:08:53 -0800131 """
132 Root class that sets up the controller and dataplane
133 """
134 def setUp(self):
Dan Talayco6ce963a2010-03-07 21:58:13 -0800135 SimpleProtocol.setUp(self)
Jeffrey Townsend4d5ca922012-07-11 11:37:35 -0700136 self.dataplane = dataplane.DataPlane(self.config)
Dan Talayco48370102010-03-03 15:17:33 -0800137 for of_port, ifname in basic_port_map.items():
Dan Talaycodba244e2010-02-15 14:08:53 -0800138 self.dataplane.port_add(ifname, of_port)
139
Dan Talayco677cc112012-03-27 10:28:58 -0700140 def inheritSetup(self, parent):
141 """
142 Inherit the setup of a parent
143
144 See SimpleProtocol.inheritSetup
145 """
146 SimpleProtocol.inheritSetup(self, parent)
147 self.dataplane = parent.dataplane
148
Dan Talaycodba244e2010-02-15 14:08:53 -0800149 def tearDown(self):
Rich Lane9a003812012-10-04 17:17:59 -0700150 logging.info("Teardown for simple dataplane test")
Dan Talayco6ce963a2010-03-07 21:58:13 -0800151 SimpleProtocol.tearDown(self)
Rich Lane58cf05f2012-07-11 16:41:47 -0700152 if hasattr(self, 'dataplane'):
153 self.dataplane.kill(join_threads=self.clean_shutdown)
Rich Lane9a003812012-10-04 17:17:59 -0700154 logging.info("Teardown done")
Dan Talaycodba244e2010-02-15 14:08:53 -0800155
156 def runTest(self):
Dan Talayco710438c2010-02-18 15:16:07 -0800157 self.assertTrue(self.controller.switch_socket is not None,
Dan Talaycodba244e2010-02-15 14:08:53 -0800158 str(self) + 'No connection to switch')
159 # self.dataplane.show()
160 # Would like an assert that checks the data plane
161
Dan Talayco551befa2010-07-15 17:05:32 -0700162class DataPlaneOnly(unittest.TestCase):
163 """
164 Root class that sets up only the dataplane
165 """
166
Rich Laned1d9c282012-10-04 22:07:10 -0700167 priority = -1
168
Dan Talayco551befa2010-07-15 17:05:32 -0700169 def setUp(self):
Shudong Zhoue3582a52012-08-03 20:46:50 -0700170 self.clean_shutdown = True
Dan Talayco285a8382010-07-20 14:06:55 -0700171 self.config = basic_config
Rich Lane9a003812012-10-04 17:17:59 -0700172 logging.info("** START DataPlaneOnly CASE " + str(self))
Jeffrey Townsend4d5ca922012-07-11 11:37:35 -0700173 self.dataplane = dataplane.DataPlane(self.config)
Dan Talayco551befa2010-07-15 17:05:32 -0700174 for of_port, ifname in basic_port_map.items():
175 self.dataplane.port_add(ifname, of_port)
176
177 def tearDown(self):
Rich Lane9a003812012-10-04 17:17:59 -0700178 logging.info("Teardown for simple dataplane test")
Dan Talayco551befa2010-07-15 17:05:32 -0700179 self.dataplane.kill(join_threads=self.clean_shutdown)
Rich Lane9a003812012-10-04 17:17:59 -0700180 logging.info("Teardown done")
Dan Talayco551befa2010-07-15 17:05:32 -0700181
182 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -0700183 logging.info("DataPlaneOnly")
Dan Talayco285a8382010-07-20 14:06:55 -0700184 # self.dataplane.show()
Dan Talayco551befa2010-07-15 17:05:32 -0700185 # Would like an assert that checks the data plane
186
Dan Talayco6ce963a2010-03-07 21:58:13 -0800187class Echo(SimpleProtocol):
Dan Talaycodba244e2010-02-15 14:08:53 -0800188 """
189 Test echo response with no data
190 """
191 def runTest(self):
Dan Talayco2c0dba32010-03-06 22:47:06 -0800192 request = message.echo_request()
Dan Talaycoe226eb12010-02-18 23:06:30 -0800193 response, pkt = self.controller.transact(request)
Dan Talayco97d4f362012-09-18 03:22:09 -0700194 self.assertTrue(response is not None,
195 "Did not get echo reply")
Dan Talayco2c0dba32010-03-06 22:47:06 -0800196 self.assertEqual(response.header.type, ofp.OFPT_ECHO_REPLY,
Dan Talaycoa92e75b2010-02-16 20:53:56 -0800197 'response is not echo_reply')
Dan Talaycodba244e2010-02-15 14:08:53 -0800198 self.assertEqual(request.header.xid, response.header.xid,
199 'response xid != request xid')
200 self.assertEqual(len(response.data), 0, 'response data non-empty')
201
Dan Talayco6ce963a2010-03-07 21:58:13 -0800202class EchoWithData(SimpleProtocol):
Dan Talaycodba244e2010-02-15 14:08:53 -0800203 """
204 Test echo response with short string data
205 """
206 def runTest(self):
Dan Talayco2c0dba32010-03-06 22:47:06 -0800207 request = message.echo_request()
Dan Talaycodba244e2010-02-15 14:08:53 -0800208 request.data = 'OpenFlow Will Rule The World'
Dan Talaycoe226eb12010-02-18 23:06:30 -0800209 response, pkt = self.controller.transact(request)
Dan Talayco97d4f362012-09-18 03:22:09 -0700210 self.assertTrue(response is not None,
211 "Did not get echo reply (with data)")
Dan Talayco2c0dba32010-03-06 22:47:06 -0800212 self.assertEqual(response.header.type, ofp.OFPT_ECHO_REPLY,
Dan Talaycoa92e75b2010-02-16 20:53:56 -0800213 'response is not echo_reply')
Dan Talaycodba244e2010-02-15 14:08:53 -0800214 self.assertEqual(request.header.xid, response.header.xid,
215 'response xid != request xid')
216 self.assertEqual(request.data, response.data,
217 'response data does not match request')
218
Dan Talayco6ce963a2010-03-07 21:58:13 -0800219class PacketIn(SimpleDataPlane):
Dan Talaycodba244e2010-02-15 14:08:53 -0800220 """
221 Test packet in function
Dan Talayco6ce963a2010-03-07 21:58:13 -0800222
223 Send a packet to each dataplane port and verify that a packet
224 in message is received from the controller for each
Dan Talaycodba244e2010-02-15 14:08:53 -0800225 """
226 def runTest(self):
227 # Construct packet to send to dataplane
Dan Talaycoe226eb12010-02-18 23:06:30 -0800228 # Send packet to dataplane, once to each port
Dan Talaycodba244e2010-02-15 14:08:53 -0800229 # Poll controller with expect message type packet in
Dan Talaycoe226eb12010-02-18 23:06:30 -0800230
Rich Lane9a003812012-10-04 17:17:59 -0700231 rc = delete_all_flows(self.controller)
Dan Talayco6ce963a2010-03-07 21:58:13 -0800232 self.assertEqual(rc, 0, "Failed to delete all flows")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700233 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco6ce963a2010-03-07 21:58:13 -0800234
Ken Chiangaeb23d62012-08-23 21:20:07 -0700235 vid = test_param_get(self.config, 'vid', default=TEST_VID_DEFAULT)
236
Dan Talayco48370102010-03-03 15:17:33 -0800237 for of_port in basic_port_map.keys():
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700238 for pkt, pt in [
239 (simple_tcp_packet(), "simple TCP packet"),
Ken Chiangaeb23d62012-08-23 21:20:07 -0700240 (simple_tcp_packet(dl_vlan_enable=True,dl_vlan=vid,pktlen=108),
241 "simple tagged TCP packet"),
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700242 (simple_eth_packet(), "simple Ethernet packet"),
243 (simple_eth_packet(pktlen=40), "tiny Ethernet packet")]:
Dan Talaycodba244e2010-02-15 14:08:53 -0800244
Rich Lane9a003812012-10-04 17:17:59 -0700245 logging.info("PKT IN test with %s, port %s" % (pt, of_port))
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700246 self.dataplane.send(of_port, str(pkt))
247 #@todo Check for unexpected messages?
248 count = 0
249 while True:
Dan Talaycoc689a792012-09-28 14:22:53 -0700250 (response, raw) = self.controller.poll(ofp.OFPT_PACKET_IN)
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700251 if not response: # Timeout
252 break
Ed Swierk506614a2012-03-29 08:16:59 -0700253 if dataplane.match_exp_pkt(pkt, response.data): # Got match
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700254 break
255 if not basic_config["relax"]: # Only one attempt to match
256 break
257 count += 1
258 if count > 10: # Too many tries
259 break
Dan Talayco48370102010-03-03 15:17:33 -0800260
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700261 self.assertTrue(response is not None,
262 'Packet in message not received on port ' +
263 str(of_port))
Ed Swierk506614a2012-03-29 08:16:59 -0700264 if not dataplane.match_exp_pkt(pkt, response.data):
Rich Lane9a003812012-10-04 17:17:59 -0700265 logging.debug("Sent %s" % format_packet(pkt))
266 logging.debug("Resp %s" % format_packet(response.data))
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700267 self.assertTrue(False,
268 'Response packet does not match send packet' +
269 ' for port ' + str(of_port))
Dan Talaycodba244e2010-02-15 14:08:53 -0800270
Ed Swierk3ae7f712012-08-22 06:45:25 -0700271class PacketInDefaultDrop(SimpleDataPlane):
272 """
273 Test packet in function
274
275 Send a packet to each dataplane port and verify that a packet
276 in message is received from the controller for each
277 """
Rich Laned1d9c282012-10-04 22:07:10 -0700278
279 priority = -1
280
Ed Swierk3ae7f712012-08-22 06:45:25 -0700281 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -0700282 rc = delete_all_flows(self.controller)
Ed Swierk3ae7f712012-08-22 06:45:25 -0700283 self.assertEqual(rc, 0, "Failed to delete all flows")
284 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
285
286 for of_port in basic_port_map.keys():
287 pkt = simple_tcp_packet()
288 self.dataplane.send(of_port, str(pkt))
289 count = 0
290 while True:
Dan Talaycoc689a792012-09-28 14:22:53 -0700291 (response, raw) = self.controller.poll(ofp.OFPT_PACKET_IN)
Ed Swierk3ae7f712012-08-22 06:45:25 -0700292 if not response: # Timeout
293 break
294 if dataplane.match_exp_pkt(pkt, response.data): # Got match
295 break
296 if not basic_config["relax"]: # Only one attempt to match
297 break
298 count += 1
299 if count > 10: # Too many tries
300 break
301
302 self.assertTrue(response is None,
303 'Packet in message received on port ' +
304 str(of_port))
305
Dan Talayco1f648cb2012-05-03 09:37:56 -0700306class PacketInBroadcastCheck(SimpleDataPlane):
307 """
308 Check if bcast pkts leak when no flows are present
309
310 Clear the flow table
311 Send in a broadcast pkt
312 Look for the packet on other dataplane ports.
313 """
Rich Laned1d9c282012-10-04 22:07:10 -0700314
315 priority = -1
316
Dan Talayco1f648cb2012-05-03 09:37:56 -0700317 def runTest(self):
318 # Need at least two ports
319 self.assertTrue(len(basic_port_map) > 1, "Too few ports for test")
320
Rich Lane9a003812012-10-04 17:17:59 -0700321 rc = delete_all_flows(self.controller)
Dan Talayco1f648cb2012-05-03 09:37:56 -0700322 self.assertEqual(rc, 0, "Failed to delete all flows")
323 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
324
325 of_ports = basic_port_map.keys()
326 d_port = of_ports[0]
327 pkt = simple_eth_packet(dl_dst='ff:ff:ff:ff:ff:ff')
328
Rich Lane9a003812012-10-04 17:17:59 -0700329 logging.info("BCast Leak Test, send to port %s" % d_port)
Dan Talayco1f648cb2012-05-03 09:37:56 -0700330 self.dataplane.send(d_port, str(pkt))
331
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700332 (of_port, pkt_in, pkt_time) = self.dataplane.poll(exp_pkt=pkt)
Dan Talayco1f648cb2012-05-03 09:37:56 -0700333 self.assertTrue(pkt_in is None,
334 'BCast packet received on port ' + str(of_port))
335
Dan Talayco6ce963a2010-03-07 21:58:13 -0800336class PacketOut(SimpleDataPlane):
Dan Talaycodba244e2010-02-15 14:08:53 -0800337 """
338 Test packet out function
Dan Talayco6ce963a2010-03-07 21:58:13 -0800339
340 Send packet out message to controller for each dataplane port and
341 verify the packet appears on the appropriate dataplane port
Dan Talaycodba244e2010-02-15 14:08:53 -0800342 """
343 def runTest(self):
344 # Construct packet to send to dataplane
345 # Send packet to dataplane
346 # Poll controller with expect message type packet in
Dan Talayco41eae8b2010-03-10 13:57:06 -0800347
Rich Lane9a003812012-10-04 17:17:59 -0700348 rc = delete_all_flows(self.controller)
Dan Talayco41eae8b2010-03-10 13:57:06 -0800349 self.assertEqual(rc, 0, "Failed to delete all flows")
Dan Talaycodba244e2010-02-15 14:08:53 -0800350
351 # These will get put into function
Dan Talayco48370102010-03-03 15:17:33 -0800352 of_ports = basic_port_map.keys()
353 of_ports.sort()
354 for dp_port in of_ports:
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700355 for outpkt, opt in [
356 (simple_tcp_packet(), "simple TCP packet"),
357 (simple_eth_packet(), "simple Ethernet packet"),
358 (simple_eth_packet(pktlen=40), "tiny Ethernet packet")]:
Dan Talaycodba244e2010-02-15 14:08:53 -0800359
Rich Lane9a003812012-10-04 17:17:59 -0700360 logging.info("PKT OUT test with %s, port %s" % (opt, dp_port))
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700361 msg = message.packet_out()
362 msg.data = str(outpkt)
363 act = action.action_output()
364 act.port = dp_port
365 self.assertTrue(msg.actions.add(act), 'Could not add action to msg')
Dan Talaycodba244e2010-02-15 14:08:53 -0800366
Rich Lane9a003812012-10-04 17:17:59 -0700367 logging.info("PacketOut to: " + str(dp_port))
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700368 rv = self.controller.message_send(msg)
369 self.assertTrue(rv == 0, "Error sending out message")
Dan Talaycodba244e2010-02-15 14:08:53 -0800370
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700371 exp_pkt_arg = None
372 exp_port = None
373 if basic_config["relax"]:
374 exp_pkt_arg = outpkt
375 exp_port = dp_port
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700376 (of_port, pkt, pkt_time) = self.dataplane.poll(port_number=exp_port,
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700377 exp_pkt=exp_pkt_arg)
378
379 self.assertTrue(pkt is not None, 'Packet not received')
Rich Lane9a003812012-10-04 17:17:59 -0700380 logging.info("PacketOut: got pkt from " + str(of_port))
Ed Swierk0aeff8c2012-03-23 20:27:18 -0700381 if of_port is not None:
382 self.assertEqual(of_port, dp_port, "Unexpected receive port")
Ed Swierk506614a2012-03-29 08:16:59 -0700383 if not dataplane.match_exp_pkt(outpkt, pkt):
Rich Lane9a003812012-10-04 17:17:59 -0700384 logging.debug("Sent %s" % format_packet(outpkt))
385 logging.debug("Resp %s" % format_packet(
Dan Talayco2baf8b52012-03-30 09:55:42 -0700386 str(pkt)[:len(str(outpkt))]))
Dan Talaycodc6fca32012-03-30 10:05:49 -0700387 self.assertEqual(str(outpkt), str(pkt)[:len(str(outpkt))],
388 'Response packet does not match send packet')
Dan Talaycodba244e2010-02-15 14:08:53 -0800389
Ken Chiang1bf01602012-04-04 10:48:23 -0700390class PacketOutMC(SimpleDataPlane):
391 """
392 Test packet out to multiple output ports
393
394 Send packet out message to controller for 1 to N dataplane ports and
395 verify the packet appears on the appropriate ports
396 """
397 def runTest(self):
398 # Construct packet to send to dataplane
399 # Send packet to dataplane
400 # Poll controller with expect message type packet in
401
Rich Lane9a003812012-10-04 17:17:59 -0700402 rc = delete_all_flows(self.controller)
Ken Chiang1bf01602012-04-04 10:48:23 -0700403 self.assertEqual(rc, 0, "Failed to delete all flows")
404
405 # These will get put into function
406 of_ports = basic_port_map.keys()
407 random.shuffle(of_ports)
408 for num_ports in range(1,len(of_ports)+1):
409 for outpkt, opt in [
410 (simple_tcp_packet(), "simple TCP packet"),
411 (simple_eth_packet(), "simple Ethernet packet"),
412 (simple_eth_packet(pktlen=40), "tiny Ethernet packet")]:
413
414 dp_ports = of_ports[0:num_ports]
Rich Lane9a003812012-10-04 17:17:59 -0700415 logging.info("PKT OUT test with " + opt +
Ken Chiang1bf01602012-04-04 10:48:23 -0700416 ", ports " + str(dp_ports))
417 msg = message.packet_out()
418 msg.data = str(outpkt)
419 act = action.action_output()
420 for i in range(0,num_ports):
421 act.port = dp_ports[i]
422 self.assertTrue(msg.actions.add(act),
423 'Could not add action to msg')
424
Rich Lane9a003812012-10-04 17:17:59 -0700425 logging.info("PacketOut to: " + str(dp_ports))
Ken Chiang1bf01602012-04-04 10:48:23 -0700426 rv = self.controller.message_send(msg)
427 self.assertTrue(rv == 0, "Error sending out message")
428
429 receive_pkt_check(self.dataplane, outpkt, dp_ports,
430 set(of_ports).difference(dp_ports),
Rich Lane9a003812012-10-04 17:17:59 -0700431 self, basic_config)
Ken Chiang1bf01602012-04-04 10:48:23 -0700432
Dan Talayco6ce963a2010-03-07 21:58:13 -0800433class FlowStatsGet(SimpleProtocol):
434 """
435 Get stats
Dan Talayco2c0dba32010-03-06 22:47:06 -0800436
Dan Talayco6ce963a2010-03-07 21:58:13 -0800437 Simply verify stats get transaction
438 """
Rich Laned1d9c282012-10-04 22:07:10 -0700439
440 priority = -1
441
Dan Talayco6ce963a2010-03-07 21:58:13 -0800442 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -0700443 logging.info("Running StatsGet")
444 logging.info("Inserting trial flow")
Dan Talayco677c0b72011-08-23 22:53:38 -0700445 request = flow_mod_gen(basic_port_map, True)
Dan Talayco41eae8b2010-03-10 13:57:06 -0800446 rv = self.controller.message_send(request)
447 self.assertTrue(rv != -1, "Failed to insert test flow")
448
Rich Lane9a003812012-10-04 17:17:59 -0700449 logging.info("Sending flow request")
Dan Talayco6ce963a2010-03-07 21:58:13 -0800450 request = message.flow_stats_request()
451 request.out_port = ofp.OFPP_NONE
Dan Talayco41eae8b2010-03-10 13:57:06 -0800452 request.table_id = 0xff
453 request.match.wildcards = 0 # ofp.OFPFW_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700454 response, pkt = self.controller.transact(request)
Dan Talayco97d4f362012-09-18 03:22:09 -0700455 self.assertTrue(response is not None,
456 "Did not get response for flow stats")
Rich Lane9a003812012-10-04 17:17:59 -0700457 logging.debug(response.show())
Dan Talayco6ce963a2010-03-07 21:58:13 -0800458
Dan Talayco79c6c4d2010-06-08 14:01:53 -0700459class TableStatsGet(SimpleProtocol):
460 """
461 Get table stats
462
463 Simply verify table stats get transaction
464 """
465 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -0700466 logging.info("Running TableStatsGet")
467 logging.info("Inserting trial flow")
Dan Talayco677c0b72011-08-23 22:53:38 -0700468 request = flow_mod_gen(basic_port_map, True)
Dan Talayco79c6c4d2010-06-08 14:01:53 -0700469 rv = self.controller.message_send(request)
470 self.assertTrue(rv != -1, "Failed to insert test flow")
471
Rich Lane9a003812012-10-04 17:17:59 -0700472 logging.info("Sending table stats request")
Dan Talayco79c6c4d2010-06-08 14:01:53 -0700473 request = message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700474 response, pkt = self.controller.transact(request)
Dan Talayco97d4f362012-09-18 03:22:09 -0700475 self.assertTrue(response is not None,
476 "Did not get reply for table stats")
Rich Lane9a003812012-10-04 17:17:59 -0700477 logging.debug(response.show())
Dan Talayco79c6c4d2010-06-08 14:01:53 -0700478
Ed Swierkae74c362012-04-02 08:21:41 -0700479class DescStatsGet(SimpleProtocol):
480 """
481 Get stats
482
483 Simply verify stats get transaction
484 """
485 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -0700486 logging.info("Running DescStatsGet")
Ed Swierkae74c362012-04-02 08:21:41 -0700487
Rich Lane9a003812012-10-04 17:17:59 -0700488 logging.info("Sending stats request")
Ed Swierkae74c362012-04-02 08:21:41 -0700489 request = message.desc_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -0700490 response, pkt = self.controller.transact(request)
Dan Talayco97d4f362012-09-18 03:22:09 -0700491 self.assertTrue(response is not None,
492 "Did not get reply for desc stats")
Rich Lane9a003812012-10-04 17:17:59 -0700493 logging.debug(response.show())
Ed Swierkae74c362012-04-02 08:21:41 -0700494
Dan Talayco6ce963a2010-03-07 21:58:13 -0800495class FlowMod(SimpleProtocol):
496 """
497 Insert a flow
498
499 Simple verification of a flow mod transaction
500 """
501
502 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -0700503 logging.info("Running " + str(self))
Dan Talayco677c0b72011-08-23 22:53:38 -0700504 request = flow_mod_gen(basic_port_map, True)
Dan Talayco6ce963a2010-03-07 21:58:13 -0800505 rv = self.controller.message_send(request)
Dan Talayco41eae8b2010-03-10 13:57:06 -0800506 self.assertTrue(rv != -1, "Error installing flow mod")
507
Dan Talaycob3f43fe2010-05-13 14:24:20 -0700508class PortConfigMod(SimpleProtocol):
509 """
510 Modify a bit in port config and verify changed
511
512 Get the switch configuration, modify the port configuration
513 and write it back; get the config again and verify changed.
514 Then set it back to the way it was.
515 """
516
517 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -0700518 logging.info("Running " + str(self))
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700519 for of_port, ifname in basic_port_map.items(): # Grab first port
520 break
Dan Talaycob3f43fe2010-05-13 14:24:20 -0700521
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700522 (hw_addr, config, advert) = \
Rich Lane9a003812012-10-04 17:17:59 -0700523 port_config_get(self.controller, of_port)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700524 self.assertTrue(config is not None, "Did not get port config")
525
Rich Lane9a003812012-10-04 17:17:59 -0700526 logging.debug("No flood bit port " + str(of_port) + " is now " +
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700527 str(config & ofp.OFPPC_NO_FLOOD))
528
529 rv = port_config_set(self.controller, of_port,
Rich Lane9a003812012-10-04 17:17:59 -0700530 config ^ ofp.OFPPC_NO_FLOOD, ofp.OFPPC_NO_FLOOD)
Dan Talaycob3f43fe2010-05-13 14:24:20 -0700531 self.assertTrue(rv != -1, "Error sending port mod")
532
533 # Verify change took place with same feature request
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700534 (hw_addr, config2, advert) = \
Rich Lane9a003812012-10-04 17:17:59 -0700535 port_config_get(self.controller, of_port)
536 logging.debug("No flood bit port " + str(of_port) + " is now " +
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700537 str(config2 & ofp.OFPPC_NO_FLOOD))
538 self.assertTrue(config2 is not None, "Did not get port config2")
539 self.assertTrue(config2 & ofp.OFPPC_NO_FLOOD !=
540 config & ofp.OFPPC_NO_FLOOD,
541 "Bit change did not take")
Dan Talaycob3f43fe2010-05-13 14:24:20 -0700542 # Set it back
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700543 rv = port_config_set(self.controller, of_port, config,
Rich Lane9a003812012-10-04 17:17:59 -0700544 ofp.OFPPC_NO_FLOOD)
Dan Talayco9f47f4d2010-06-03 13:54:37 -0700545 self.assertTrue(rv != -1, "Error sending port mod")
Dan Talaycob3f43fe2010-05-13 14:24:20 -0700546
Ken Chiangaeb23d62012-08-23 21:20:07 -0700547class PortConfigModErr(SimpleProtocol):
548 """
549 Modify a bit in port config on an invalid port and verify
550 error message is received.
551 """
552
553 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -0700554 logging.info("Running " + str(self))
Ken Chiangaeb23d62012-08-23 21:20:07 -0700555
556 # pick a random bad port number
557 bad_port = random.randint(1, ofp.OFPP_MAX)
558 count = 0
559 while (count < 50) and (bad_port in basic_port_map.keys()):
560 bad_port = random.randint(1, ofp.OFPP_MAX)
561 count = count + 1
562 self.assertTrue(count < 50, "Error selecting bad port")
Rich Lane9a003812012-10-04 17:17:59 -0700563 logging.info("Select " + str(bad_port) + " as invalid port")
Ken Chiangaeb23d62012-08-23 21:20:07 -0700564
565 rv = port_config_set(self.controller, bad_port,
Rich Lane9a003812012-10-04 17:17:59 -0700566 ofp.OFPPC_NO_FLOOD, ofp.OFPPC_NO_FLOOD)
Ken Chiangaeb23d62012-08-23 21:20:07 -0700567 self.assertTrue(rv != -1, "Error sending port mod")
568
569 # poll for error message
570 while True:
Dan Talaycoc689a792012-09-28 14:22:53 -0700571 (response, raw) = self.controller.poll(ofp.OFPT_ERROR)
Ken Chiangaeb23d62012-08-23 21:20:07 -0700572 if not response: # Timeout
573 break
574 if response.code == ofp.OFPPMFC_BAD_PORT:
Rich Lane9a003812012-10-04 17:17:59 -0700575 logging.info("Received error message with OFPPMFC_BAD_PORT code")
Ken Chiangaeb23d62012-08-23 21:20:07 -0700576 break
577 if not basic_config["relax"]: # Only one attempt to match
578 break
579 count += 1
580 if count > 10: # Too many tries
581 break
582
583 self.assertTrue(response is not None, 'Did not receive error message')
584
Dan Talaycoe605b1b2012-09-18 06:56:20 -0700585class BadMessage(SimpleProtocol):
586 """
587 Send a message with a bad type and verify an error is returned
588 """
589
590 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -0700591 logging.info("Running " + str(self))
Dan Talaycoe605b1b2012-09-18 06:56:20 -0700592 request = illegal_message.illegal_message_type()
593
Dan Talaycoc689a792012-09-28 14:22:53 -0700594 reply, pkt = self.controller.transact(request)
Dan Talaycoe605b1b2012-09-18 06:56:20 -0700595 self.assertTrue(reply is not None, "Did not get response to bad req")
596 self.assertTrue(reply.header.type == ofp.OFPT_ERROR,
597 "reply not an error message")
598 self.assertTrue(reply.type == ofp.OFPET_BAD_REQUEST,
599 "reply error type is not bad request")
600 self.assertTrue(reply.code == ofp.OFPBRC_BAD_TYPE,
601 "reply error code is not bad type")
602
Dan Talaycodba244e2010-02-15 14:08:53 -0800603if __name__ == "__main__":
Dan Talayco2c0dba32010-03-06 22:47:06 -0800604 print "Please run through oft script: ./oft --test_spec=basic"