blob: d1e469c7611353b23f87357ae1812a8850f9d6ec [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
Rich Lane207599b2014-03-06 14:24:16 -080017# Distributed under the OpenFlow Software License (see LICENSE)
18# Copyright (c) 2014 Big Switch Networks, Inc.
19"""
20BSN flow checksum extension test cases
21"""
22
23import logging
24import math
25import random
26
27from oftest import config
28import oftest.base_tests as base_tests
29import ofp
30
31from oftest.testutils import *
32
33TABLE_ID = 0
34
35def make_checksum(hi, lo):
36 """
37 Place 'hi' in the upper 8 bits and 'lo' in the lower bits.
38 """
39 return ((hi & 0xff) << 56) | lo
40
41assert make_checksum(0xab, 0xcd) == 0xab000000000000cd
42
Rich Lanea7331722014-03-11 13:28:25 -070043def shuffled(seq):
44 l = list(seq)[:]
45 random.shuffle(l)
46 return l
47
Rich Lane4ef81fd2014-06-30 17:16:07 -070048def add_checksum(a, b):
49 return (a + b) % 2**64
50
51def subtract_checksum(a, b):
52 return (a - b) % 2**64
53
54def bucket_index(num_buckets, checksum):
55 """
56 Use the top bits of the checksum to select a bucket index
57 """
58 return checksum >> (64 - int(math.log(num_buckets, 2)))
59
60def add_bucket_checksum(buckets, checksum):
61 """
62 Add the checksum to the correct bucket
63 """
64 index = bucket_index(len(buckets), checksum)
65 buckets[index] = add_checksum(buckets[index], checksum)
66
67def subtract_bucket_checksum(buckets, checksum):
68 """
69 Subtract the checksum from the correct bucket
70 """
71 index = bucket_index(len(buckets), checksum)
72 buckets[index] = subtract_checksum(buckets[index], checksum)
73
Rich Lane207599b2014-03-06 14:24:16 -080074class FlowChecksumBase(base_tests.SimpleProtocol):
75 """
76 Base class that maintains the expected table and bucket checksums
77 """
78 checksum_buckets = None
79 table_checksum = None
80 all_checksums = []
81
82 def get_table_checksum(self):
83 for entry in get_stats(self, ofp.message.bsn_table_checksum_stats_request()):
84 if entry.table_id == TABLE_ID:
85 return entry.checksum
86 return None
87
88 def get_checksum_buckets(self):
89 stats = get_stats(self,
90 ofp.message.bsn_flow_checksum_bucket_stats_request(table_id=TABLE_ID))
91 return [x.checksum for x in stats]
92
93 def verify_checksums(self):
94 self.assertEquals(self.get_table_checksum(), self.table_checksum)
95 self.assertEquals(self.get_checksum_buckets(), self.checksum_buckets)
96
Rich Lane207599b2014-03-06 14:24:16 -080097 def insert_checksum(self, checksum):
Rich Lane4ef81fd2014-06-30 17:16:07 -070098 self.table_checksum = add_checksum(self.table_checksum, checksum)
99 add_bucket_checksum(self.checksum_buckets, checksum)
Rich Lane207599b2014-03-06 14:24:16 -0800100 self.all_checksums.append(checksum)
101
102 def remove_checksum(self, checksum):
Rich Lane4ef81fd2014-06-30 17:16:07 -0700103 self.table_checksum = subtract_checksum(self.table_checksum, checksum)
104 subtract_bucket_checksum(self.checksum_buckets, checksum)
Rich Lane207599b2014-03-06 14:24:16 -0800105 self.all_checksums.remove(checksum)
106
107 def set_buckets_size(self, buckets_size):
108 self.controller.message_send(
109 ofp.message.bsn_table_set_buckets_size(
110 table_id=TABLE_ID, buckets_size=buckets_size))
111 do_barrier(self.controller)
112 verify_no_errors(self.controller)
113
Rich Lane4ef81fd2014-06-30 17:16:07 -0700114 old_checksums = self.all_checksums
115 self.all_checksums = []
Rich Lane207599b2014-03-06 14:24:16 -0800116 self.checksum_buckets = [0] * buckets_size
117 self.table_checksum = 0
Rich Lane4ef81fd2014-06-30 17:16:07 -0700118 for checksum in old_checksums:
119 self.insert_checksum(checksum)
Rich Lane207599b2014-03-06 14:24:16 -0800120
121class FlowChecksum(FlowChecksumBase):
122 """
123 Test flow checksum buckets and table checksums
124 """
125 def runTest(self):
126 delete_all_flows(self.controller)
127
128 # Deleted all flows, table checksum should be 0
129 self.assertEquals(self.get_table_checksum(), 0)
130
131 self.set_buckets_size(8)
132 self.verify_checksums()
133
134 # Interesting checksums
135 checksums = [
136 make_checksum(0, 1),
137 make_checksum(0, 2),
138 make_checksum(1, 0xab),
139 make_checksum(1, 0xab),
140 make_checksum(7, 0xff),
141 make_checksum(7, 0xaa),
142 ]
143
144 # Random checksums
145 for _ in xrange(0, 8):
146 checksums.append(random.randint(0, 2**64-1))
147
148 # Add flows in random order
Rich Lanea7331722014-03-11 13:28:25 -0700149 for i, checksum in shuffled(enumerate(checksums)):
Rich Lane207599b2014-03-06 14:24:16 -0800150 self.insert_checksum(checksum)
151 request = ofp.message.flow_add(
152 table_id=TABLE_ID,
153 cookie=checksum,
154 buffer_id=ofp.OFP_NO_BUFFER,
155 priority=i)
156 self.controller.message_send(request)
Rich Lanea7331722014-03-11 13:28:25 -0700157 do_barrier(self.controller)
158 verify_no_errors(self.controller)
159 self.verify_checksums()
Rich Lane207599b2014-03-06 14:24:16 -0800160
161 # Delete flows in random order
Rich Lanea7331722014-03-11 13:28:25 -0700162 for i, checksum in shuffled(enumerate(checksums)):
Rich Lane207599b2014-03-06 14:24:16 -0800163 self.remove_checksum(checksum)
164 request = ofp.message.flow_delete_strict(
165 table_id=TABLE_ID,
166 priority=i,
167 out_port=ofp.OFPP_ANY,
168 out_group=ofp.OFPG_ANY)
169 self.controller.message_send(request)
Rich Lanea7331722014-03-11 13:28:25 -0700170 do_barrier(self.controller)
171 verify_no_errors(self.controller)
172 self.verify_checksums()
Rich Lane207599b2014-03-06 14:24:16 -0800173
174 # Deleted all flows, table checksum should be 0
175 self.assertEquals(self.get_table_checksum(), 0)
176
177class Resize(FlowChecksumBase):
178 """
179 Resize the checksum buckets, checking limits and redistribution
180 """
181 def runTest(self):
182 delete_all_flows(self.controller)
183
184 self.assertEquals(self.get_table_checksum(), 0)
185
186 self.set_buckets_size(128)
187 self.verify_checksums()
188
189 checksums = [random.randint(0, 2**64-1) for _ in xrange(0, 128)]
190
191 # Add flows
192 for i, checksum in enumerate(checksums):
193 self.insert_checksum(checksum)
194 request = ofp.message.flow_add(
195 table_id=TABLE_ID,
196 cookie=checksum,
197 buffer_id=ofp.OFP_NO_BUFFER,
198 priority=i)
199 self.controller.message_send(request)
Rich Lanea7331722014-03-11 13:28:25 -0700200 if i % 17 == 0:
201 do_barrier(self.controller)
202 verify_no_errors(self.controller)
203 self.verify_checksums()
204
Rich Lane207599b2014-03-06 14:24:16 -0800205 do_barrier(self.controller)
206 verify_no_errors(self.controller)
207 self.verify_checksums()
208
209 # Shrink checksum buckets
210 self.set_buckets_size(64)
211 self.verify_checksums()
212
213 # Shrink checksum buckets to minimum
214 self.set_buckets_size(1)
215 self.verify_checksums()
216
217 # Grow checksum buckets
218 self.set_buckets_size(2)
219 self.verify_checksums()
220
221 # Grow checksum buckets
222 self.set_buckets_size(256)
223 self.verify_checksums()
224
225 # Grow checksum buckets to maximum
226 self.set_buckets_size(65536)
227 self.verify_checksums()
228
229 # Delete flows
230 for i, checksum in enumerate(checksums):
231 self.remove_checksum(checksum)
232 request = ofp.message.flow_delete_strict(
233 table_id=TABLE_ID,
234 priority=i,
235 out_port=ofp.OFPP_ANY,
236 out_group=ofp.OFPG_ANY)
237 self.controller.message_send(request)
Rich Lanea7331722014-03-11 13:28:25 -0700238 if i % 17 == 0:
239 do_barrier(self.controller)
240 verify_no_errors(self.controller)
241 self.verify_checksums()
242
Rich Lane207599b2014-03-06 14:24:16 -0800243 do_barrier(self.controller)
244 verify_no_errors(self.controller)
245 self.verify_checksums()
246
247 # Deleted all flows, table checksum should be 0
248 self.assertEquals(self.get_table_checksum(), 0)
249
250class ResizeError(FlowChecksumBase):
251 """
252 Check that the switch rejects invalid checksum buckets sizes
253 """
254 def runTest(self):
255 # buckets_size = 0
256 self.controller.message_send(
257 ofp.message.bsn_table_set_buckets_size(
258 table_id=TABLE_ID, buckets_size=0))
259 do_barrier(self.controller)
260 error, _ = self.controller.poll(ofp.OFPT_ERROR)
261 self.assertIsInstance(error, ofp.message.error_msg)
262
263 # buckets_size = 3
264 self.controller.message_send(
265 ofp.message.bsn_table_set_buckets_size(
266 table_id=TABLE_ID, buckets_size=3))
267 do_barrier(self.controller)
268 error, _ = self.controller.poll(ofp.OFPT_ERROR)
269 self.assertIsInstance(error, ofp.message.error_msg)
270
271 # buckets_size = 100
272 self.controller.message_send(
273 ofp.message.bsn_table_set_buckets_size(
274 table_id=TABLE_ID, buckets_size=100))
275 do_barrier(self.controller)
276 error, _ = self.controller.poll(ofp.OFPT_ERROR)
277 self.assertIsInstance(error, ofp.message.error_msg)
278
279 # buckets_size = 2**32 - 1
280 self.controller.message_send(
281 ofp.message.bsn_table_set_buckets_size(
282 table_id=TABLE_ID, buckets_size=2**32-1))
283 do_barrier(self.controller)
284 error, _ = self.controller.poll(ofp.OFPT_ERROR)
285 self.assertIsInstance(error, ofp.message.error_msg)
286
287 # buckets_size = 2**31
288 self.controller.message_send(
289 ofp.message.bsn_table_set_buckets_size(
290 table_id=TABLE_ID, buckets_size=2**31))
291 do_barrier(self.controller)
292 error, _ = self.controller.poll(ofp.OFPT_ERROR)
293 self.assertIsInstance(error, ofp.message.error_msg)
Rich Lane506673a2014-05-30 15:26:29 -0700294
295class TableChecksumIds(FlowChecksumBase):
296 """
297 Check that each table is represented in the table checksum stats reply
298 """
299 def runTest(self):
300 table_checksum_stats_ids = [x.table_id for x in get_stats(self, ofp.message.bsn_table_checksum_stats_request())]
301 table_stats_ids = [x.table_id for x in get_stats(self, ofp.message.table_stats_request())]
302 self.assertEquals(sorted(table_checksum_stats_ids), sorted(table_stats_ids))