blob: 04a2f91a6d863e595a2614ec6c451e1cf83e7662 [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()
87 response = self.controller.transact(request)
88 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'
101 response = self.controller.transact(request)
102 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
115 # Send packet to dataplane
116 # Poll controller with expect message type packet in
117 # For now, a random packet from scapy tutorial
118 pkt=Ether()/IP(dst="www.slashdot.org")/TCP()/\
119 "GET /index.html HTTP/1.0 \n\n"
120 for of_port in interface_ofport_map.keys():
121 self.dataplane.send(of_port, str(pkt))
122 # For now, just send one packet
123 break
124
125 time.sleep(2) # @todo Implement poll timeout for test cases
126 #@todo Check for unexpected messages?
127 (response, raw) = self.controller.poll(OFPT_PACKET_IN)
128
Dan Talayco710438c2010-02-18 15:16:07 -0800129 self.assertTrue(response is not None, 'Packet in message not received')
Dan Talaycodba244e2010-02-15 14:08:53 -0800130 # Data has CRC on it, so take off last 4 bytes
131 self.assertEqual(str(pkt), response.data[:-4],
132 'Response packet does not match send packet')
133
134class PacketOutTestCase(SimpleDataPlaneTestCase):
135 """
136 Test packet out function
137 """
138 def runTest(self):
139 # Construct packet to send to dataplane
140 # Send packet to dataplane
141 # Poll controller with expect message type packet in
142 # For now, a random packet from scapy tutorial
143
144 # These will get put into function
145 outpkt=Ether()/IP(dst="www.slashdot.org")/TCP()/\
146 "GET /index.html HTTP/1.0 \n\n"
147 msg = packet_out()
148 msg.data = str(outpkt)
149 act = action_output()
Dan Talayco710438c2010-02-18 15:16:07 -0800150 dp_port = act.port = interface_ofport_map.keys()[0]
Dan Talaycodba244e2010-02-15 14:08:53 -0800151 self.assertTrue(msg.actions.add(act), 'Could not add action to msg')
152
Dan Talayco710438c2010-02-18 15:16:07 -0800153 self.dbg(DEBUG_INFO, "pkt out to port " + str(dp_port))
154 rv = self.controller.message_send(msg)
155 self.assertTrue(rv == 0, "Error sending out message")
Dan Talaycodba244e2010-02-15 14:08:53 -0800156
Dan Talayco710438c2010-02-18 15:16:07 -0800157 time.sleep(1) # @todo Implement poll timeout for test cases
Dan Talaycodba244e2010-02-15 14:08:53 -0800158 (of_port, pkt, pkt_time) = self.dataplane.packet_get()
Dan Talaycodba244e2010-02-15 14:08:53 -0800159
Dan Talayco710438c2010-02-18 15:16:07 -0800160 self.assertTrue(pkt is not None, 'Packet not received')
161 if of_port is not None:
162 self.assertEqual(of_port, dp_port, "Unexpected receive port")
Dan Talaycodba244e2010-02-15 14:08:53 -0800163 self.assertEqual(str(outpkt), str(pkt),
164 'Response packet does not match send packet')
165
166
167if __name__ == "__main__":
168 unittest.main()
Dan Talayco710438c2010-02-18 15:16:07 -0800169# suite = unittest.TestLoader().loadTestsFromTestCase(PacketOutTestCase)
170# unittest.TextTestRunner(verbosity=2).run(suite)