blob: f265bcab6458270157328f49a739c36a9f77ccf6 [file] [log] [blame]
Rich Lane21356d72013-11-12 16:27:39 -08001"""
2Test the role request message
3"""
4import struct
5import unittest
6import logging
7
8import oftest
9from oftest import config
10import oftest.controller as controller
11import ofp
12import oftest.base_tests as base_tests
13
14from oftest.testutils import *
15
16def add_mod64(a, b):
17 return (a + b) & (2**64-1)
18
19def simple_role_request(test, role, gen=None, con=None):
20 """
21 Send a role request we expect to succeed
22 """
23 if con == None:
24 con = test.controller
25 request = ofp.message.role_request(role=role, generation_id=gen)
26 response, _ = con.transact(request)
27 test.assertTrue(isinstance(response, ofp.message.role_reply), "Expected a role reply")
28 if role != ofp.OFPCR_ROLE_NOCHANGE:
29 test.assertEquals(response.role, role)
30 if gen != None:
31 test.assertEquals(response.generation_id, gen)
32 return response.role, response.generation_id
33
34def failed_role_request(test, role, gen, code, con=None):
35 """
36 Send a role request we expect to fail
37 """
38 if con == None:
39 con = test.controller
40 request = ofp.message.role_request(role=role, generation_id=gen)
41 response, _ = con.transact(request)
42 test.assertIsInstance(response, ofp.message.role_request_failed_error_msg)
43 test.assertEqual(response.code, code)
44
45class RoleRequestNochange(base_tests.SimpleDataPlane):
46 """
47 Verify that we can query the switch for our current role and generation ID
48
49 The role should default to OFPCR_ROLE_EQUAL.
50 """
51 def runTest(self):
52 role, gen = simple_role_request(self, ofp.OFPCR_ROLE_NOCHANGE)
53 self.assertEqual(role, ofp.OFPCR_ROLE_EQUAL)
54
55 # Make sure the generation ID is still the same
56 role, new_gen = simple_role_request(self, ofp.OFPCR_ROLE_NOCHANGE)
57 self.assertEqual(role, ofp.OFPCR_ROLE_EQUAL)
58 self.assertEqual(new_gen, gen)
59
60class RoleRequestEqualToSlave(base_tests.SimpleDataPlane):
61 """
62 Transition between equal and slave roles and back
63 """
64 def runTest(self):
65 role, gen0 = simple_role_request(self, ofp.OFPCR_ROLE_NOCHANGE)
66 self.assertEqual(role, ofp.OFPCR_ROLE_EQUAL)
67
68 # Unchanged generation ID
69 role, gen1 = simple_role_request(self, ofp.OFPCR_ROLE_SLAVE, gen0)
70
71 # Back to equal
72 simple_role_request(self, ofp.OFPCR_ROLE_EQUAL)
73
74 # Smallest greater generation ID
75 role, gen2 = simple_role_request(self, ofp.OFPCR_ROLE_SLAVE, add_mod64(gen1, 1))
76
77 # Back to equal
78 simple_role_request(self, ofp.OFPCR_ROLE_EQUAL)
79
80 # Largest greater generation ID
81 role, gen3 = simple_role_request(self, ofp.OFPCR_ROLE_SLAVE,
82 add_mod64(gen2, 2**63-1))
83
84 # Back to equal
85 simple_role_request(self, ofp.OFPCR_ROLE_EQUAL)
86
87 # Send least stale generation ID
88 failed_role_request(self, ofp.OFPCR_ROLE_SLAVE,
89 add_mod64(gen3, -1),
90 ofp.OFPRRFC_STALE)
91
92 # Check that our role is unchanged
93 role, gen = simple_role_request(self, ofp.OFPCR_ROLE_NOCHANGE)
94 self.assertEqual(role, ofp.OFPCR_ROLE_EQUAL)
95 self.assertEqual(gen, gen3)
96
97 # Send most stale generation ID
98 failed_role_request(self, ofp.OFPCR_ROLE_SLAVE,
99 add_mod64(gen3, -(2**63)),
100 ofp.OFPRRFC_STALE)
101
102 # Check that our role is unchanged
103 role, gen = simple_role_request(self, ofp.OFPCR_ROLE_NOCHANGE)
104 self.assertEqual(role, ofp.OFPCR_ROLE_EQUAL)
105 self.assertEqual(gen, gen3)
106
107class RoleRequestEqualToMaster(base_tests.SimpleDataPlane):
108 """
109 Transition between equal and master roles and back
110 """
111 def runTest(self):
112 role, gen0 = simple_role_request(self, ofp.OFPCR_ROLE_NOCHANGE)
113 self.assertEqual(role, ofp.OFPCR_ROLE_EQUAL)
114
115 # Unchanged generation ID
116 role, gen1 = simple_role_request(self, ofp.OFPCR_ROLE_MASTER, gen0)
117
118 # Back to equal
119 simple_role_request(self, ofp.OFPCR_ROLE_EQUAL)
120
121 # Smallest greater generation ID
122 role, gen2 = simple_role_request(self, ofp.OFPCR_ROLE_MASTER, add_mod64(gen1, 1))
123
124 # Back to equal
125 simple_role_request(self, ofp.OFPCR_ROLE_EQUAL)
126
127 # Largest greater generation ID
128 role, gen3 = simple_role_request(self, ofp.OFPCR_ROLE_MASTER,
129 add_mod64(gen2, 2**63-1))
130
131 # Back to equal
132 simple_role_request(self, ofp.OFPCR_ROLE_EQUAL)
133
134 # Send least stale generation ID
135 failed_role_request(self, ofp.OFPCR_ROLE_MASTER,
136 add_mod64(gen3, -1),
137 ofp.OFPRRFC_STALE)
138
139 # Check that our role is unchanged
140 role, gen = simple_role_request(self, ofp.OFPCR_ROLE_NOCHANGE)
141 self.assertEqual(role, ofp.OFPCR_ROLE_EQUAL)
142 self.assertEqual(gen, gen3)
143
144 # Send most stale generation ID
145 failed_role_request(self, ofp.OFPCR_ROLE_MASTER,
146 add_mod64(gen3, -(2**63)),
147 ofp.OFPRRFC_STALE)
148
149 # Check that our role is unchanged
150 role, gen = simple_role_request(self, ofp.OFPCR_ROLE_NOCHANGE)
151 self.assertEqual(role, ofp.OFPCR_ROLE_EQUAL)
152 self.assertEqual(gen, gen3)
153
154class RoleRequestSlaveToMaster(base_tests.SimpleDataPlane):
155 """
156 Transition between slave and master roles and back
157 """
158 def runTest(self):
159 role, gen0 = simple_role_request(self, ofp.OFPCR_ROLE_NOCHANGE)
160 self.assertEqual(role, ofp.OFPCR_ROLE_EQUAL)
161
162 # Initial transition to slave
163 role, gen1 = simple_role_request(self, ofp.OFPCR_ROLE_SLAVE, gen0)
164
165 # Unchanged generation ID
166 role, gen2 = simple_role_request(self, ofp.OFPCR_ROLE_MASTER, gen1)
167
168 # Back to slave
169 simple_role_request(self, ofp.OFPCR_ROLE_SLAVE, gen2)
170
171 # Smallest greater generation ID
172 role, gen3 = simple_role_request(self, ofp.OFPCR_ROLE_MASTER,
173 add_mod64(gen2, 1))
174
175 # Back to slave
176 simple_role_request(self, ofp.OFPCR_ROLE_SLAVE, gen3)
177
178 # Largest greater generation ID
179 role, gen4 = simple_role_request(self, ofp.OFPCR_ROLE_MASTER,
180 add_mod64(gen3, 2**63-1))
181
182 # Back to slave
183 simple_role_request(self, ofp.OFPCR_ROLE_SLAVE, gen4)
184
185 # Send least stale generation ID
186 failed_role_request(self, ofp.OFPCR_ROLE_MASTER,
187 add_mod64(gen4, -1),
188 ofp.OFPRRFC_STALE)
189
190 # Check that our role is unchanged
191 role, gen = simple_role_request(self, ofp.OFPCR_ROLE_NOCHANGE)
192 self.assertEqual(role, ofp.OFPCR_ROLE_SLAVE)
193 self.assertEqual(gen, gen4)
194
195 # Send most stale generation ID
196 failed_role_request(self, ofp.OFPCR_ROLE_MASTER,
197 add_mod64(gen4, -(2**63)),
198 ofp.OFPRRFC_STALE)
199
200 # Check that our role is unchanged
201 role, gen = simple_role_request(self, ofp.OFPCR_ROLE_NOCHANGE)
202 self.assertEqual(role, ofp.OFPCR_ROLE_SLAVE)
203 self.assertEqual(gen, gen4)
204
205class RolePermissions(base_tests.SimpleDataPlane):
206 """
207 Verify that a slave connection cannot modify switch state, but
208 a master or equal can.
209 """
210 def runTest(self):
211 delete_all_flows(self.controller)
212 self.verify_permission(True)
213
214 role, gen = simple_role_request(self, ofp.OFPCR_ROLE_NOCHANGE)
215
216 simple_role_request(self, ofp.OFPCR_ROLE_MASTER, gen)
217 self.verify_permission(True)
218
219 simple_role_request(self, ofp.OFPCR_ROLE_SLAVE, gen)
220 self.verify_permission(False)
221
222 simple_role_request(self, ofp.OFPCR_ROLE_EQUAL)
223 self.verify_permission(True)
224
225 def verify_permission(self, perm):
226 self.controller.message_send(
227 ofp.message.packet_out(buffer_id=ofp.OFP_NO_BUFFER))
228
229 self.controller.message_send(
230 ofp.message.flow_delete(
231 buffer_id=ofp.OFP_NO_BUFFER,
232 out_port=ofp.OFPP_ANY,
233 out_group=ofp.OFPG_ANY))
234
235 self.controller.message_send(
236 ofp.message.group_mod(
237 command=ofp.OFPGC_DELETE,
238 group_id=ofp.OFPG_ALL))
239
240 # TODO OFPT_PORT_MOD
241 # TODO OFPT_TABLE_MOD
242
243 do_barrier(self.controller)
244
245 err_count = 0
246 while self.controller.packets:
247 msg = self.controller.packets.pop(0)[0]
248 if msg.type == ofp.OFPT_ERROR:
249 self.assertEquals(msg.err_type, ofp.OFPET_BAD_REQUEST)
250 self.assertEquals(msg.code, ofp.OFPBRC_IS_SLAVE)
251 err_count += 1
252
253 if perm:
254 self.assertEquals(err_count, 0, "Expected no errors")
255 else:
256 self.assertEquals(err_count, 3, "Expected errors for each message")
257
258class SlaveNoPacketIn(base_tests.SimpleDataPlane):
259 """
260 Verify that slave connections do not receive OFPT_PACKET_IN messages but other roles do.
261 """
262 def runTest(self):
263 delete_all_flows(self.controller)
264 ingress_port, = openflow_ports(1)
265 pkt = str(simple_tcp_packet())
266
267 logging.info("Inserting table-miss flow sending all packets to controller")
268 request = ofp.message.flow_add(
269 table_id=test_param_get("table", 0),
270 instructions=[
271 ofp.instruction.apply_actions(
272 actions=[
273 ofp.action.output(
274 port=ofp.OFPP_CONTROLLER,
275 max_len=ofp.OFPCML_NO_BUFFER)])],
276 buffer_id=ofp.OFP_NO_BUFFER,
277 priority=0)
278 self.controller.message_send(request)
279 do_barrier(self.controller)
280
281 _, gen = simple_role_request(self, ofp.OFPCR_ROLE_NOCHANGE)
282
283 simple_role_request(self, ofp.OFPCR_ROLE_MASTER, gen)
284 self.dataplane.send(ingress_port, pkt)
285 verify_packet_in(self, pkt, ingress_port, ofp.OFPR_NO_MATCH)
286
287 simple_role_request(self, ofp.OFPCR_ROLE_SLAVE, gen)
288 self.dataplane.send(ingress_port, pkt)
289 verify_no_packet_in(self, pkt, ingress_port)
290
291 simple_role_request(self, ofp.OFPCR_ROLE_EQUAL, gen)
292 self.dataplane.send(ingress_port, pkt)
293 verify_packet_in(self, pkt, ingress_port, ofp.OFPR_NO_MATCH)
294
295@disabled
296class RoleSwitch(unittest.TestCase):
297 """
298 Verify that when a connection becomes a master the existing master is
299 downgraded to slave.
300
301 Requires the switch to attempt to connect in parallel to ports 6653
302 and 6753 on the configured IP.
303 """
304
305 def setUp(self):
306 host = config["controller_host"]
307 self.controllers = [
308 controller.Controller(host=host,port=6653),
309 controller.Controller(host=host,port=6753)
310 ]
311
312 def runTest(self):
313 # Connect and handshake with both controllers
314 for con in self.controllers:
315 con.start()
316 if not con.connect():
317 raise AssertionError("failed to connect controller %s" % str(con))
318 reply, _ = con.transact(ofp.message.features_request())
319 self.assertTrue(isinstance(reply, ofp.message.features_reply))
320
321 # Assert initial role and get generation IDs
322 role, gen0 = simple_role_request(self, ofp.OFPCR_ROLE_NOCHANGE, con=self.controllers[0])
323 self.assertEqual(role, ofp.OFPCR_ROLE_EQUAL)
324 role, gen1 = simple_role_request(self, ofp.OFPCR_ROLE_NOCHANGE, con=self.controllers[1])
325 self.assertEqual(role, ofp.OFPCR_ROLE_EQUAL)
326
327 # Initial role assignment: controller 0 is master, controller 1 is slave
328 simple_role_request(self, ofp.OFPCR_ROLE_MASTER, gen0, con=self.controllers[0])
329 simple_role_request(self, ofp.OFPCR_ROLE_SLAVE, gen1, con=self.controllers[1])
330 self.verify_role(self.controllers[0], ofp.OFPCR_ROLE_MASTER)
331 self.verify_role(self.controllers[1], ofp.OFPCR_ROLE_SLAVE)
332
333 # Controller 1 requests master
334 # Controller 0 becomes slave
335 simple_role_request(self, ofp.OFPCR_ROLE_MASTER, gen1, con=self.controllers[1])
336 self.verify_role(self.controllers[0], ofp.OFPCR_ROLE_SLAVE)
337 self.verify_role(self.controllers[1], ofp.OFPCR_ROLE_MASTER)
338
339 # Controller 0 requests master
340 # Controller 1 becomes slave
341 simple_role_request(self, ofp.OFPCR_ROLE_MASTER, gen0, con=self.controllers[0])
342 self.verify_role(self.controllers[0], ofp.OFPCR_ROLE_MASTER)
343 self.verify_role(self.controllers[1], ofp.OFPCR_ROLE_SLAVE)
344
345 # Controller 1 requests equal
346 # Controller 0 remains master
347 simple_role_request(self, ofp.OFPCR_ROLE_EQUAL, gen1, con=self.controllers[1])
348 self.verify_role(self.controllers[0], ofp.OFPCR_ROLE_MASTER)
349 self.verify_role(self.controllers[1], ofp.OFPCR_ROLE_EQUAL)
350
351 # Both controllers request slave
352 simple_role_request(self, ofp.OFPCR_ROLE_SLAVE, gen0, con=self.controllers[0])
353 simple_role_request(self, ofp.OFPCR_ROLE_SLAVE, gen1, con=self.controllers[1])
354 self.verify_role(self.controllers[0], ofp.OFPCR_ROLE_SLAVE)
355 self.verify_role(self.controllers[1], ofp.OFPCR_ROLE_SLAVE)
356
357 def verify_role(self, con, role):
358 rcv_role, _ = simple_role_request(self, ofp.OFPCR_ROLE_NOCHANGE, con=con)
359 self.assertEqual(rcv_role, role)
360
361 def tearDown(self):
362 for con in self.controllers:
363 con.shutdown()