blob: c5cc5144c6d97e29941e0e64071c9b4ece23d0b3 [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
Shudong Zhoudc276ae2012-10-15 16:02:56 -070017"""
Rich Lane5252a512013-04-04 13:19:22 -070018Test the Nicira controller role extension
Shudong Zhoudc276ae2012-10-15 16:02:56 -070019"""
20import struct
Rich Lanecf5dbde2013-03-28 13:53:05 -070021import unittest
Shudong Zhoudc276ae2012-10-15 16:02:56 -070022import logging
23
Rich Lane2c232ca2013-03-28 16:53:09 -070024import oftest
Shudong Zhoudc276ae2012-10-15 16:02:56 -070025from oftest import config
26import oftest.controller as controller
Rich Laned7b0ffa2013-03-08 15:53:42 -080027import ofp
Shudong Zhoudc276ae2012-10-15 16:02:56 -070028import oftest.base_tests as base_tests
29
30from oftest.testutils import *
31
Rich Lanecb816fd2013-03-26 21:53:47 -070032NX_ROLE_OTHER = 0
33NX_ROLE_MASTER = 1
34NX_ROLE_SLAVE = 2
Shudong Zhoudc276ae2012-10-15 16:02:56 -070035
Rich Lanecf5dbde2013-03-28 13:53:05 -070036def set_role(test, role, con=None):
37 if con == None:
38 con = test.controller
Rich Lanef41eea62013-03-27 16:05:43 -070039 request = ofp.message.nicira_controller_role_request(role=role)
Rich Lanecf5dbde2013-03-28 13:53:05 -070040 response, _ = con.transact(request)
Rich Lanef41eea62013-03-27 16:05:43 -070041 test.assertTrue(isinstance(response, ofp.message.nicira_controller_role_reply), "Expected a role reply")
42 test.assertEquals(response.role, role)
43
Rich Lanecb816fd2013-03-26 21:53:47 -070044class AnyReply(base_tests.SimpleDataPlane):
Shudong Zhoudc276ae2012-10-15 16:02:56 -070045 """
Rich Lanecb816fd2013-03-26 21:53:47 -070046 Verify that a role request gets either a role reply or an error.
Shudong Zhoudc276ae2012-10-15 16:02:56 -070047
Rich Lanecb816fd2013-03-26 21:53:47 -070048 This test should pass on any switch, no matter whether it implements
49 the extension.
50 """
Shudong Zhoudc276ae2012-10-15 16:02:56 -070051 def runTest(self):
Rich Lane4b601452013-03-11 23:37:06 -070052 request = ofp.message.nicira_controller_role_request(role=NX_ROLE_MASTER)
Shudong Zhoudc276ae2012-10-15 16:02:56 -070053 response, pkt = self.controller.transact(request)
54 self.assertTrue(response is not None, "No reply to Nicira role request")
Rich Lanecb816fd2013-03-26 21:53:47 -070055 if isinstance(response, ofp.message.nicira_controller_role_reply):
56 logging.info("Role reply received")
57 logging.info(response.show())
58 self.assertEquals(response.role, NX_ROLE_MASTER)
Rich Lanee226f042013-10-21 06:22:03 -070059 elif isinstance(response, ofp.message.bad_request_error_msg):
Rich Lanecb816fd2013-03-26 21:53:47 -070060 logging.info("Error message received")
61 logging.info(response.show())
Rich Lanecb816fd2013-03-26 21:53:47 -070062 self.assertEquals(response.code, ofp.OFPBRC_BAD_VENDOR)
63 else:
64 raise AssertionError("Unexpected reply type")
Rich Lanef41eea62013-03-27 16:05:43 -070065
66@nonstandard
67class RolePermissions(base_tests.SimpleDataPlane):
68 """
69 Verify that a slave connection cannot modify switch state, but
70 a master or equal can.
71 """
72 def runTest(self):
73 self.features_reply, _ = self.controller.transact(ofp.message.features_request())
74 delete_all_flows(self.controller)
75 self.verify_permission(True)
76
77 set_role(self, NX_ROLE_MASTER)
78 self.verify_permission(True)
79
80 set_role(self, NX_ROLE_SLAVE)
81 self.verify_permission(False)
82
83 set_role(self, NX_ROLE_OTHER)
84 self.verify_permission(True)
85
86 def verify_permission(self, perm):
87 port = self.features_reply.ports[0]
88
89 self.controller.message_send(ofp.message.port_mod(port_no=port.port_no, hw_addr=port.hw_addr))
90 self.controller.message_send(ofp.message.packet_out(buffer_id=0xffffffff))
91 self.controller.message_send(ofp.message.flow_add(buffer_id=0xffffffff))
92 do_barrier(self.controller)
93
94 err_count = 0
95 while self.controller.packets:
96 msg = self.controller.packets.pop(0)[0]
Rich Lanee226f042013-10-21 06:22:03 -070097 if msg.type == ofp.OFPT_ERROR:
Rich Lanef41eea62013-03-27 16:05:43 -070098 self.assertEquals(msg.err_type, ofp.OFPET_BAD_REQUEST)
99 self.assertEquals(msg.code, ofp.OFPBRC_EPERM)
100 err_count += 1
101
102 if perm:
103 self.assertEquals(err_count, 0, "Expected no errors")
104 else:
105 self.assertEquals(err_count, 3, "Expected errors for each message")
Rich Lane13c91592013-03-27 17:03:56 -0700106
107@nonstandard
108class SlaveNoPacketIn(base_tests.SimpleDataPlane):
109 """
110 Verify that slave connections do not receive OFPT_PACKET_IN messages but other roles do.
111 """
112 def runTest(self):
113 delete_all_flows(self.controller)
Rich Lane4c504f32013-06-07 17:24:14 -0700114 ingress_port = config["port_map"].keys()[0]
115 pkt = str(simple_tcp_packet())
Rich Lane13c91592013-03-27 17:03:56 -0700116
117 set_role(self, NX_ROLE_MASTER)
Rich Lane4c504f32013-06-07 17:24:14 -0700118 self.dataplane.send(ingress_port, pkt)
119 verify_packet_in(self, pkt, ingress_port, ofp.OFPR_NO_MATCH)
Rich Lane13c91592013-03-27 17:03:56 -0700120
121 set_role(self, NX_ROLE_SLAVE)
Rich Lane4c504f32013-06-07 17:24:14 -0700122 self.dataplane.send(ingress_port, pkt)
123 verify_no_packet_in(self, pkt, ingress_port)
Rich Lane13c91592013-03-27 17:03:56 -0700124
125 set_role(self, NX_ROLE_OTHER)
Rich Lane4c504f32013-06-07 17:24:14 -0700126 self.dataplane.send(ingress_port, pkt)
127 verify_packet_in(self, pkt, ingress_port, ofp.OFPR_NO_MATCH)
Rich Lanecf5dbde2013-03-28 13:53:05 -0700128
129@nonstandard
130@disabled
131class RoleSwitch(unittest.TestCase):
132 """
133 Verify that when a connection becomes a master the existing master is
134 downgraded to slave.
135
136 Requires the switch to attempt to connect in parallel to ports 6633
137 and 6634 on the configured IP.
138 """
139
140 def setUp(self):
141 host = config["controller_host"]
142 self.controllers = [
143 controller.Controller(host=host,port=6633),
144 controller.Controller(host=host,port=6634)
145 ]
146
147 def runTest(self):
148 # Connect and handshake with both controllers
149 for con in self.controllers:
150 con.start()
151 if not con.connect():
152 raise AssertionError("failed to connect controller %s" % str(con))
153 reply, _ = con.transact(ofp.message.features_request())
154 self.assertTrue(isinstance(reply, ofp.message.features_reply))
155
156 # Initial role assignment, controller 0 is master
157 set_role(self, NX_ROLE_MASTER, con=self.controllers[0])
158 set_role(self, NX_ROLE_SLAVE, con=self.controllers[1])
159 self.verify_role(self.controllers[0], True)
160 self.verify_role(self.controllers[1], False)
161
162 # Controller 1 becomes master
163 set_role(self, NX_ROLE_MASTER, con=self.controllers[1])
164 self.verify_role(self.controllers[0], False)
165 self.verify_role(self.controllers[1], True)
166
167 # Controller 0 becomes master
168 set_role(self, NX_ROLE_MASTER, con=self.controllers[0])
169 self.verify_role(self.controllers[0], True)
170 self.verify_role(self.controllers[1], False)
171
172 # Controller 1 becomes equal
173 set_role(self, NX_ROLE_OTHER, con=self.controllers[1])
174 self.verify_role(self.controllers[0], True)
175 self.verify_role(self.controllers[1], True)
176
177 # Both controllers become slaves
178 set_role(self, NX_ROLE_SLAVE, con=self.controllers[0])
179 set_role(self, NX_ROLE_SLAVE, con=self.controllers[1])
180 self.verify_role(self.controllers[0], False)
181 self.verify_role(self.controllers[1], False)
182
183 def verify_role(self, con, master):
184 con.message_send(ofp.message.flow_add(buffer_id=0xffffffff))
185 do_barrier(con)
186
187 err_count = 0
188 while con.packets:
189 msg = con.packets.pop(0)[0]
Rich Lanee226f042013-10-21 06:22:03 -0700190 if msg.type == ofp.OFPT_ERROR:
Rich Lanecf5dbde2013-03-28 13:53:05 -0700191 self.assertEquals(msg.err_type, ofp.OFPET_BAD_REQUEST)
192 self.assertEquals(msg.code, ofp.OFPBRC_EPERM)
193 err_count += 1
194
195 if master:
196 self.assertEquals(err_count, 0, "Expected no errors")
197 else:
198 self.assertEquals(err_count, 1, "Expected errors for each message")
199
200 def tearDown(self):
201 for con in self.controllers:
202 con.shutdown()
Rich Lane2c232ca2013-03-28 16:53:09 -0700203
204@nonstandard
205@disabled
206class EqualAsyncMessages(unittest.TestCase):
207 """
208 Verify that 'equal' controllers all get async events.
209
210 Requires the switch to attempt to connect in parallel to ports 6633
211 and 6634 on the configured IP.
212 """
213
214 def setUp(self):
215 host = config["controller_host"]
216 self.controllers = [
217 controller.Controller(host=host,port=6633),
218 controller.Controller(host=host,port=6634)
219 ]
220 self.dataplane = oftest.dataplane_instance
221 self.dataplane.flush()
222
223 def runTest(self):
224 # Connect and handshake with both controllers
225 for con in self.controllers:
226 con.start()
227 if not con.connect():
228 raise AssertionError("failed to connect controller %s" % str(con))
229 reply, _ = con.transact(ofp.message.features_request())
230 self.assertTrue(isinstance(reply, ofp.message.features_reply))
231
232 delete_all_flows(self.controllers[0])
233 do_barrier(self.controllers[0])
234
235 pkt = str(simple_tcp_packet())
236 ingress_port = config["port_map"].keys()[0]
237 self.dataplane.send(ingress_port, pkt)
238
239 for con in self.controllers:
Rich Lane4c504f32013-06-07 17:24:14 -0700240 verify_packet_in(self, pkt, ingress_port, ofp.OFPR_NO_MATCH, controller=con)
Rich Lane2c232ca2013-03-28 16:53:09 -0700241
242 def tearDown(self):
243 for con in self.controllers:
244 con.shutdown()
245 con.join()
246 del self.controllers