blob: 13a97710816b6d27abda4490742963b9707739de [file] [log] [blame]
Ken Chiangd6f5f862012-09-28 15:40:33 -07001"""
2Connection test cases
3
4"""
5
6import time
Ken Chiangd6f5f862012-09-28 15:40:33 -07007import sys
8import logging
9
10import unittest
11import random
12
Rich Lane477f4812012-10-04 22:49:00 -070013from oftest import config
Ken Chiangd6f5f862012-09-28 15:40:33 -070014import oftest.controller as controller
Rich Laned7b0ffa2013-03-08 15:53:42 -080015import ofp
Ken Chiangd6f5f862012-09-28 15:40:33 -070016import oftest.dataplane as dataplane
Ken Chiangd6f5f862012-09-28 15:40:33 -070017
Rich Laneda3b5ad2012-10-03 09:05:32 -070018from oftest.testutils import *
Ken Chiangd6f5f862012-09-28 15:40:33 -070019
Rich Lane0a4f6372013-01-02 14:40:22 -080020@disabled
Ken Chiangd6f5f862012-09-28 15:40:33 -070021class BaseHandshake(unittest.TestCase):
22 """
23 Base handshake case to set up controller, but do not send hello.
24 """
25
Ken Chiangd6f5f862012-09-28 15:40:33 -070026 def controllerSetup(self, host, port):
Ken Chiangadc950f2012-10-05 13:50:03 -070027 con = controller.Controller(host=host,port=port)
Ken Chiangd6f5f862012-09-28 15:40:33 -070028
29 # clean_shutdown should be set to False to force quit app
30 self.clean_shutdown = True
31 # disable initial hello so hello is under control of test
Ken Chiangadc950f2012-10-05 13:50:03 -070032 con.initial_hello = False
Ken Chiangd6f5f862012-09-28 15:40:33 -070033
Ken Chiangadc950f2012-10-05 13:50:03 -070034 con.start()
35 self.controllers.append(con)
Ken Chiangd6f5f862012-09-28 15:40:33 -070036
37 def setUp(self):
Rich Lane9a003812012-10-04 17:17:59 -070038 logging.info("** START TEST CASE " + str(self))
Ken Chiangd6f5f862012-09-28 15:40:33 -070039
Ed Swierkcfdcbd32013-01-02 18:44:52 -080040 self.controllers = []
Ken Chiange875baf2012-10-09 15:24:40 -070041 self.default_timeout = test_param_get('default_timeout',
42 default=2)
Ken Chiangd6f5f862012-09-28 15:40:33 -070043
Ken Chiangd6f5f862012-09-28 15:40:33 -070044 def tearDown(self):
Rich Lane9a003812012-10-04 17:17:59 -070045 logging.info("** END TEST CASE " + str(self))
Ken Chiangadc950f2012-10-05 13:50:03 -070046 for con in self.controllers:
47 con.shutdown()
48 if self.clean_shutdown:
49 con.join()
Ken Chiangd6f5f862012-09-28 15:40:33 -070050
51 def runTest(self):
52 # do nothing in the base case
53 pass
54
55 def assertTrue(self, cond, msg):
56 if not cond:
Rich Lane9a003812012-10-04 17:17:59 -070057 logging.error("** FAILED ASSERTION: " + msg)
Ken Chiangd6f5f862012-09-28 15:40:33 -070058 unittest.TestCase.assertTrue(self, cond, msg)
59
Ken Chiangd6f5f862012-09-28 15:40:33 -070060class HandshakeNoHello(BaseHandshake):
Ken Chiang35a74372012-10-01 15:39:25 -070061 """
62 TCP connect to switch, but do not sent hello,
63 and wait for disconnect.
64 """
Ken Chiangd6f5f862012-09-28 15:40:33 -070065 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -070066 self.controllerSetup(config["controller_host"],
67 config["controller_port"])
Ken Chiangadc950f2012-10-05 13:50:03 -070068 self.controllers[0].connect(self.default_timeout)
Ken Chiangd6f5f862012-09-28 15:40:33 -070069
Rich Lane9a003812012-10-04 17:17:59 -070070 logging.info("TCP Connected " +
Ken Chiange875baf2012-10-09 15:24:40 -070071 str(self.controllers[0].switch_addr))
Rich Lane9a003812012-10-04 17:17:59 -070072 logging.info("Hello not sent, waiting for timeout")
Ken Chiangd6f5f862012-09-28 15:40:33 -070073
74 # wait for controller to die
Ken Chiangadc950f2012-10-05 13:50:03 -070075 self.assertTrue(self.controllers[0].wait_disconnected(timeout=10),
76 "Not notified of controller disconnect")
Ken Chiangd6f5f862012-09-28 15:40:33 -070077
78class HandshakeNoFeaturesRequest(BaseHandshake):
Ken Chiang35a74372012-10-01 15:39:25 -070079 """
80 TCP connect to switch, send hello, but do not send features request,
81 and wait for disconnect.
82 """
Ken Chiangd6f5f862012-09-28 15:40:33 -070083 def runTest(self):
Rich Lane477f4812012-10-04 22:49:00 -070084 self.controllerSetup(config["controller_host"],
85 config["controller_port"])
Ken Chiangadc950f2012-10-05 13:50:03 -070086 self.controllers[0].connect(self.default_timeout)
Ken Chiangd6f5f862012-09-28 15:40:33 -070087
Rich Lane9a003812012-10-04 17:17:59 -070088 logging.info("TCP Connected " +
Ken Chiange875baf2012-10-09 15:24:40 -070089 str(self.controllers[0].switch_addr))
Rich Lane9a003812012-10-04 17:17:59 -070090 logging.info("Sending hello")
Rich Lane28fa9272013-03-08 16:00:25 -080091 self.controllers[0].message_send(ofp.message.hello())
Ken Chiangd6f5f862012-09-28 15:40:33 -070092
Rich Lane9a003812012-10-04 17:17:59 -070093 logging.info("Features request not sent, waiting for timeout")
Ken Chiangd6f5f862012-09-28 15:40:33 -070094
95 # wait for controller to die
Ken Chiangadc950f2012-10-05 13:50:03 -070096 self.assertTrue(self.controllers[0].wait_disconnected(timeout=10),
97 "Not notified of controller disconnect")
Ken Chiangd6f5f862012-09-28 15:40:33 -070098
Rich Lane0a4f6372013-01-02 14:40:22 -080099@disabled
Ken Chiang9c93e672012-12-18 12:00:14 -0800100class CompleteHandshake(BaseHandshake):
Ken Chiang35a74372012-10-01 15:39:25 -0700101 """
Ken Chiang9c93e672012-12-18 12:00:14 -0800102 Set up multiple controllers and complete handshake, but otherwise do nothing.
Ken Chiang35a74372012-10-01 15:39:25 -0700103 """
Rich Laned1d9c282012-10-04 22:07:10 -0700104
Ken Chiang9c93e672012-12-18 12:00:14 -0800105 def buildControllerList(self):
106 # controller_list is a list of IP:port tuples
107 con_list = test_param_get('controller_list')
108 if con_list is not None:
109 self.controller_list = []
110 for controller in con_list:
111 ip,portstr = controller.split(':')
112 try:
113 port = int(portstr)
114 except:
115 self.assertTrue(0, "failure converting port " +
116 portstr + " to integer")
117 self.controller_list.append( (ip, int(port)) )
118 else:
119 self.controller_list = [(config["controller_host"],
120 config["controller_port"])]
Ken Chiang35a74372012-10-01 15:39:25 -0700121
Ken Chiang9c93e672012-12-18 12:00:14 -0800122 def __init__(self, keep_alive=True, cxn_cycles=5,
123 controller_timeout=-1, hello_timeout=5,
Dan Talayco7e454122013-04-12 08:22:42 -0700124 features_req_timeout=5, disconnected_timeout=3,
125 report_pkts=False):
Ken Chiang9c93e672012-12-18 12:00:14 -0800126 BaseHandshake.__init__(self)
127 self.buildControllerList()
128 self.keep_alive = keep_alive
129 self.cxn_cycles = test_param_get('cxn_cycles') \
130 or cxn_cycles
131 self.controller_timeout = test_param_get('controller_timeout') \
132 or controller_timeout
133 self.hello_timeout = test_param_get('hello_timeout') \
134 or hello_timeout
135 self.features_req_timeout = test_param_get('features_req_timeout') \
136 or features_req_timeout
137 self.disconnected_timeout = test_param_get('disconnected_timeout') \
138 or disconnected_timeout
Dan Talayco7e454122013-04-12 08:22:42 -0700139 self.report_pkts = report_pkts
Ken Chiang9c93e672012-12-18 12:00:14 -0800140
Dan Talayco7e454122013-04-12 08:22:42 -0700141 # These functions provide per-tick processing
142 def periodic_init(self, tick_time):
143 """
144 Assumes tick_time is in seconds, usually 1/10 of a sec
145 """
146 if not self.report_pkts:
147 return
148 self.start_time = time.time()
149 self.last_report = self.start_time
150 self.pkt_in_count = 0 # Total packet in count
151 self.periodic_pkt_in_count = 0 # Packet-ins this cycle
152
153 def periodic_tick(self, con):
154 """
155 Process one tick. Currently this just counts pkt-in msgs
156 """
157 if not self.report_pkts:
158 return
159 if con.cstate != 4:
160 return
161 if self.report_pkts:
162 # Gather packets from control cxn
163 current_time = time.time()
164 new_pkts = con.packet_in_count - self.pkt_in_count
165 self.pkt_in_count = con.packet_in_count
166 self.periodic_pkt_in_count += new_pkts
167 con.clear_queue()
168
169 # Report every second or so
170 if (current_time - self.last_report >= 1):
171 if self.periodic_pkt_in_count:
172 print "%7.2f: pkt/sec last period: %6d. Total %10d." % (
173 current_time - self.start_time,
174 self.periodic_pkt_in_count/(current_time - self.last_report),
175 self.pkt_in_count)
176 self.last_report = current_time
177 self.periodic_pkt_in_count = 0
178
179 def periodic_done(self):
180 if not self.report_pkts:
181 return
182 print "Received %d pkt-ins over %d seconds" % (
183 self.pkt_in_count, time.time() - self.start_time)
184
Ken Chiang9c93e672012-12-18 12:00:14 -0800185 def runTest(self):
186 for conspec in self.controller_list:
187 self.controllerSetup(conspec[0], conspec[1])
188 for i in range(len(self.controller_list)):
Ken Chiang77173992012-10-30 15:44:39 -0700189 self.controllers[i].cstate = 0
Ken Chiang9c93e672012-12-18 12:00:14 -0800190 self.controllers[i].keep_alive = self.keep_alive
Ken Chiang74be4722012-12-21 13:07:03 -0800191 self.controllers[i].saved_switch_addr = None
Ken Chiang77173992012-10-30 15:44:39 -0700192 tick = 0.1 # time period in seconds at which controllers are handled
Dan Talayco7e454122013-04-12 08:22:42 -0700193 self.periodic_init(tick)
Ken Chiang35a74372012-10-01 15:39:25 -0700194
Ken Chiang9c93e672012-12-18 12:00:14 -0800195 disconnected_count = 0
196 cycle = 0
Ken Chiangadc950f2012-10-05 13:50:03 -0700197 while True:
Ken Chiang9c93e672012-12-18 12:00:14 -0800198 states = []
Ken Chiangadc950f2012-10-05 13:50:03 -0700199 for con in self.controllers:
Ken Chiang77173992012-10-30 15:44:39 -0700200 condesc = con.host + ":" + str(con.port) + ": "
201 logging.debug("Checking " + condesc)
Ken Chiang35a74372012-10-01 15:39:25 -0700202
Ken Chiang74be4722012-12-21 13:07:03 -0800203 if con.switch_socket:
204 if con.switch_addr != con.saved_switch_addr:
205 con.saved_switch_addr = con.switch_addr
206 con.cstate = 0
207
Ken Chiang77173992012-10-30 15:44:39 -0700208 if con.cstate == 0:
209 logging.info(condesc + "Sending hello to " +
210 str(con.switch_addr))
Rich Lane28fa9272013-03-08 16:00:25 -0800211 con.message_send(ofp.message.hello())
Ken Chiang77173992012-10-30 15:44:39 -0700212 con.cstate = 1
213 con.count = 0
214 elif con.cstate == 1:
215 reply, pkt = con.poll(exp_msg=ofp.OFPT_HELLO,
216 timeout=0)
217 if reply is not None:
218 logging.info(condesc +
219 "Hello received from " +
220 str(con.switch_addr))
221 con.cstate = 2
222 else:
223 con.count = con.count + 1
224 # fall back to previous state on timeout
225 if con.count >= self.hello_timeout/tick:
226 logging.info(condesc +
227 "Timeout hello from " +
228 str(con.switch_addr))
229 con.cstate = 0
230 elif con.cstate == 2:
231 logging.info(condesc + "Sending features request to " +
232 str(con.switch_addr))
Rich Lane28fa9272013-03-08 16:00:25 -0800233 con.message_send(ofp.message.features_request())
Ken Chiang77173992012-10-30 15:44:39 -0700234 con.cstate = 3
235 con.count = 0
236 elif con.cstate == 3:
237 reply, pkt = con.poll(exp_msg=ofp.OFPT_FEATURES_REPLY,
238 timeout=0)
239 if reply is not None:
240 logging.info(condesc +
Dan Talayco7e454122013-04-12 08:22:42 -0700241 "Features reply received from " +
Ken Chiang77173992012-10-30 15:44:39 -0700242 str(con.switch_addr))
243 con.cstate = 4
244 con.count = 0
Ken Chiang9c93e672012-12-18 12:00:14 -0800245 cycle = cycle + 1
Ken Chiang74be4722012-12-21 13:07:03 -0800246 logging.info("Cycle " + str(cycle))
Ken Chiang77173992012-10-30 15:44:39 -0700247 else:
248 con.count = con.count + 1
249 # fall back to previous state on timeout
250 if con.count >= self.features_req_timeout/tick:
251 logging.info(condesc +
252 "Timeout features request from " +
253 str(con.switch_addr))
254 con.cstate = 2
255 elif con.cstate == 4:
256 if (self.controller_timeout < 0 or
257 con.count < self.controller_timeout/tick):
258 logging.debug(condesc +
259 "Maintaining connection to " +
260 str(con.switch_addr))
261 con.count = con.count + 1
262 else:
263 logging.info(condesc +
264 "Disconnecting from " +
265 str(con.switch_addr))
266 con.disconnect()
267 con.cstate = 0
268 else:
269 con.cstate = 0
Ken Chiang9c93e672012-12-18 12:00:14 -0800270
271 states.append(con.cstate)
Dan Talayco7e454122013-04-12 08:22:42 -0700272 self.periodic_tick(con)
Ken Chiang77173992012-10-30 15:44:39 -0700273
Ken Chiang9c93e672012-12-18 12:00:14 -0800274 logging.debug("Cycle " + str(cycle) +
275 ", states " + str(states) +
276 ", disconnected_count " + str(disconnected_count))
277 if 4 in states:
278 disconnected_count = 0
279 else:
280 disconnected_count = disconnected_count + 1
281 if cycle != 0:
282 self.assertTrue(disconnected_count < self.disconnected_timeout/tick,
283 "Timeout expired connecting to controller")
284 else:
285 # on first cycle, allow more time for initial connect
286 self.assertTrue(disconnected_count < 2*self.disconnected_timeout/tick,
287 "Timeout expired connecting to controller on init")
288
289 if cycle > self.cxn_cycles:
290 break
Ken Chiang77173992012-10-30 15:44:39 -0700291 time.sleep(tick)
Dan Talayco7e454122013-04-12 08:22:42 -0700292 self.periodic_done()
Ken Chiang9c93e672012-12-18 12:00:14 -0800293
Rich Lane0a4f6372013-01-02 14:40:22 -0800294@disabled
Ken Chiang9c93e672012-12-18 12:00:14 -0800295class HandshakeAndKeepalive(CompleteHandshake):
296 """
297 Complete handshake and respond to echo request, but otherwise do nothing.
298 Good for manual testing.
299 """
300
Ken Chiang9c93e672012-12-18 12:00:14 -0800301 def __init__(self):
302 CompleteHandshake.__init__(self, keep_alive=True)
303
Rich Lane0a4f6372013-01-02 14:40:22 -0800304@disabled
Dan Talayco7e454122013-04-12 08:22:42 -0700305class MonitorPacketIn(CompleteHandshake):
306 """
307 Complete handshake and respond to echo request. As packet-in messages
308 arrive, report the count and pkts/second
309 """
310
311 def __init__(self):
312 CompleteHandshake.__init__(self, keep_alive=True, report_pkts=True)
313
314@disabled
Ken Chiang9c93e672012-12-18 12:00:14 -0800315class HandshakeNoEcho(CompleteHandshake):
316 """
317 Complete handshake, but otherwise do nothing, and do not respond to echo.
318 """
319
Ken Chiang9c93e672012-12-18 12:00:14 -0800320 def __init__(self):
321 CompleteHandshake.__init__(self, keep_alive=False)
322
Rich Lane0a4f6372013-01-02 14:40:22 -0800323@disabled
Ken Chiang9c93e672012-12-18 12:00:14 -0800324class HandshakeAndDrop(CompleteHandshake):
325 """
326 Complete handshake, but otherwise do nothing, and drop connection after a while.
327 """
328
Ken Chiang9c93e672012-12-18 12:00:14 -0800329 def __init__(self):
330 CompleteHandshake.__init__(self, keep_alive=True, controller_timeout=10)
331