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