blob: c52d9991b0fb57576751f78795fab332a6b072b2 [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
7from oftest import config
8import oftest.controller as controller
Rich Laned7b0ffa2013-03-08 15:53:42 -08009import ofp
Shudong Zhoudc276ae2012-10-15 16:02:56 -070010import oftest.base_tests as base_tests
11
12from oftest.testutils import *
13
Rich Lanecb816fd2013-03-26 21:53:47 -070014NX_ROLE_OTHER = 0
15NX_ROLE_MASTER = 1
16NX_ROLE_SLAVE = 2
Shudong Zhoudc276ae2012-10-15 16:02:56 -070017
Rich Lanecf5dbde2013-03-28 13:53:05 -070018def set_role(test, role, con=None):
19 if con == None:
20 con = test.controller
Rich Lanef41eea62013-03-27 16:05:43 -070021 request = ofp.message.nicira_controller_role_request(role=role)
Rich Lanecf5dbde2013-03-28 13:53:05 -070022 response, _ = con.transact(request)
Rich Lanef41eea62013-03-27 16:05:43 -070023 test.assertTrue(isinstance(response, ofp.message.nicira_controller_role_reply), "Expected a role reply")
24 test.assertEquals(response.role, role)
25
Rich Lanecb816fd2013-03-26 21:53:47 -070026class AnyReply(base_tests.SimpleDataPlane):
Shudong Zhoudc276ae2012-10-15 16:02:56 -070027 """
Rich Lanecb816fd2013-03-26 21:53:47 -070028 Verify that a role request gets either a role reply or an error.
Shudong Zhoudc276ae2012-10-15 16:02:56 -070029
Rich Lanecb816fd2013-03-26 21:53:47 -070030 This test should pass on any switch, no matter whether it implements
31 the extension.
32 """
Shudong Zhoudc276ae2012-10-15 16:02:56 -070033 def runTest(self):
Rich Lane4b601452013-03-11 23:37:06 -070034 request = ofp.message.nicira_controller_role_request(role=NX_ROLE_MASTER)
Shudong Zhoudc276ae2012-10-15 16:02:56 -070035 response, pkt = self.controller.transact(request)
36 self.assertTrue(response is not None, "No reply to Nicira role request")
Rich Lanecb816fd2013-03-26 21:53:47 -070037 if isinstance(response, ofp.message.nicira_controller_role_reply):
38 logging.info("Role reply received")
39 logging.info(response.show())
40 self.assertEquals(response.role, NX_ROLE_MASTER)
41 elif isinstance(response, ofp.message.error_msg):
42 logging.info("Error message received")
43 logging.info(response.show())
44 self.assertEquals(response.err_type, ofp.OFPET_BAD_REQUEST)
45 self.assertEquals(response.code, ofp.OFPBRC_BAD_VENDOR)
46 else:
47 raise AssertionError("Unexpected reply type")
Rich Lanef41eea62013-03-27 16:05:43 -070048
49@nonstandard
50class RolePermissions(base_tests.SimpleDataPlane):
51 """
52 Verify that a slave connection cannot modify switch state, but
53 a master or equal can.
54 """
55 def runTest(self):
56 self.features_reply, _ = self.controller.transact(ofp.message.features_request())
57 delete_all_flows(self.controller)
58 self.verify_permission(True)
59
60 set_role(self, NX_ROLE_MASTER)
61 self.verify_permission(True)
62
63 set_role(self, NX_ROLE_SLAVE)
64 self.verify_permission(False)
65
66 set_role(self, NX_ROLE_OTHER)
67 self.verify_permission(True)
68
69 def verify_permission(self, perm):
70 port = self.features_reply.ports[0]
71
72 self.controller.message_send(ofp.message.port_mod(port_no=port.port_no, hw_addr=port.hw_addr))
73 self.controller.message_send(ofp.message.packet_out(buffer_id=0xffffffff))
74 self.controller.message_send(ofp.message.flow_add(buffer_id=0xffffffff))
75 do_barrier(self.controller)
76
77 err_count = 0
78 while self.controller.packets:
79 msg = self.controller.packets.pop(0)[0]
80 if isinstance(msg, ofp.message.error_msg):
81 self.assertEquals(msg.err_type, ofp.OFPET_BAD_REQUEST)
82 self.assertEquals(msg.code, ofp.OFPBRC_EPERM)
83 err_count += 1
84
85 if perm:
86 self.assertEquals(err_count, 0, "Expected no errors")
87 else:
88 self.assertEquals(err_count, 3, "Expected errors for each message")
Rich Lane13c91592013-03-27 17:03:56 -070089
90@nonstandard
91class SlaveNoPacketIn(base_tests.SimpleDataPlane):
92 """
93 Verify that slave connections do not receive OFPT_PACKET_IN messages but other roles do.
94 """
95 def runTest(self):
96 delete_all_flows(self.controller)
97
98 set_role(self, NX_ROLE_MASTER)
99 self.verify_packetin(True)
100
101 set_role(self, NX_ROLE_SLAVE)
102 self.verify_packetin(False)
103
104 set_role(self, NX_ROLE_OTHER)
105 self.verify_packetin(True)
106
107 def verify_packetin(self, enabled):
108 ingress_port = config["port_map"].keys()[0]
109 self.dataplane.send(ingress_port, str(simple_tcp_packet()))
110
111 if enabled:
112 timeout = -1
113 else:
114 timeout = 0.5
115 msg, _ = self.controller.poll(exp_msg=ofp.OFPT_PACKET_IN, timeout=timeout)
116
117 if enabled:
118 self.assertTrue(msg != None, "Expected a packet-in message")
119 else:
120 self.assertTrue(msg == None, "Did not expect a packet-in message")
Rich Lanecf5dbde2013-03-28 13:53:05 -0700121
122@nonstandard
123@disabled
124class RoleSwitch(unittest.TestCase):
125 """
126 Verify that when a connection becomes a master the existing master is
127 downgraded to slave.
128
129 Requires the switch to attempt to connect in parallel to ports 6633
130 and 6634 on the configured IP.
131 """
132
133 def setUp(self):
134 host = config["controller_host"]
135 self.controllers = [
136 controller.Controller(host=host,port=6633),
137 controller.Controller(host=host,port=6634)
138 ]
139
140 def runTest(self):
141 # Connect and handshake with both controllers
142 for con in self.controllers:
143 con.start()
144 if not con.connect():
145 raise AssertionError("failed to connect controller %s" % str(con))
146 reply, _ = con.transact(ofp.message.features_request())
147 self.assertTrue(isinstance(reply, ofp.message.features_reply))
148
149 # Initial role assignment, controller 0 is master
150 set_role(self, NX_ROLE_MASTER, con=self.controllers[0])
151 set_role(self, NX_ROLE_SLAVE, con=self.controllers[1])
152 self.verify_role(self.controllers[0], True)
153 self.verify_role(self.controllers[1], False)
154
155 # Controller 1 becomes master
156 set_role(self, NX_ROLE_MASTER, con=self.controllers[1])
157 self.verify_role(self.controllers[0], False)
158 self.verify_role(self.controllers[1], True)
159
160 # Controller 0 becomes master
161 set_role(self, NX_ROLE_MASTER, con=self.controllers[0])
162 self.verify_role(self.controllers[0], True)
163 self.verify_role(self.controllers[1], False)
164
165 # Controller 1 becomes equal
166 set_role(self, NX_ROLE_OTHER, con=self.controllers[1])
167 self.verify_role(self.controllers[0], True)
168 self.verify_role(self.controllers[1], True)
169
170 # Both controllers become slaves
171 set_role(self, NX_ROLE_SLAVE, con=self.controllers[0])
172 set_role(self, NX_ROLE_SLAVE, con=self.controllers[1])
173 self.verify_role(self.controllers[0], False)
174 self.verify_role(self.controllers[1], False)
175
176 def verify_role(self, con, master):
177 con.message_send(ofp.message.flow_add(buffer_id=0xffffffff))
178 do_barrier(con)
179
180 err_count = 0
181 while con.packets:
182 msg = con.packets.pop(0)[0]
183 if isinstance(msg, ofp.message.error_msg):
184 self.assertEquals(msg.err_type, ofp.OFPET_BAD_REQUEST)
185 self.assertEquals(msg.code, ofp.OFPBRC_EPERM)
186 err_count += 1
187
188 if master:
189 self.assertEquals(err_count, 0, "Expected no errors")
190 else:
191 self.assertEquals(err_count, 1, "Expected errors for each message")
192
193 def tearDown(self):
194 for con in self.controllers:
195 con.shutdown()