blob: f7db5444928549dc12cbe1ae6dac06f8559214d0 [file] [log] [blame]
Dan Talaycodba244e2010-02-15 14:08:53 -08001"""
2Basic test cases for the oftest OpenFlow test framework
3
4Current Assumptions:
5
6 The oftest framework source is in ../src/python/oftest
7 Configuration of the platform and system is stored in oft_config in that dir
8 The switch is actively attempting to contact the controller at the address
9indicated oin oft_config
10
11"""
12
13from scapy.all import *
14import unittest
15
16import time
Dan Talayco710438c2010-02-18 15:16:07 -080017import signal
Dan Talaycodba244e2010-02-15 14:08:53 -080018import sys
19sys.path.append("../src/python/oftest")
20from message import *
21from dataplane import *
22from controller import *
23from oft_config import *
24
Dan Talayco710438c2010-02-18 15:16:07 -080025#debug_level_default = DEBUG_VERBOSE
26dbg_lvl = debug_level_default
27
Dan Talaycodba244e2010-02-15 14:08:53 -080028class SimpleProtocolTestCase(unittest.TestCase):
29 """
30 Root class for setting up the controller
31 """
32
Dan Talayco710438c2010-02-18 15:16:07 -080033 def dbg(self, level, string):
34 debug_log(str(self), dbg_lvl, level, string)
35
36 def sig_handler(self):
37 print "Received interrupt signal; exiting"
38 self.controller.shutdown()
39 sys.exit(1)
40
Dan Talaycodba244e2010-02-15 14:08:53 -080041 def setUp(self):
Dan Talayco710438c2010-02-18 15:16:07 -080042 signal.signal(signal.SIGINT, self.sig_handler)
43 self.dbg(DEBUG_INFO, "Setup for " + str(self))
Dan Talaycodba244e2010-02-15 14:08:53 -080044 self.controller = Controller()
Dan Talayco710438c2010-02-18 15:16:07 -080045 self.controller.start()
46 self.controller.connect(timeout=20)
47 self.dbg(DEBUG_INFO, "Connected " + str(self.controller.switch_addr))
Dan Talaycodba244e2010-02-15 14:08:53 -080048
49 def tearDown(self):
Dan Talayco710438c2010-02-18 15:16:07 -080050 self.dbg(DEBUG_INFO, "Teardown for simple proto test")
Dan Talaycodba244e2010-02-15 14:08:53 -080051 self.controller.shutdown()
Dan Talayco710438c2010-02-18 15:16:07 -080052 # self.controller.join()
Dan Talaycodba244e2010-02-15 14:08:53 -080053
54 def runTest(self):
Dan Talayco710438c2010-02-18 15:16:07 -080055 # Just a simple sanity check as illustration
56 self.assertTrue(self.controller.switch_socket is not None,
Dan Talaycodba244e2010-02-15 14:08:53 -080057 str(self) + 'No connection to switch')
58
59class SimpleDataPlaneTestCase(SimpleProtocolTestCase):
60 """
61 Root class that sets up the controller and dataplane
62 """
63 def setUp(self):
64 SimpleProtocolTestCase.setUp(self)
65 self.dataplane = DataPlane()
66 for of_port, ifname in interface_ofport_map.items():
67 self.dataplane.port_add(ifname, of_port)
68
69 def tearDown(self):
Dan Talayco710438c2010-02-18 15:16:07 -080070 self.dbg(DEBUG_INFO, "Teardown for simple dataplane test")
Dan Talaycodba244e2010-02-15 14:08:53 -080071 SimpleProtocolTestCase.tearDown(self)
72 self.dataplane.kill(join_threads=False)
Dan Talayco710438c2010-02-18 15:16:07 -080073 self.dbg(DEBUG_INFO, "Teardown done")
Dan Talaycodba244e2010-02-15 14:08:53 -080074
75 def runTest(self):
Dan Talayco710438c2010-02-18 15:16:07 -080076 self.assertTrue(self.controller.switch_socket is not None,
Dan Talaycodba244e2010-02-15 14:08:53 -080077 str(self) + 'No connection to switch')
78 # self.dataplane.show()
79 # Would like an assert that checks the data plane
80
81class EchoTestCase(SimpleProtocolTestCase):
82 """
83 Test echo response with no data
84 """
85 def runTest(self):
86 request = echo_request()
Dan Talaycoe226eb12010-02-18 23:06:30 -080087 response, pkt = self.controller.transact(request)
Dan Talaycodba244e2010-02-15 14:08:53 -080088 self.assertEqual(response.header.type, OFPT_ECHO_REPLY,
Dan Talaycoa92e75b2010-02-16 20:53:56 -080089 'response is not echo_reply')
Dan Talaycodba244e2010-02-15 14:08:53 -080090 self.assertEqual(request.header.xid, response.header.xid,
91 'response xid != request xid')
92 self.assertEqual(len(response.data), 0, 'response data non-empty')
93
94class EchoWithDataTestCase(SimpleProtocolTestCase):
95 """
96 Test echo response with short string data
97 """
98 def runTest(self):
99 request = echo_request()
100 request.data = 'OpenFlow Will Rule The World'
Dan Talaycoe226eb12010-02-18 23:06:30 -0800101 response, pkt = self.controller.transact(request)
Dan Talaycodba244e2010-02-15 14:08:53 -0800102 self.assertEqual(response.header.type, OFPT_ECHO_REPLY,
Dan Talaycoa92e75b2010-02-16 20:53:56 -0800103 'response is not echo_reply')
Dan Talaycodba244e2010-02-15 14:08:53 -0800104 self.assertEqual(request.header.xid, response.header.xid,
105 'response xid != request xid')
106 self.assertEqual(request.data, response.data,
107 'response data does not match request')
108
109class PacketInTestCase(SimpleDataPlaneTestCase):
110 """
111 Test packet in function
112 """
113 def runTest(self):
114 # Construct packet to send to dataplane
Dan Talaycoe226eb12010-02-18 23:06:30 -0800115 # Send packet to dataplane, once to each port
Dan Talaycodba244e2010-02-15 14:08:53 -0800116 # Poll controller with expect message type packet in
117 # For now, a random packet from scapy tutorial
Dan Talaycoe226eb12010-02-18 23:06:30 -0800118
Dan Talaycodba244e2010-02-15 14:08:53 -0800119 for of_port in interface_ofport_map.keys():
Dan Talaycoe226eb12010-02-18 23:06:30 -0800120 self.dbg(DEBUG_INFO, "PKT IN test, port " + str(of_port))
121 pkt=Ether()/IP(dst="www.slashdot.org")/TCP()/\
122 ("GET /index.html HTTP/1.0. port" + str(of_port))
Dan Talaycodba244e2010-02-15 14:08:53 -0800123 self.dataplane.send(of_port, str(pkt))
Dan Talaycoe226eb12010-02-18 23:06:30 -0800124 #@todo Check for unexpected messages?
125 (response, raw) = self.controller.poll(OFPT_PACKET_IN, 2)
Dan Talaycodba244e2010-02-15 14:08:53 -0800126
Dan Talaycoe226eb12010-02-18 23:06:30 -0800127 self.assertTrue(response is not None,
128 'Packet in message not received')
129 # Data has CRC on it, so take off last 4 bytes
130 self.assertEqual(str(pkt), response.data[:-4],
131 'Response packet does not match send packet')
Dan Talaycodba244e2010-02-15 14:08:53 -0800132
133class PacketOutTestCase(SimpleDataPlaneTestCase):
134 """
135 Test packet out function
136 """
137 def runTest(self):
138 # Construct packet to send to dataplane
139 # Send packet to dataplane
140 # Poll controller with expect message type packet in
141 # For now, a random packet from scapy tutorial
142
143 # These will get put into function
144 outpkt=Ether()/IP(dst="www.slashdot.org")/TCP()/\
145 "GET /index.html HTTP/1.0 \n\n"
146 msg = packet_out()
147 msg.data = str(outpkt)
148 act = action_output()
Dan Talayco710438c2010-02-18 15:16:07 -0800149 dp_port = act.port = interface_ofport_map.keys()[0]
Dan Talaycodba244e2010-02-15 14:08:53 -0800150 self.assertTrue(msg.actions.add(act), 'Could not add action to msg')
151
Dan Talayco710438c2010-02-18 15:16:07 -0800152 self.dbg(DEBUG_INFO, "pkt out to port " + str(dp_port))
153 rv = self.controller.message_send(msg)
154 self.assertTrue(rv == 0, "Error sending out message")
Dan Talaycodba244e2010-02-15 14:08:53 -0800155
Dan Talayco710438c2010-02-18 15:16:07 -0800156 time.sleep(1) # @todo Implement poll timeout for test cases
Dan Talaycoe226eb12010-02-18 23:06:30 -0800157 (of_port, pkt, pkt_time) = self.dataplane.poll()
Dan Talaycodba244e2010-02-15 14:08:53 -0800158
Dan Talayco710438c2010-02-18 15:16:07 -0800159 self.assertTrue(pkt is not None, 'Packet not received')
160 if of_port is not None:
161 self.assertEqual(of_port, dp_port, "Unexpected receive port")
Dan Talaycodba244e2010-02-15 14:08:53 -0800162 self.assertEqual(str(outpkt), str(pkt),
163 'Response packet does not match send packet')
164
165
166if __name__ == "__main__":
167 unittest.main()
Dan Talayco710438c2010-02-18 15:16:07 -0800168# suite = unittest.TestLoader().loadTestsFromTestCase(PacketOutTestCase)
169# unittest.TextTestRunner(verbosity=2).run(suite)