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