blob: 915ba9644f1557acbe2a743497ee901ea7add562 [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
Ken Chiangd6f5f862012-09-28 15:40:33 -070017"""
18Connection test cases
19
20"""
21
22import time
Ken Chiangd6f5f862012-09-28 15:40:33 -070023import sys
24import logging
25
26import unittest
27import random
28
Rich Lane477f4812012-10-04 22:49:00 -070029from oftest import config
Ken Chiangd6f5f862012-09-28 15:40:33 -070030import oftest.controller as controller
Rich Laned7b0ffa2013-03-08 15:53:42 -080031import ofp
Ken Chiangd6f5f862012-09-28 15:40:33 -070032import oftest.dataplane as dataplane
Ken Chiangd6f5f862012-09-28 15:40:33 -070033
Rich Laneda3b5ad2012-10-03 09:05:32 -070034from oftest.testutils import *
Ken Chiangd6f5f862012-09-28 15:40:33 -070035
Rich Lane0a4f6372013-01-02 14:40:22 -080036@disabled
Ken Chiangd6f5f862012-09-28 15:40:33 -070037class BaseHandshake(unittest.TestCase):
38 """
39 Base handshake case to set up controller, but do not send hello.
40 """
41
Ken Chiangd6f5f862012-09-28 15:40:33 -070042 def controllerSetup(self, host, port):
Ken Chiangadc950f2012-10-05 13:50:03 -070043 con = controller.Controller(host=host,port=port)
Ken Chiangd6f5f862012-09-28 15:40:33 -070044
45 # clean_shutdown should be set to False to force quit app
46 self.clean_shutdown = True
47 # disable initial hello so hello is under control of test
Ken Chiangadc950f2012-10-05 13:50:03 -070048 con.initial_hello = False
Ken Chiangd6f5f862012-09-28 15:40:33 -070049
Ken Chiangadc950f2012-10-05 13:50:03 -070050 con.start()
51 self.controllers.append(con)
Ken Chiangd6f5f862012-09-28 15:40:33 -070052
53 def setUp(self):
Rich Lane9a003812012-10-04 17:17:59 -070054 logging.info("** START TEST CASE " + str(self))
Ken Chiangd6f5f862012-09-28 15:40:33 -070055
Ed Swierkcfdcbd32013-01-02 18:44:52 -080056 self.controllers = []
Ken Chiange875baf2012-10-09 15:24:40 -070057 self.default_timeout = test_param_get('default_timeout',
58 default=2)
Ken Chiangd6f5f862012-09-28 15:40:33 -070059
Ken Chiangd6f5f862012-09-28 15:40:33 -070060 def tearDown(self):
Rich Lane9a003812012-10-04 17:17:59 -070061 logging.info("** END TEST CASE " + str(self))
Ken Chiangadc950f2012-10-05 13:50:03 -070062 for con in self.controllers:
63 con.shutdown()
64 if self.clean_shutdown:
65 con.join()
Ken Chiangd6f5f862012-09-28 15:40:33 -070066
67 def runTest(self):
68 # do nothing in the base case
69 pass
70
71 def assertTrue(self, cond, msg):
72 if not cond:
Rich Lane9a003812012-10-04 17:17:59 -070073 logging.error("** FAILED ASSERTION: " + msg)
Ken Chiangd6f5f862012-09-28 15:40:33 -070074 unittest.TestCase.assertTrue(self, cond, msg)
75
Ken Chiangd6f5f862012-09-28 15:40:33 -070076class HandshakeNoHello(BaseHandshake):
Ken Chiang35a74372012-10-01 15:39:25 -070077 """
78 TCP connect to switch, but do not sent hello,
79 and wait for disconnect.
80 """
Ken Chiangd6f5f862012-09-28 15:40:33 -070081 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -070082 self.controllerSetup(config["controller_host"],
83 config["controller_port"])
Ken Chiangadc950f2012-10-05 13:50:03 -070084 self.controllers[0].connect(self.default_timeout)
Ken Chiangd6f5f862012-09-28 15:40:33 -070085
Rich Lane9a003812012-10-04 17:17:59 -070086 logging.info("TCP Connected " +
Ken Chiange875baf2012-10-09 15:24:40 -070087 str(self.controllers[0].switch_addr))
Rich Lane9a003812012-10-04 17:17:59 -070088 logging.info("Hello not sent, waiting for timeout")
Ken Chiangd6f5f862012-09-28 15:40:33 -070089
90 # wait for controller to die
Ken Chiangadc950f2012-10-05 13:50:03 -070091 self.assertTrue(self.controllers[0].wait_disconnected(timeout=10),
92 "Not notified of controller disconnect")
Ken Chiangd6f5f862012-09-28 15:40:33 -070093
94class HandshakeNoFeaturesRequest(BaseHandshake):
Ken Chiang35a74372012-10-01 15:39:25 -070095 """
96 TCP connect to switch, send hello, but do not send features request,
97 and wait for disconnect.
98 """
Ken Chiangd6f5f862012-09-28 15:40:33 -070099 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -0700100 self.controllerSetup(config["controller_host"],
101 config["controller_port"])
Ken Chiangadc950f2012-10-05 13:50:03 -0700102 self.controllers[0].connect(self.default_timeout)
Ken Chiangd6f5f862012-09-28 15:40:33 -0700103
Rich Lane9a003812012-10-04 17:17:59 -0700104 logging.info("TCP Connected " +
Ken Chiange875baf2012-10-09 15:24:40 -0700105 str(self.controllers[0].switch_addr))
Rich Lane9a003812012-10-04 17:17:59 -0700106 logging.info("Sending hello")
Rich Lane28fa9272013-03-08 16:00:25 -0800107 self.controllers[0].message_send(ofp.message.hello())
Ken Chiangd6f5f862012-09-28 15:40:33 -0700108
Rich Lane9a003812012-10-04 17:17:59 -0700109 logging.info("Features request not sent, waiting for timeout")
Ken Chiangd6f5f862012-09-28 15:40:33 -0700110
111 # wait for controller to die
Ken Chiangadc950f2012-10-05 13:50:03 -0700112 self.assertTrue(self.controllers[0].wait_disconnected(timeout=10),
113 "Not notified of controller disconnect")
Ken Chiangd6f5f862012-09-28 15:40:33 -0700114
Rich Lane0a4f6372013-01-02 14:40:22 -0800115@disabled
Ken Chiang9c93e672012-12-18 12:00:14 -0800116class CompleteHandshake(BaseHandshake):
Ken Chiang35a74372012-10-01 15:39:25 -0700117 """
Ken Chiang9c93e672012-12-18 12:00:14 -0800118 Set up multiple controllers and complete handshake, but otherwise do nothing.
Ken Chiang35a74372012-10-01 15:39:25 -0700119 """
Rich Laned1d9c282012-10-04 22:07:10 -0700120
Ken Chiang9c93e672012-12-18 12:00:14 -0800121 def buildControllerList(self):
122 # controller_list is a list of IP:port tuples
123 con_list = test_param_get('controller_list')
124 if con_list is not None:
125 self.controller_list = []
126 for controller in con_list:
127 ip,portstr = controller.split(':')
128 try:
129 port = int(portstr)
130 except:
131 self.assertTrue(0, "failure converting port " +
132 portstr + " to integer")
133 self.controller_list.append( (ip, int(port)) )
134 else:
135 self.controller_list = [(config["controller_host"],
136 config["controller_port"])]
Ken Chiang35a74372012-10-01 15:39:25 -0700137
Ken Chiang9c93e672012-12-18 12:00:14 -0800138 def __init__(self, keep_alive=True, cxn_cycles=5,
139 controller_timeout=-1, hello_timeout=5,
Dan Talayco7e454122013-04-12 08:22:42 -0700140 features_req_timeout=5, disconnected_timeout=3,
141 report_pkts=False):
Ken Chiang9c93e672012-12-18 12:00:14 -0800142 BaseHandshake.__init__(self)
143 self.buildControllerList()
144 self.keep_alive = keep_alive
145 self.cxn_cycles = test_param_get('cxn_cycles') \
146 or cxn_cycles
147 self.controller_timeout = test_param_get('controller_timeout') \
148 or controller_timeout
149 self.hello_timeout = test_param_get('hello_timeout') \
150 or hello_timeout
151 self.features_req_timeout = test_param_get('features_req_timeout') \
152 or features_req_timeout
153 self.disconnected_timeout = test_param_get('disconnected_timeout') \
154 or disconnected_timeout
Dan Talayco7e454122013-04-12 08:22:42 -0700155 self.report_pkts = report_pkts
Ken Chiang9c93e672012-12-18 12:00:14 -0800156
Dan Talayco7e454122013-04-12 08:22:42 -0700157 # These functions provide per-tick processing
Dan Talayco7071cf12013-04-16 11:02:13 -0700158 def periodic_task_init(self, tick_time):
Dan Talayco7e454122013-04-12 08:22:42 -0700159 """
160 Assumes tick_time is in seconds, usually 1/10 of a sec
161 """
162 if not self.report_pkts:
163 return
164 self.start_time = time.time()
165 self.last_report = self.start_time
166 self.pkt_in_count = 0 # Total packet in count
167 self.periodic_pkt_in_count = 0 # Packet-ins this cycle
168
Dan Talayco7071cf12013-04-16 11:02:13 -0700169 def periodic_task_tick(self, con):
Dan Talayco7e454122013-04-12 08:22:42 -0700170 """
171 Process one tick. Currently this just counts pkt-in msgs
172 """
173 if not self.report_pkts:
174 return
175 if con.cstate != 4:
176 return
Dan Talayco7e454122013-04-12 08:22:42 -0700177
Dan Talayco7071cf12013-04-16 11:02:13 -0700178 # Gather packets from control cxn
179 current_time = time.time()
180 new_pkts = con.packet_in_count - self.pkt_in_count
181 self.pkt_in_count = con.packet_in_count
182 self.periodic_pkt_in_count += new_pkts
183 con.clear_queue()
Dan Talayco7e454122013-04-12 08:22:42 -0700184
Dan Talayco7071cf12013-04-16 11:02:13 -0700185 # Report every second or so
186 if (current_time - self.last_report >= 1):
187 if self.periodic_pkt_in_count:
188 print "%7.2f: pkt/sec last period: %6d. Total %10d." % (
189 current_time - self.start_time,
190 self.periodic_pkt_in_count/(current_time - self.last_report),
191 self.pkt_in_count)
192 self.last_report = current_time
193 self.periodic_pkt_in_count = 0
194
195 def periodic_task_done(self):
Dan Talayco7e454122013-04-12 08:22:42 -0700196 if not self.report_pkts:
197 return
198 print "Received %d pkt-ins over %d seconds" % (
199 self.pkt_in_count, time.time() - self.start_time)
200
Ken Chiang9c93e672012-12-18 12:00:14 -0800201 def runTest(self):
202 for conspec in self.controller_list:
203 self.controllerSetup(conspec[0], conspec[1])
204 for i in range(len(self.controller_list)):
Ken Chiang77173992012-10-30 15:44:39 -0700205 self.controllers[i].cstate = 0
Ken Chiang9c93e672012-12-18 12:00:14 -0800206 self.controllers[i].keep_alive = self.keep_alive
Ken Chiang74be4722012-12-21 13:07:03 -0800207 self.controllers[i].saved_switch_addr = None
Ken Chiang77173992012-10-30 15:44:39 -0700208 tick = 0.1 # time period in seconds at which controllers are handled
Dan Talayco7071cf12013-04-16 11:02:13 -0700209 self.periodic_task_init(tick)
Ken Chiang35a74372012-10-01 15:39:25 -0700210
Ken Chiang9c93e672012-12-18 12:00:14 -0800211 disconnected_count = 0
212 cycle = 0
Ken Chiangadc950f2012-10-05 13:50:03 -0700213 while True:
Ken Chiang9c93e672012-12-18 12:00:14 -0800214 states = []
Ken Chiangadc950f2012-10-05 13:50:03 -0700215 for con in self.controllers:
Ken Chiang77173992012-10-30 15:44:39 -0700216 condesc = con.host + ":" + str(con.port) + ": "
217 logging.debug("Checking " + condesc)
Ken Chiang35a74372012-10-01 15:39:25 -0700218
Ken Chiang74be4722012-12-21 13:07:03 -0800219 if con.switch_socket:
220 if con.switch_addr != con.saved_switch_addr:
221 con.saved_switch_addr = con.switch_addr
222 con.cstate = 0
223
Ken Chiang77173992012-10-30 15:44:39 -0700224 if con.cstate == 0:
225 logging.info(condesc + "Sending hello to " +
226 str(con.switch_addr))
Rich Lane28fa9272013-03-08 16:00:25 -0800227 con.message_send(ofp.message.hello())
Ken Chiang77173992012-10-30 15:44:39 -0700228 con.cstate = 1
229 con.count = 0
230 elif con.cstate == 1:
231 reply, pkt = con.poll(exp_msg=ofp.OFPT_HELLO,
232 timeout=0)
233 if reply is not None:
234 logging.info(condesc +
235 "Hello received from " +
236 str(con.switch_addr))
237 con.cstate = 2
238 else:
239 con.count = con.count + 1
240 # fall back to previous state on timeout
241 if con.count >= self.hello_timeout/tick:
242 logging.info(condesc +
243 "Timeout hello from " +
244 str(con.switch_addr))
245 con.cstate = 0
246 elif con.cstate == 2:
247 logging.info(condesc + "Sending features request to " +
248 str(con.switch_addr))
Rich Lane28fa9272013-03-08 16:00:25 -0800249 con.message_send(ofp.message.features_request())
Ken Chiang77173992012-10-30 15:44:39 -0700250 con.cstate = 3
251 con.count = 0
252 elif con.cstate == 3:
253 reply, pkt = con.poll(exp_msg=ofp.OFPT_FEATURES_REPLY,
254 timeout=0)
255 if reply is not None:
256 logging.info(condesc +
Dan Talayco7e454122013-04-12 08:22:42 -0700257 "Features reply received from " +
Ken Chiang77173992012-10-30 15:44:39 -0700258 str(con.switch_addr))
259 con.cstate = 4
260 con.count = 0
Ken Chiang9c93e672012-12-18 12:00:14 -0800261 cycle = cycle + 1
Ken Chiang74be4722012-12-21 13:07:03 -0800262 logging.info("Cycle " + str(cycle))
Ken Chiang77173992012-10-30 15:44:39 -0700263 else:
264 con.count = con.count + 1
265 # fall back to previous state on timeout
266 if con.count >= self.features_req_timeout/tick:
267 logging.info(condesc +
268 "Timeout features request from " +
269 str(con.switch_addr))
270 con.cstate = 2
271 elif con.cstate == 4:
272 if (self.controller_timeout < 0 or
273 con.count < self.controller_timeout/tick):
274 logging.debug(condesc +
275 "Maintaining connection to " +
276 str(con.switch_addr))
277 con.count = con.count + 1
278 else:
279 logging.info(condesc +
280 "Disconnecting from " +
281 str(con.switch_addr))
282 con.disconnect()
283 con.cstate = 0
284 else:
285 con.cstate = 0
Ken Chiang9c93e672012-12-18 12:00:14 -0800286
287 states.append(con.cstate)
Dan Talayco7071cf12013-04-16 11:02:13 -0700288 self.periodic_task_tick(con)
Ken Chiang77173992012-10-30 15:44:39 -0700289
Ken Chiang9c93e672012-12-18 12:00:14 -0800290 logging.debug("Cycle " + str(cycle) +
291 ", states " + str(states) +
292 ", disconnected_count " + str(disconnected_count))
293 if 4 in states:
294 disconnected_count = 0
295 else:
296 disconnected_count = disconnected_count + 1
297 if cycle != 0:
298 self.assertTrue(disconnected_count < self.disconnected_timeout/tick,
299 "Timeout expired connecting to controller")
300 else:
301 # on first cycle, allow more time for initial connect
302 self.assertTrue(disconnected_count < 2*self.disconnected_timeout/tick,
303 "Timeout expired connecting to controller on init")
304
305 if cycle > self.cxn_cycles:
306 break
Ken Chiang77173992012-10-30 15:44:39 -0700307 time.sleep(tick)
Dan Talayco7071cf12013-04-16 11:02:13 -0700308 self.periodic_task_done()
Ken Chiang9c93e672012-12-18 12:00:14 -0800309
Rich Lane0a4f6372013-01-02 14:40:22 -0800310@disabled
Ken Chiang9c93e672012-12-18 12:00:14 -0800311class HandshakeAndKeepalive(CompleteHandshake):
312 """
313 Complete handshake and respond to echo request, but otherwise do nothing.
314 Good for manual testing.
315 """
316
Ken Chiang9c93e672012-12-18 12:00:14 -0800317 def __init__(self):
318 CompleteHandshake.__init__(self, keep_alive=True)
319
Rich Lane0a4f6372013-01-02 14:40:22 -0800320@disabled
Dan Talayco7e454122013-04-12 08:22:42 -0700321class MonitorPacketIn(CompleteHandshake):
322 """
323 Complete handshake and respond to echo request. As packet-in messages
324 arrive, report the count and pkts/second
325 """
326
327 def __init__(self):
328 CompleteHandshake.__init__(self, keep_alive=True, report_pkts=True)
329
330@disabled
Ken Chiang9c93e672012-12-18 12:00:14 -0800331class HandshakeNoEcho(CompleteHandshake):
332 """
333 Complete handshake, but otherwise do nothing, and do not respond to echo.
334 """
335
Ken Chiang9c93e672012-12-18 12:00:14 -0800336 def __init__(self):
337 CompleteHandshake.__init__(self, keep_alive=False)
338
Rich Lane0a4f6372013-01-02 14:40:22 -0800339@disabled
Ken Chiang9c93e672012-12-18 12:00:14 -0800340class HandshakeAndDrop(CompleteHandshake):
341 """
342 Complete handshake, but otherwise do nothing, and drop connection after a while.
343 """
344
Ken Chiang9c93e672012-12-18 12:00:14 -0800345 def __init__(self):
346 CompleteHandshake.__init__(self, keep_alive=True, controller_timeout=10)
347