blob: 584188b94f4018d5b1164878f88a825e4bab4e14 [file] [log] [blame]
Shudong Zhoudc276ae2012-10-15 16:02:56 -07001"""
2"""
3import struct
Rich Lanecf5dbde2013-03-28 13:53:05 -07004import unittest
Shudong Zhoudc276ae2012-10-15 16:02:56 -07005import logging
6
Rich Lane2c232ca2013-03-28 16:53:09 -07007import oftest
Shudong Zhoudc276ae2012-10-15 16:02:56 -07008from oftest import config
9import oftest.controller as controller
Rich Laned7b0ffa2013-03-08 15:53:42 -080010import ofp
Shudong Zhoudc276ae2012-10-15 16:02:56 -070011import oftest.base_tests as base_tests
12
13from oftest.testutils import *
14
Rich Lanecb816fd2013-03-26 21:53:47 -070015NX_ROLE_OTHER = 0
16NX_ROLE_MASTER = 1
17NX_ROLE_SLAVE = 2
Shudong Zhoudc276ae2012-10-15 16:02:56 -070018
Rich Lanecf5dbde2013-03-28 13:53:05 -070019def set_role(test, role, con=None):
20 if con == None:
21 con = test.controller
Rich Lanef41eea62013-03-27 16:05:43 -070022 request = ofp.message.nicira_controller_role_request(role=role)
Rich Lanecf5dbde2013-03-28 13:53:05 -070023 response, _ = con.transact(request)
Rich Lanef41eea62013-03-27 16:05:43 -070024 test.assertTrue(isinstance(response, ofp.message.nicira_controller_role_reply), "Expected a role reply")
25 test.assertEquals(response.role, role)
26
Rich Lanecb816fd2013-03-26 21:53:47 -070027class AnyReply(base_tests.SimpleDataPlane):
Shudong Zhoudc276ae2012-10-15 16:02:56 -070028 """
Rich Lanecb816fd2013-03-26 21:53:47 -070029 Verify that a role request gets either a role reply or an error.
Shudong Zhoudc276ae2012-10-15 16:02:56 -070030
Rich Lanecb816fd2013-03-26 21:53:47 -070031 This test should pass on any switch, no matter whether it implements
32 the extension.
33 """
Shudong Zhoudc276ae2012-10-15 16:02:56 -070034 def runTest(self):
Rich Lane4b601452013-03-11 23:37:06 -070035 request = ofp.message.nicira_controller_role_request(role=NX_ROLE_MASTER)
Shudong Zhoudc276ae2012-10-15 16:02:56 -070036 response, pkt = self.controller.transact(request)
37 self.assertTrue(response is not None, "No reply to Nicira role request")
Rich Lanecb816fd2013-03-26 21:53:47 -070038 if isinstance(response, ofp.message.nicira_controller_role_reply):
39 logging.info("Role reply received")
40 logging.info(response.show())
41 self.assertEquals(response.role, NX_ROLE_MASTER)
42 elif isinstance(response, ofp.message.error_msg):
43 logging.info("Error message received")
44 logging.info(response.show())
45 self.assertEquals(response.err_type, ofp.OFPET_BAD_REQUEST)
46 self.assertEquals(response.code, ofp.OFPBRC_BAD_VENDOR)
47 else:
48 raise AssertionError("Unexpected reply type")
Rich Lanef41eea62013-03-27 16:05:43 -070049
50@nonstandard
51class RolePermissions(base_tests.SimpleDataPlane):
52 """
53 Verify that a slave connection cannot modify switch state, but
54 a master or equal can.
55 """
56 def runTest(self):
57 self.features_reply, _ = self.controller.transact(ofp.message.features_request())
58 delete_all_flows(self.controller)
59 self.verify_permission(True)
60
61 set_role(self, NX_ROLE_MASTER)
62 self.verify_permission(True)
63
64 set_role(self, NX_ROLE_SLAVE)
65 self.verify_permission(False)
66
67 set_role(self, NX_ROLE_OTHER)
68 self.verify_permission(True)
69
70 def verify_permission(self, perm):
71 port = self.features_reply.ports[0]
72
73 self.controller.message_send(ofp.message.port_mod(port_no=port.port_no, hw_addr=port.hw_addr))
74 self.controller.message_send(ofp.message.packet_out(buffer_id=0xffffffff))
75 self.controller.message_send(ofp.message.flow_add(buffer_id=0xffffffff))
76 do_barrier(self.controller)
77
78 err_count = 0
79 while self.controller.packets:
80 msg = self.controller.packets.pop(0)[0]
81 if isinstance(msg, ofp.message.error_msg):
82 self.assertEquals(msg.err_type, ofp.OFPET_BAD_REQUEST)
83 self.assertEquals(msg.code, ofp.OFPBRC_EPERM)
84 err_count += 1
85
86 if perm:
87 self.assertEquals(err_count, 0, "Expected no errors")
88 else:
89 self.assertEquals(err_count, 3, "Expected errors for each message")
Rich Lane13c91592013-03-27 17:03:56 -070090
91@nonstandard
92class SlaveNoPacketIn(base_tests.SimpleDataPlane):
93 """
94 Verify that slave connections do not receive OFPT_PACKET_IN messages but other roles do.
95 """
96 def runTest(self):
97 delete_all_flows(self.controller)
98
99 set_role(self, NX_ROLE_MASTER)
100 self.verify_packetin(True)
101
102 set_role(self, NX_ROLE_SLAVE)
103 self.verify_packetin(False)
104
105 set_role(self, NX_ROLE_OTHER)
106 self.verify_packetin(True)
107
108 def verify_packetin(self, enabled):
109 ingress_port = config["port_map"].keys()[0]
110 self.dataplane.send(ingress_port, str(simple_tcp_packet()))
111
112 if enabled:
113 timeout = -1
114 else:
115 timeout = 0.5
116 msg, _ = self.controller.poll(exp_msg=ofp.OFPT_PACKET_IN, timeout=timeout)
117
118 if enabled:
119 self.assertTrue(msg != None, "Expected a packet-in message")
120 else:
121 self.assertTrue(msg == None, "Did not expect a packet-in message")
Rich Lanecf5dbde2013-03-28 13:53:05 -0700122
123@nonstandard
124@disabled
125class RoleSwitch(unittest.TestCase):
126 """
127 Verify that when a connection becomes a master the existing master is
128 downgraded to slave.
129
130 Requires the switch to attempt to connect in parallel to ports 6633
131 and 6634 on the configured IP.
132 """
133
134 def setUp(self):
135 host = config["controller_host"]
136 self.controllers = [
137 controller.Controller(host=host,port=6633),
138 controller.Controller(host=host,port=6634)
139 ]
140
141 def runTest(self):
142 # Connect and handshake with both controllers
143 for con in self.controllers:
144 con.start()
145 if not con.connect():
146 raise AssertionError("failed to connect controller %s" % str(con))
147 reply, _ = con.transact(ofp.message.features_request())
148 self.assertTrue(isinstance(reply, ofp.message.features_reply))
149
150 # Initial role assignment, controller 0 is master
151 set_role(self, NX_ROLE_MASTER, con=self.controllers[0])
152 set_role(self, NX_ROLE_SLAVE, con=self.controllers[1])
153 self.verify_role(self.controllers[0], True)
154 self.verify_role(self.controllers[1], False)
155
156 # Controller 1 becomes master
157 set_role(self, NX_ROLE_MASTER, con=self.controllers[1])
158 self.verify_role(self.controllers[0], False)
159 self.verify_role(self.controllers[1], True)
160
161 # Controller 0 becomes master
162 set_role(self, NX_ROLE_MASTER, con=self.controllers[0])
163 self.verify_role(self.controllers[0], True)
164 self.verify_role(self.controllers[1], False)
165
166 # Controller 1 becomes equal
167 set_role(self, NX_ROLE_OTHER, con=self.controllers[1])
168 self.verify_role(self.controllers[0], True)
169 self.verify_role(self.controllers[1], True)
170
171 # Both controllers become slaves
172 set_role(self, NX_ROLE_SLAVE, con=self.controllers[0])
173 set_role(self, NX_ROLE_SLAVE, con=self.controllers[1])
174 self.verify_role(self.controllers[0], False)
175 self.verify_role(self.controllers[1], False)
176
177 def verify_role(self, con, master):
178 con.message_send(ofp.message.flow_add(buffer_id=0xffffffff))
179 do_barrier(con)
180
181 err_count = 0
182 while con.packets:
183 msg = con.packets.pop(0)[0]
184 if isinstance(msg, ofp.message.error_msg):
185 self.assertEquals(msg.err_type, ofp.OFPET_BAD_REQUEST)
186 self.assertEquals(msg.code, ofp.OFPBRC_EPERM)
187 err_count += 1
188
189 if master:
190 self.assertEquals(err_count, 0, "Expected no errors")
191 else:
192 self.assertEquals(err_count, 1, "Expected errors for each message")
193
194 def tearDown(self):
195 for con in self.controllers:
196 con.shutdown()
Rich Lane2c232ca2013-03-28 16:53:09 -0700197
198@nonstandard
199@disabled
200class EqualAsyncMessages(unittest.TestCase):
201 """
202 Verify that 'equal' controllers all get async events.
203
204 Requires the switch to attempt to connect in parallel to ports 6633
205 and 6634 on the configured IP.
206 """
207
208 def setUp(self):
209 host = config["controller_host"]
210 self.controllers = [
211 controller.Controller(host=host,port=6633),
212 controller.Controller(host=host,port=6634)
213 ]
214 self.dataplane = oftest.dataplane_instance
215 self.dataplane.flush()
216
217 def runTest(self):
218 # Connect and handshake with both controllers
219 for con in self.controllers:
220 con.start()
221 if not con.connect():
222 raise AssertionError("failed to connect controller %s" % str(con))
223 reply, _ = con.transact(ofp.message.features_request())
224 self.assertTrue(isinstance(reply, ofp.message.features_reply))
225
226 delete_all_flows(self.controllers[0])
227 do_barrier(self.controllers[0])
228
229 pkt = str(simple_tcp_packet())
230 ingress_port = config["port_map"].keys()[0]
231 self.dataplane.send(ingress_port, pkt)
232
233 for con in self.controllers:
234 msg, _ = con.poll(ofp.OFPT_PACKET_IN)
235 self.assertTrue(msg != None)
236 self.assertEquals(msg.data, pkt)
237
238 def tearDown(self):
239 for con in self.controllers:
240 con.shutdown()
241 con.join()
242 del self.controllers