blob: 6b7d4bed36f38e3e2029757467dc9c7cb309e8e1 [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
Dan Talayco942f5302012-04-12 22:32:34 -070017"""
18Prototype test cases related to operation under load
19
20It is recommended that these definitions be kept in their own
21namespace as different groups of tests will likely define
22similar identifiers.
23
Rich Lane477f4812012-10-04 22:49:00 -070024The switch is actively attempting to contact the controller at the address
25indicated in config.
Dan Talayco942f5302012-04-12 22:32:34 -070026
27In general these test cases make some assumption about the external
28configuration of the switch under test. For now, the assumption is
29that the first two OF ports are connected by a loopback cable.
30"""
31
32import copy
Rich Laned9ef7c32012-12-31 11:00:30 -080033import random
Dan Talayco942f5302012-04-12 22:32:34 -070034import logging
Dan Talayco942f5302012-04-12 22:32:34 -070035import unittest
36
Rich Lane477f4812012-10-04 22:49:00 -070037from oftest import config
Dan Talayco942f5302012-04-12 22:32:34 -070038import oftest.controller as controller
Rich Laned7b0ffa2013-03-08 15:53:42 -080039import ofp
Dan Talayco942f5302012-04-12 22:32:34 -070040import oftest.dataplane as dataplane
Dan Talayco942f5302012-04-12 22:32:34 -070041import oftest.parse as parse
Rich Laneb90a1c42012-10-05 09:16:05 -070042import oftest.base_tests as base_tests
Dan Talayco942f5302012-04-12 22:32:34 -070043import time
44
Rich Laneda3b5ad2012-10-03 09:05:32 -070045from oftest.testutils import *
Dan Talayco942f5302012-04-12 22:32:34 -070046
Rich Lane0a4f6372013-01-02 14:40:22 -080047@nonstandard
Rich Laneb90a1c42012-10-05 09:16:05 -070048class LoadBarrier(base_tests.SimpleProtocol):
Dan Talayco942f5302012-04-12 22:32:34 -070049 """
50 Test barrier under load with loopback
51
52 This test assumes there is a pair of ports on the switch with
53 a loopback cable connected and that spanning tree is disabled.
54 A flow is installed to cause a storm of packet-in messages
55 when a packet is sent to the loopbacked interface. After causing
56 this storm, a barrier request is sent.
57
58 The test succeeds if the barrier response is received. Otherwise
59 the test fails.
60 """
Rich Laned1d9c282012-10-04 22:07:10 -070061
Dan Talayco942f5302012-04-12 22:32:34 -070062 def runTest(self):
63 # Set up flow to send from port 1 to port 2 and copy to CPU
64 # Test parameter gives LB port base (assumes consecutive)
Rich Lane2014f9b2012-10-05 15:29:40 -070065 lb_port = test_param_get('lb_port', default=1)
66 barrier_count = test_param_get('barrier_count',
Dan Talayco942f5302012-04-12 22:32:34 -070067 default=10)
68
69 # Set controller to filter packet ins
70 self.controller.filter_packet_in = True
71 self.controller.pkt_in_filter_limit = 10
72
73 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -070074 match = packet_to_flow_match(self, pkt)
Dan Talayco942f5302012-04-12 22:32:34 -070075 match.wildcards &= ~ofp.OFPFW_IN_PORT
76 match.in_port = lb_port
Rich Lane9d3cc6b2013-03-08 16:33:08 -080077 act = ofp.action.output()
Dan Talayco942f5302012-04-12 22:32:34 -070078 act.port = lb_port + 1
79
Rich Laneba3f0e22013-03-11 16:43:57 -070080 request = ofp.message.flow_add()
Dan Talayco942f5302012-04-12 22:32:34 -070081 request.match = match
82 request.hard_timeout = 2 * barrier_count
83
84 request.buffer_id = 0xffffffff
Rich Lanec495d9e2013-03-08 17:43:36 -080085 request.actions.append(act)
Dan Talayco942f5302012-04-12 22:32:34 -070086
Rich Lane9d3cc6b2013-03-08 16:33:08 -080087 act = ofp.action.output()
Dan Talayco942f5302012-04-12 22:32:34 -070088 act.port = ofp.OFPP_CONTROLLER
Rich Lanec495d9e2013-03-08 17:43:36 -080089 request.actions.append(act)
Dan Talayco942f5302012-04-12 22:32:34 -070090
Rich Lane5c3151c2013-01-03 17:15:41 -080091 self.controller.message_send(request)
Rich Lane3a261d52013-01-03 17:45:08 -080092 do_barrier(self.controller)
Dan Talayco942f5302012-04-12 22:32:34 -070093
94 # Create packet out and send to port lb_port + 1
Rich Lane28fa9272013-03-08 16:00:25 -080095 msg = ofp.message.packet_out()
Rich Laneafcf4672012-11-14 13:19:27 -080096 msg.in_port = lb_port
Dan Talayco942f5302012-04-12 22:32:34 -070097 msg.data = str(pkt)
Rich Laneea8c4722013-04-04 15:30:20 -070098 msg.buffer_id = 0xffffffff
Rich Lane9d3cc6b2013-03-08 16:33:08 -080099 act = ofp.action.output()
Dan Talayco942f5302012-04-12 22:32:34 -0700100 act.port = lb_port + 1
Rich Lanec495d9e2013-03-08 17:43:36 -0800101 msg.actions.append(act)
Rich Lane9a003812012-10-04 17:17:59 -0700102 logging.info("Sleeping before starting storm")
Dan Talayco942f5302012-04-12 22:32:34 -0700103 time.sleep(1) # Root causing issue with fast disconnects
Rich Lane9a003812012-10-04 17:17:59 -0700104 logging.info("Sending packet out to %d" % (lb_port + 1))
Rich Lane5c3151c2013-01-03 17:15:41 -0800105 self.controller.message_send(msg)
Dan Talayco942f5302012-04-12 22:32:34 -0700106
107 for idx in range(0, barrier_count):
Rich Lane3a261d52013-01-03 17:45:08 -0800108 do_barrier(self.controller)
Dan Talayco942f5302012-04-12 22:32:34 -0700109 # To do: Add some interesting functionality here
Rich Lane9a003812012-10-04 17:17:59 -0700110 logging.info("Barrier %d completed" % idx)
Dan Talayco942f5302012-04-12 22:32:34 -0700111
112 # Clear the flow table when done
Rich Lane9a003812012-10-04 17:17:59 -0700113 logging.debug("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -0800114 delete_all_flows(self.controller)
Dan Talaycod0832852012-10-10 09:49:53 -0700115
116class PacketInLoad(base_tests.SimpleDataPlane):
117 """
118 Generate lots of packet-in messages
119
120 Test packet-in function by sending lots of packets to the dataplane.
121 This test tracks the number of pkt-ins received but does not enforce
122 any requirements about the number received.
123 """
124 def runTest(self):
125 # Construct packet to send to dataplane
126 # Send packet to dataplane, once to each port
127 # Poll controller with expect message type packet in
128
Rich Lane32bf9482013-01-03 17:26:30 -0800129 delete_all_flows(self.controller)
Rich Lane3a261d52013-01-03 17:45:08 -0800130 do_barrier(self.controller)
Dan Talaycod0832852012-10-10 09:49:53 -0700131 out_count = 0
132 in_count = 0
133
134 of_ports = config["port_map"].keys()
135 for of_port in of_ports:
136 for pkt, pt in [
137 (simple_tcp_packet(), "simple TCP packet"),
138 (simple_tcp_packet(dl_vlan_enable=True,pktlen=108),
139 "simple tagged TCP packet"),
140 (simple_eth_packet(), "simple Ethernet packet"),
141 (simple_eth_packet(pktlen=40), "tiny Ethernet packet")]:
142
143 logging.info("PKT IN test with %s, port %s" % (pt, of_port))
144 for count in range(100):
145 out_count += 1
146 self.dataplane.send(of_port, str(pkt))
Dan Talaycod0832852012-10-10 09:49:53 -0700147 while True:
Ed Swierka9e12ab2013-01-16 07:35:25 -0800148 (response, raw) = self.controller.poll(ofp.OFPT_PACKET_IN)
Dan Talaycod0832852012-10-10 09:49:53 -0700149 if not response:
150 break
151 in_count += 1
152 logging.info("PacketInLoad Sent %d. Got %d." % (out_count, in_count))
153
154
155
156class PacketOutLoad(base_tests.SimpleDataPlane):
157 """
158 Generate lots of packet-out messages
159
160 Test packet-out function by sending lots of packet-out msgs
161 to the switch. This test tracks the number of packets received in
162 the dataplane, but does not enforce any requirements about the
163 number received.
164 """
165 def runTest(self):
166 # Construct packet to send to dataplane
167 # Send packet to dataplane
168 # Poll controller with expect message type packet in
169
Rich Lane32bf9482013-01-03 17:26:30 -0800170 delete_all_flows(self.controller)
Dan Talaycod0832852012-10-10 09:49:53 -0700171
172 # These will get put into function
173 of_ports = config["port_map"].keys()
174 of_ports.sort()
175 out_count = 0
176 in_count = 0
177 xid = 100
178 for dp_port in of_ports:
179 for outpkt, opt in [
180 (simple_tcp_packet(), "simple TCP packet"),
181 (simple_eth_packet(), "simple Ethernet packet"),
182 (simple_eth_packet(pktlen=40), "tiny Ethernet packet")]:
183
184 logging.info("PKT OUT test with %s, port %s" % (opt, dp_port))
Rich Lane28fa9272013-03-08 16:00:25 -0800185 msg = ofp.message.packet_out()
Rich Laneafcf4672012-11-14 13:19:27 -0800186 msg.in_port = ofp.OFPP_NONE
Dan Talaycod0832852012-10-10 09:49:53 -0700187 msg.data = str(outpkt)
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800188 act = ofp.action.output()
Dan Talaycod0832852012-10-10 09:49:53 -0700189 act.port = dp_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800190 msg.actions.append(act)
Rich Laneea8c4722013-04-04 15:30:20 -0700191 msg.buffer_id = 0xffffffff
Dan Talaycod0832852012-10-10 09:49:53 -0700192
193 logging.info("PacketOutLoad to: " + str(dp_port))
194 for count in range(100):
195 msg.xid = xid
196 xid += 1
Rich Lane5c3151c2013-01-03 17:15:41 -0800197 self.controller.message_send(msg)
Dan Talaycod0832852012-10-10 09:49:53 -0700198 out_count += 1
199
200 exp_pkt_arg = None
201 exp_port = None
Dan Talaycod0832852012-10-10 09:49:53 -0700202 while True:
Ed Swierka9e12ab2013-01-16 07:35:25 -0800203 (of_port, pkt, pkt_time) = self.dataplane.poll()
Dan Talaycod0832852012-10-10 09:49:53 -0700204 if pkt is None:
205 break
206 in_count += 1
207 logging.info("PacketOutLoad Sent %d. Got %d." % (out_count, in_count))
Ed Swierke6fca642012-11-30 12:00:54 -0800208
209class FlowModLoad(base_tests.SimpleProtocol):
210
211 def checkBarrier(self):
Rich Lane28fa9272013-03-08 16:00:25 -0800212 msg, pkt = self.controller.transact(ofp.message.barrier_request(), timeout=60)
Ed Swierke6fca642012-11-30 12:00:54 -0800213 self.assertNotEqual(msg, None, "Barrier failed")
214 while self.controller.packets:
215 msg = self.controller.packets.pop(0)[0]
Rich Lanef9f6b512013-03-11 22:35:28 -0700216 self.assertNotEqual(msg.type, ofp.OFPT_ERROR, "Error received")
Ed Swierke6fca642012-11-30 12:00:54 -0800217
218 def runTest(self):
Rich Lane28fa9272013-03-08 16:00:25 -0800219 msg, pkt = self.controller.transact(ofp.message.table_stats_request())
Rich Lane30ca70c2012-12-31 16:53:55 -0800220
221 # Some switches report an extremely high max_entries that would cause
222 # us to run out of memory attempting to create all the flow-mods.
Rich Lane5fd6faf2013-03-11 13:30:20 -0700223 num_flows = min(msg.entries[0].max_entries, 32678)
Rich Lane30ca70c2012-12-31 16:53:55 -0800224
225 logging.info("Creating %d flow-mods messages", num_flows)
Ed Swierke6fca642012-11-30 12:00:54 -0800226
227 requests = []
228 for i in range(num_flows):
Rich Lane0237baf2013-03-11 22:34:59 -0700229 match = ofp.match()
Ed Swierke6fca642012-11-30 12:00:54 -0800230 match.wildcards = ofp.OFPFW_ALL & ~ofp.OFPFW_DL_VLAN & ~ofp.OFPFW_DL_DST
Rich Laned0478ff2013-03-11 12:46:58 -0700231 match.vlan_vid = ofp.OFP_VLAN_NONE
232 match.eth_dst = [0, 1, 2, 3, i / 256, i % 256]
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800233 act = ofp.action.output()
Ed Swierke6fca642012-11-30 12:00:54 -0800234 act.port = ofp.OFPP_CONTROLLER
Rich Laneba3f0e22013-03-11 16:43:57 -0700235 request = ofp.message.flow_add()
Ed Swierke6fca642012-11-30 12:00:54 -0800236 request.buffer_id = 0xffffffff
237 request.priority = num_flows - i
238 request.out_port = ofp.OFPP_NONE
239 request.match = match
Rich Lanec495d9e2013-03-08 17:43:36 -0800240 request.actions.append(act)
Ed Swierke6fca642012-11-30 12:00:54 -0800241 requests.append(request)
242
Rich Lane82c35e82012-12-31 10:59:36 -0800243 for i in range(3):
Ed Swierke6fca642012-11-30 12:00:54 -0800244 logging.info("Iteration %d: delete all flows" % i)
Rich Lane32bf9482013-01-03 17:26:30 -0800245 delete_all_flows(self.controller)
Ed Swierke6fca642012-11-30 12:00:54 -0800246 self.checkBarrier()
247
248 logging.info("Iteration %d: add %s flows" % (i, num_flows))
Rich Laned9ef7c32012-12-31 11:00:30 -0800249 random.shuffle(requests)
Ed Swierke6fca642012-11-30 12:00:54 -0800250 for request in requests:
251 self.assertNotEqual(self.controller.message_send(request), -1,
252 "Error installing flow mod")
253 self.checkBarrier()
Rich Lane9c491602013-04-15 16:00:46 -0700254
255class FlowRemovedLoad(base_tests.SimpleDataPlane):
256 """
257 Generate lots of flow-removed messages
258
259 We keep track of the number of flow-removed messages we get but do not
260 assert on it. The goal of this test is just to make sure the controller
261 stays connected.
262 """
263
264 def checkBarrier(self):
265 msg, pkt = self.controller.transact(ofp.message.barrier_request(), timeout=60)
266 self.assertNotEqual(msg, None, "Barrier failed")
267 while self.controller.packets:
268 msg = self.controller.packets.pop(0)[0]
269 self.assertNotEqual(msg.type, ofp.OFPT_ERROR, "Error received")
270
271 def runTest(self):
272 delete_all_flows(self.controller)
273 self.checkBarrier()
274 msg, _ = self.controller.transact(ofp.message.table_stats_request())
275
276 # Some switches report an extremely high max_entries that would cause
277 # us to run out of memory attempting to create all the flow-mods.
278 num_flows = min(msg.entries[0].max_entries, 32678)
279
280 logging.info("Creating %d flow-mods messages", num_flows)
281
282 requests = []
283 for i in range(num_flows):
284 match = ofp.match()
285 match.wildcards = ofp.OFPFW_ALL & ~ofp.OFPFW_DL_VLAN & ~ofp.OFPFW_DL_DST
286 match.vlan_vid = ofp.OFP_VLAN_NONE
287 match.eth_dst = [0, 1, 2, 3, i / 256, i % 256]
288 act = ofp.action.output()
289 act.port = ofp.OFPP_CONTROLLER
290 request = ofp.message.flow_add()
291 request.buffer_id = 0xffffffff
292 request.priority = num_flows - i
293 request.out_port = ofp.OFPP_NONE
294 request.flags = ofp.OFPFF_SEND_FLOW_REM
295 request.match = match
296 request.actions.append(act)
297 requests.append(request)
298
299 logging.info("Adding %d flows", num_flows)
300 random.shuffle(requests)
301 for request in requests:
302 self.controller.message_send(request)
303 self.checkBarrier()
304
305 # Trigger a flood of flow-removed messages
Tony van der Peet80c5b202013-11-20 11:47:48 +1300306 delete_all_flows(self.controller, send_barrier=False)
Rich Lane9c491602013-04-15 16:00:46 -0700307
308 count = 0
309 while True:
310 (response, raw) = self.controller.poll(ofp.OFPT_FLOW_REMOVED)
311 if not response:
312 break
313 count += 1
314
315 # Make sure the switch is still connected
316 self.checkBarrier()
317
318 logging.info("FlowRemovedLoad got %d/%d flow_removed messages." % (count, num_flows))