blob: 057dfef9f813867ea601dfa0a011bbf55d8a6ca3 [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 Lane284dc4d2014-01-06 15:24:07 -080017# Distributed under the OpenFlow Software License (see LICENSE)
18# Copyright (c) 2012, 2013 Big Switch Networks, Inc.
19"""
20BSN gentable extension test cases
21"""
22
23import logging
Rich Lane232d2ab2014-01-07 12:23:16 -080024import math
Rich Lane14e4c142014-01-09 10:31:08 -080025import random
Rich Lane284dc4d2014-01-06 15:24:07 -080026
27from oftest import config
28import oftest.base_tests as base_tests
29import ofp
30
31from oftest.testutils import *
32
33# Hardcoded in the switch to ease testing
34TABLE_ID = 0
35
Rich Laneb2c5bf62014-01-06 17:18:40 -080036def tlv_dict(tlvs):
37 d = {}
38 for tlv in tlvs:
39 d[tlv.__class__] = tlv.value
40 return d
41
Rich Lane64c4e602014-01-07 11:27:06 -080042def make_checksum(hi, lo):
43 """
44 Place 'hi' in the upper 8 bits and 'lo' in the lower bits.
45 """
46 return ((hi & 0xff) << 120) | lo
47
48assert make_checksum(0xab, 0xcd) == 0xab0000000000000000000000000000cd
49
Rich Lane8f405c22014-06-30 17:17:21 -070050def add_checksum(a, b):
51 return (a + b) % 2**128
52
53def subtract_checksum(a, b):
54 return (a - b) % 2**128
55
56def bucket_index(num_buckets, checksum):
57 """
58 Use the top bits of the checksum to select a bucket index
59 """
60 return checksum >> (128 - int(math.log(num_buckets, 2)))
61
62def add_bucket_checksum(buckets, checksum):
63 """
64 Add the checksum to the correct bucket
65 """
66 index = bucket_index(len(buckets), checksum)
67 buckets[index] = add_checksum(buckets[index], checksum)
68
69def subtract_bucket_checksum(buckets, checksum):
70 """
71 Subtract the checksum from the correct bucket
72 """
73 index = bucket_index(len(buckets), checksum)
74 buckets[index] = subtract_checksum(buckets[index], checksum)
75
Rich Lane284dc4d2014-01-06 15:24:07 -080076class BaseGenTableTest(base_tests.SimpleProtocol):
77 def setUp(self):
78 base_tests.SimpleProtocol.setUp(self)
Rich Laneb2c5bf62014-01-06 17:18:40 -080079 self.do_clear()
Rich Lane284dc4d2014-01-06 15:24:07 -080080
81 def tearDown(self):
Rich Laneb2c5bf62014-01-06 17:18:40 -080082 self.do_clear()
Rich Lane284dc4d2014-01-06 15:24:07 -080083 base_tests.SimpleProtocol.tearDown(self)
84
Rich Laneb2c5bf62014-01-06 17:18:40 -080085 def do_clear(self, checksum=0, checksum_mask=0):
86 request = ofp.message.bsn_gentable_clear_request(
87 table_id=TABLE_ID,
Rich Lane20f6b592014-01-08 15:17:50 -080088 checksum=checksum,
89 checksum_mask=checksum_mask)
Rich Lane284dc4d2014-01-06 15:24:07 -080090 response, _ = self.controller.transact(request)
91 self.assertIsInstance(response, ofp.message.bsn_gentable_clear_reply)
Rich Lane20f6b592014-01-08 15:17:50 -080092 return response.deleted_count, response.error_count
Rich Lane284dc4d2014-01-06 15:24:07 -080093
Rich Laneb2c5bf62014-01-06 17:18:40 -080094 def do_add(self, vlan_vid, ipv4, mac, idle_notification=False, checksum=0):
Rich Lane284dc4d2014-01-06 15:24:07 -080095 msg = ofp.message.bsn_gentable_entry_add(
96 table_id=TABLE_ID,
97 key=[
98 ofp.bsn_tlv.vlan_vid(vlan_vid),
99 ofp.bsn_tlv.ipv4(ipv4)],
100 value=[
101 ofp.bsn_tlv.mac(mac)],
Rich Laneb2c5bf62014-01-06 17:18:40 -0800102 checksum=checksum)
Rich Lane284dc4d2014-01-06 15:24:07 -0800103 if idle_notification:
104 msg.value.append(ofp.bsn_tlv.idle_notification())
105 self.controller.message_send(msg)
106
107 def do_delete(self, vlan_vid, ipv4):
108 msg = ofp.message.bsn_gentable_entry_delete(
109 table_id=TABLE_ID,
110 key=[
111 ofp.bsn_tlv.vlan_vid(vlan_vid),
112 ofp.bsn_tlv.ipv4(ipv4)])
113 self.controller.message_send(msg)
114
Rich Laneb2c5bf62014-01-06 17:18:40 -0800115 def do_entry_stats(self, checksum=0, checksum_mask=0):
116 request = ofp.message.bsn_gentable_entry_stats_request(
117 table_id=TABLE_ID,
118 checksum=checksum,
119 checksum_mask=checksum_mask)
120 return get_stats(self, request)
121
122 def do_entry_desc_stats(self, checksum=0, checksum_mask=0):
123 request = ofp.message.bsn_gentable_entry_desc_stats_request(
124 table_id=TABLE_ID,
125 checksum=checksum,
126 checksum_mask=checksum_mask)
127 return get_stats(self, request)
128
Rich Lane4e691ad2014-01-06 17:45:20 -0800129 def do_table_desc_stats(self):
130 request = ofp.message.bsn_gentable_desc_stats_request()
131 return get_stats(self, request)
132
Rich Lanea8f56672014-01-06 17:50:39 -0800133 def do_table_stats(self):
134 request = ofp.message.bsn_gentable_stats_request()
135 return get_stats(self, request)
136
Rich Lane64c4e602014-01-07 11:27:06 -0800137 def do_test_table_stats(self):
138 entries = self.do_table_stats()
139 for entry in entries:
140 if entry.table_id == TABLE_ID:
141 return entry
142 raise AssertionError("did not find test table")
143
Rich Lane232d2ab2014-01-07 12:23:16 -0800144 def do_bucket_stats(self):
145 request = ofp.message.bsn_gentable_bucket_stats_request(table_id=TABLE_ID)
146 return get_stats(self, request)
147
Rich Lane78bd3772014-01-08 11:51:13 -0800148 def do_set_buckets_size(self, buckets_size):
149 msg = ofp.message.bsn_gentable_set_buckets_size(
150 table_id=TABLE_ID,
151 buckets_size=buckets_size)
152 self.controller.message_send(msg)
153
Rich Lane284dc4d2014-01-06 15:24:07 -0800154class ClearAll(BaseGenTableTest):
155 """
156 Test clearing entire table
157 """
158 def runTest(self):
159 # Add a few entries
160 for i in range(0, 3):
161 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i))
162
163 do_barrier(self.controller)
164 verify_no_errors(self.controller)
165
166 # Delete all entries
Rich Lane20f6b592014-01-08 15:17:50 -0800167 deleted, errors = self.do_clear(checksum=0, checksum_mask=0)
168 self.assertEquals(deleted, 3)
169 self.assertEquals(errors, 0)
170
171class ClearMasked(BaseGenTableTest):
172 """
173 Test clearing with a checksum mask
174 """
175 def runTest(self):
176 # Add 4 entries to each checksum bucket
177 for i in range(0, 256):
178 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i),
179 checksum=make_checksum(i, i*31))
180
181 do_barrier(self.controller)
182 verify_no_errors(self.controller)
183
184 # Delete bucket 0
185 deleted, errors = self.do_clear(make_checksum(0, 0), make_checksum(0xFC, 0))
186 self.assertEquals(deleted, 4)
187 self.assertEquals(errors, 0)
188
189 # Delete buckets 0 (already cleared), 1, 2, 3
190 deleted, errors = self.do_clear(make_checksum(0, 0), make_checksum(0xF0, 0))
191 self.assertEquals(deleted, 12)
192 self.assertEquals(errors, 0)
193
194 # Delete second half of bucket 4
195 deleted, errors = self.do_clear(make_checksum(0x10, 0), make_checksum(0xFE, 0))
196 self.assertEquals(deleted, 2)
197 self.assertEquals(errors, 0)
Rich Lane284dc4d2014-01-06 15:24:07 -0800198
199class AddDelete(BaseGenTableTest):
200 """
201 Test adding and deleting entries
202 """
203 def runTest(self):
204 # Add a few entries
205 for i in range(0, 3):
206 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i))
207
208 do_barrier(self.controller)
209 verify_no_errors(self.controller)
210
211 # Delete each entry
212 for i in range(0, 3):
213 self.do_delete(vlan_vid=i, ipv4=0x12345678)
214
215 do_barrier(self.controller)
216 verify_no_errors(self.controller)
217
218 # Clear table, but expect it to have already been empty
219 request = ofp.message.bsn_gentable_clear_request(table_id=TABLE_ID)
220 response, _ = self.controller.transact(request)
221 self.assertIsInstance(response, ofp.message.bsn_gentable_clear_reply)
222 self.assertEquals(response.error_count, 0)
223 self.assertEquals(response.deleted_count, 0)
Rich Laneb2c5bf62014-01-06 17:18:40 -0800224
225class EntryStats(BaseGenTableTest):
226 """
227 Test retrieving entry stats
228 """
229 def runTest(self):
230 # Add a few entries
231 for i in range(0, 3):
232 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i))
233
234 do_barrier(self.controller)
235 verify_no_errors(self.controller)
236
237 entries = self.do_entry_stats()
238 seen = set()
239 for entry in entries:
240 logging.debug(entry.show())
241 key = tlv_dict(entry.key)
242 stats = tlv_dict(entry.stats)
243 self.assertIn(ofp.bsn_tlv.vlan_vid, key)
244 self.assertIn(ofp.bsn_tlv.ipv4, key)
245 self.assertIn(ofp.bsn_tlv.rx_packets, stats)
246 self.assertIn(ofp.bsn_tlv.tx_packets, stats)
247 vlan_vid = key[ofp.bsn_tlv.vlan_vid]
248 seen.add(vlan_vid)
249 self.assertEqual(key[ofp.bsn_tlv.ipv4], 0x12345678)
250 self.assertEqual(stats[ofp.bsn_tlv.rx_packets], 100 * vlan_vid)
251 self.assertEqual(stats[ofp.bsn_tlv.tx_packets], 101 * vlan_vid)
252
253 self.assertEquals(seen, set([0, 1, 2]))
254
Rich Lane790cc202014-01-08 14:54:25 -0800255class EntryStatsMasked(BaseGenTableTest):
256 """
257 Test retrieving entry stats with a checksum mask
258 """
259 def runTest(self):
260 def get_range(checksum, checksum_mask):
261 entries = self.do_entry_stats(checksum, checksum_mask)
262 vlan_vids = []
263 for entry in entries:
264 key = tlv_dict(entry.key)
265 vlan_vids.append(key[ofp.bsn_tlv.vlan_vid])
266 return sorted(vlan_vids)
267
268 # Add 4 entries to each checksum bucket
269 for i in range(0, 256):
270 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i),
271 checksum=make_checksum(i, i))
272
273 do_barrier(self.controller)
274 verify_no_errors(self.controller)
275
276 # Check first bucket
277 self.assertEquals(get_range(make_checksum(0, 0), make_checksum(0xFC, 0)),
278 [0, 1, 2, 3])
279
280 # Check last bucket
281 self.assertEquals(get_range(make_checksum(0xFC, 0), make_checksum(0xFC, 0)),
282 [252, 253, 254, 255])
283
284 # Check first half of first bucket
285 self.assertEquals(get_range(make_checksum(0x00, 0), make_checksum(0xFE, 0)),
286 [0, 1])
287
288 # Check second half of first bucket
289 self.assertEquals(get_range(make_checksum(0x02, 0), make_checksum(0xFE, 0)),
290 [2, 3])
291
292 # Check first half of last bucket
293 self.assertEquals(get_range(make_checksum(0xFC, 0), make_checksum(0xFE, 0)),
294 [252, 253])
295
296 # Check second half of last bucket
297 self.assertEquals(get_range(make_checksum(0xFE, 0), make_checksum(0xFE, 0)),
298 [254, 255])
299
300 # Check first two buckets
301 self.assertEquals(get_range(make_checksum(0, 0), make_checksum(0xF8, 0)),
302 [0, 1, 2, 3, 4, 5, 6, 7])
303
304 # Check last two buckets
305 self.assertEquals(get_range(make_checksum(0xF8, 0), make_checksum(0xF8, 0)),
306 [248, 249, 250, 251, 252, 253, 254, 255])
307
308 # Check matching on low bits
309 self.assertEquals(get_range(make_checksum(0x00, 0x00), ~1), [0])
310 self.assertEquals(get_range(make_checksum(0x01, 0x00), ~1), [1])
311 self.assertEquals(get_range(make_checksum(0x01, 0x02), ~1), [])
312
Rich Lane464960b2014-01-08 17:30:07 -0800313class EntryStatsFragmented(BaseGenTableTest):
314 """
315 Test retrieving entry stats in mutiple replies
316 """
317 def runTest(self):
318 # Add a bunch of entries
319 # Enough for 3 stats replies
Rich Lane87f54bd2014-01-08 17:53:14 -0800320 for i in range(0, 4095):
Rich Lane464960b2014-01-08 17:30:07 -0800321 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, 5))
322
323 do_barrier(self.controller)
324 verify_no_errors(self.controller)
325
326 entries = self.do_entry_stats()
327 seen = set()
328 for entry in entries:
329 key = tlv_dict(entry.key)
330 vlan_vid = key[ofp.bsn_tlv.vlan_vid]
331 self.assertNotIn(vlan_vid, seen)
332 seen.add(vlan_vid)
333
Rich Lane87f54bd2014-01-08 17:53:14 -0800334 self.assertEquals(seen, set(range(0, 4095)))
Rich Lane790cc202014-01-08 14:54:25 -0800335
Rich Laneb2c5bf62014-01-06 17:18:40 -0800336class EntryDescStats(BaseGenTableTest):
337 """
338 Test retrieving entry desc stats
339 """
340 def runTest(self):
341 # Add a few entries
342 for i in range(0, 3):
343 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i),
344 checksum=0xfedcba9876543210fedcba9876543210 + i)
345
346 do_barrier(self.controller)
347 verify_no_errors(self.controller)
348
349 entries = self.do_entry_desc_stats()
350 seen = set()
351 for entry in entries:
352 logging.debug(entry.show())
353 key = tlv_dict(entry.key)
354 value = tlv_dict(entry.value)
355 self.assertIn(ofp.bsn_tlv.vlan_vid, key)
356 self.assertIn(ofp.bsn_tlv.ipv4, key)
357 self.assertIn(ofp.bsn_tlv.mac, value)
358 vlan_vid = key[ofp.bsn_tlv.vlan_vid]
359 seen.add(vlan_vid)
360 self.assertEqual(key[ofp.bsn_tlv.ipv4], 0x12345678)
361 self.assertEqual(value[ofp.bsn_tlv.mac], [0, 1, 2, 3, 4, vlan_vid])
362 self.assertEqual(entry.checksum, 0xfedcba9876543210fedcba9876543210 + vlan_vid)
363
364 self.assertEquals(seen, set([0, 1, 2]))
Rich Lane4e691ad2014-01-06 17:45:20 -0800365
Rich Lane790cc202014-01-08 14:54:25 -0800366class EntryDescStatsMasked(BaseGenTableTest):
367 """
368 Test retrieving entry desc stats with a checksum mask
369 """
370 def runTest(self):
371 def get_range(checksum, checksum_mask):
372 entries = self.do_entry_desc_stats(checksum, checksum_mask)
373 vlan_vids = []
374 for entry in entries:
375 key = tlv_dict(entry.key)
376 vlan_vids.append(key[ofp.bsn_tlv.vlan_vid])
377 return sorted(vlan_vids)
378
379 # Add 4 entries to each checksum bucket
380 for i in range(0, 256):
381 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i),
Rich Lane8d867ee2014-01-08 17:29:55 -0800382 checksum=make_checksum(i, i))
Rich Lane790cc202014-01-08 14:54:25 -0800383
384 do_barrier(self.controller)
385 verify_no_errors(self.controller)
386
387 # Check first bucket
388 self.assertEquals(get_range(make_checksum(0, 0), make_checksum(0xFC, 0)),
389 [0, 1, 2, 3])
390
391 # Check last bucket
392 self.assertEquals(get_range(make_checksum(0xFC, 0), make_checksum(0xFC, 0)),
393 [252, 253, 254, 255])
394
395 # Check first half of first bucket
396 self.assertEquals(get_range(make_checksum(0x00, 0), make_checksum(0xFE, 0)),
397 [0, 1])
398
399 # Check second half of first bucket
400 self.assertEquals(get_range(make_checksum(0x02, 0), make_checksum(0xFE, 0)),
401 [2, 3])
402
403 # Check first half of last bucket
404 self.assertEquals(get_range(make_checksum(0xFC, 0), make_checksum(0xFE, 0)),
405 [252, 253])
406
407 # Check second half of last bucket
408 self.assertEquals(get_range(make_checksum(0xFE, 0), make_checksum(0xFE, 0)),
409 [254, 255])
410
411 # Check first two buckets
412 self.assertEquals(get_range(make_checksum(0, 0), make_checksum(0xF8, 0)),
413 [0, 1, 2, 3, 4, 5, 6, 7])
414
415 # Check last two buckets
416 self.assertEquals(get_range(make_checksum(0xF8, 0), make_checksum(0xF8, 0)),
417 [248, 249, 250, 251, 252, 253, 254, 255])
418
419 # Check matching on low bits
420 self.assertEquals(get_range(make_checksum(0x00, 0x00), ~1), [0])
421 self.assertEquals(get_range(make_checksum(0x01, 0x00), ~1), [1])
422 self.assertEquals(get_range(make_checksum(0x01, 0x02), ~1), [])
423
Rich Lane5003c292014-01-08 17:34:45 -0800424class EntryDescStatsFragmented(BaseGenTableTest):
425 """
426 Test retrieving entry stats in mutiple replies
427 """
428 def runTest(self):
429 # Add a bunch of entries
430 # Enough for 3 stats replies
Rich Lane87f54bd2014-01-08 17:53:14 -0800431 for i in range(0, 4095):
Rich Lane5003c292014-01-08 17:34:45 -0800432 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, 5))
433
434 do_barrier(self.controller)
435 verify_no_errors(self.controller)
436
437 entries = self.do_entry_desc_stats()
438 seen = set()
439 for entry in entries:
440 key = tlv_dict(entry.key)
441 vlan_vid = key[ofp.bsn_tlv.vlan_vid]
442 self.assertNotIn(vlan_vid, seen)
443 seen.add(vlan_vid)
444
Rich Lane87f54bd2014-01-08 17:53:14 -0800445 self.assertEquals(seen, set(range(0, 4095)))
Rich Lane5003c292014-01-08 17:34:45 -0800446
Rich Lane4e691ad2014-01-06 17:45:20 -0800447class TableDescStats(BaseGenTableTest):
448 """
449 Test retrieving table desc stats
450 """
451 def runTest(self):
452 entries = self.do_table_desc_stats()
453 seen = set()
454 for entry in entries:
455 logging.debug(entry.show())
456 self.assertNotIn(entry.table_id, seen)
457 self.assertNotIn(entry.name, seen)
458 seen.add(entry.table_id)
459 seen.add(entry.name)
460 if entry.table_id == TABLE_ID:
461 self.assertEqual(entry.name, "test")
462 self.assertEqual(entry.buckets_size, 64)
463 self.assertEqual(entry.max_entries, 1000)
464
465 self.assertIn(TABLE_ID, seen)
Rich Lanea8f56672014-01-06 17:50:39 -0800466
467class TableStats(BaseGenTableTest):
468 """
469 Test retrieving table stats
470 """
471 def runTest(self):
Rich Lane64c4e602014-01-07 11:27:06 -0800472 # Verify we have the test table and no duplicates
Rich Lanea8f56672014-01-06 17:50:39 -0800473 entries = self.do_table_stats()
474 seen = set()
475 for entry in entries:
476 logging.debug(entry.show())
477 self.assertNotIn(entry.table_id, seen)
478 seen.add(entry.table_id)
479 if entry.table_id == TABLE_ID:
480 self.assertEqual(entry.entry_count, 0)
481 self.assertEqual(entry.checksum, 0)
Rich Lanea8f56672014-01-06 17:50:39 -0800482 self.assertIn(TABLE_ID, seen)
Rich Lane64c4e602014-01-07 11:27:06 -0800483
484 table_checksum = 0
485
486 # Add a bunch of entries, spread among the checksum buckets
487 for i in range(0, 256):
Rich Lane8f405c22014-06-30 17:17:21 -0700488 table_checksum = add_checksum(table_checksum, make_checksum(i, i*31))
Rich Lane64c4e602014-01-07 11:27:06 -0800489 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i),
490 checksum=make_checksum(i, i*31))
491
492 do_barrier(self.controller)
493 verify_no_errors(self.controller)
494
495 table_stats = self.do_test_table_stats()
496 self.assertEqual(table_stats.entry_count, 256)
497 self.assertEqual(table_stats.checksum, table_checksum)
498
499 # Modify an entry, changing its checksum
500 i = 30
Rich Lane8f405c22014-06-30 17:17:21 -0700501 table_checksum = subtract_checksum(table_checksum, make_checksum(i, i*31)) # subtract old checksum
502 table_checksum = add_checksum(table_checksum, make_checksum(i, i*37)) # add new checksum
Rich Lane64c4e602014-01-07 11:27:06 -0800503 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 4, 3, 2, 1, i),
504 checksum=make_checksum(i, i*37))
505
506 do_barrier(self.controller)
507 verify_no_errors(self.controller)
508
509 table_stats = self.do_test_table_stats()
510 self.assertEqual(table_stats.entry_count, 256)
511 self.assertEqual(table_stats.checksum, table_checksum)
512
513 # Delete an entry
514 i = 87
Rich Lane8f405c22014-06-30 17:17:21 -0700515 table_checksum = subtract_checksum(table_checksum, make_checksum(i, i*31))
Rich Lane64c4e602014-01-07 11:27:06 -0800516 self.do_delete(vlan_vid=i, ipv4=0x12345678)
517
518 do_barrier(self.controller)
519 verify_no_errors(self.controller)
520
521 table_stats = self.do_test_table_stats()
522 self.assertEqual(table_stats.entry_count, 255)
523 self.assertEqual(table_stats.checksum, table_checksum)
Rich Lane232d2ab2014-01-07 12:23:16 -0800524
525class BucketStats(BaseGenTableTest):
526 """
527 Test retrieving checksum bucket stats
528 """
529 def runTest(self):
530 # Verify initial state
531 entries = self.do_bucket_stats()
532 self.assertEquals(len(entries), 64)
533 for entry in entries:
534 self.assertEquals(entry.checksum, 0)
535
536 buckets = [0] * len(entries)
Rich Lane232d2ab2014-01-07 12:23:16 -0800537
538 # Add a bunch of entries, spread among the checksum buckets
539 for i in range(0, 256):
Rich Lane8f405c22014-06-30 17:17:21 -0700540 add_bucket_checksum(buckets, make_checksum(i, i*31))
Rich Lane232d2ab2014-01-07 12:23:16 -0800541 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i),
542 checksum=make_checksum(i, i*31))
543
544 entries = self.do_bucket_stats()
545 self.assertEquals(len(entries), 64)
546 for i, entry in enumerate(entries):
547 self.assertEquals(entry.checksum, buckets[i])
548
549 # Modify an entry, changing its checksum
550 i = 30
Rich Lane8f405c22014-06-30 17:17:21 -0700551 subtract_bucket_checksum(buckets, make_checksum(i, i*31)) # subtract old checksum
552 add_bucket_checksum(buckets, make_checksum(i, i*37)) # add new checksum
Rich Lane232d2ab2014-01-07 12:23:16 -0800553 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 4, 3, 2, 1, i),
554 checksum=make_checksum(i, i*37))
555
556 do_barrier(self.controller)
557 verify_no_errors(self.controller)
558
559 entries = self.do_bucket_stats()
560 self.assertEquals(len(entries), 64)
561 for i, entry in enumerate(entries):
562 self.assertEquals(entry.checksum, buckets[i])
563
564 # Delete an entry
565 i = 87
Rich Lane8f405c22014-06-30 17:17:21 -0700566 subtract_bucket_checksum(buckets, make_checksum(i, i*31))
Rich Lane232d2ab2014-01-07 12:23:16 -0800567 self.do_delete(vlan_vid=i, ipv4=0x12345678)
568
569 do_barrier(self.controller)
570 verify_no_errors(self.controller)
571
572 entries = self.do_bucket_stats()
573 self.assertEquals(len(entries), 64)
574 for i, entry in enumerate(entries):
575 self.assertEquals(entry.checksum, buckets[i])
Rich Lane78bd3772014-01-08 11:51:13 -0800576
Rich Lane7fdc07d2014-01-09 14:24:40 -0800577class BucketStatsFragmented(BaseGenTableTest):
578 """
579 Test retrieving checksum bucket stats in multiple replies
580 """
581
582 def tearDown(self):
583 self.do_set_buckets_size(64)
584 do_barrier(self.controller)
585 BaseGenTableTest.tearDown(self)
586
587 def runTest(self):
588 # Enough for 3 stats messages
589 self.do_set_buckets_size(8192)
590 do_barrier(self.controller)
591 verify_no_errors(self.controller)
592
593 entries = self.do_bucket_stats()
594 self.assertEquals(len(entries), 8192)
595
Rich Lane78bd3772014-01-08 11:51:13 -0800596class SetBucketsSize(BaseGenTableTest):
597 """
598 Test setting the checksum buckets size
599 """
600 def setUp(self):
601 BaseGenTableTest.setUp(self)
602 self.do_set_buckets_size(64)
603 do_barrier(self.controller)
604
605 def tearDown(self):
606 self.do_set_buckets_size(64)
607 do_barrier(self.controller)
608 BaseGenTableTest.tearDown(self)
609
610 def runTest(self):
611 # Verify initial state
612 entries = self.do_bucket_stats()
613 self.assertEquals(len(entries), 64)
614 for entry in entries:
615 self.assertEquals(entry.checksum, 0)
616
617 buckets32 = [0] * 32
618 buckets64 = [0] * 64
619
Rich Lane78bd3772014-01-08 11:51:13 -0800620 # Add a bunch of entries, spread among the checksum buckets
621 for i in range(0, 256):
Rich Lane8f405c22014-06-30 17:17:21 -0700622 checksum = make_checksum(i, i*31)
623 add_bucket_checksum(buckets32, checksum)
624 add_bucket_checksum(buckets64, checksum)
Rich Lane78bd3772014-01-08 11:51:13 -0800625 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i),
Rich Lane8f405c22014-06-30 17:17:21 -0700626 checksum=checksum)
Rich Lane78bd3772014-01-08 11:51:13 -0800627
628 entries = self.do_bucket_stats()
629 self.assertEquals(len(entries), 64)
630 for i, entry in enumerate(entries):
631 self.assertEquals(entry.checksum, buckets64[i])
632
633 self.do_set_buckets_size(32)
634 do_barrier(self.controller)
635
636 entries = self.do_bucket_stats()
637 self.assertEquals(len(entries), 32)
638 for i, entry in enumerate(entries):
639 self.assertEquals(entry.checksum, buckets32[i])
640
641 self.do_set_buckets_size(64)
642 do_barrier(self.controller)
643
644 entries = self.do_bucket_stats()
645 self.assertEquals(len(entries), 64)
646 for i, entry in enumerate(entries):
647 self.assertEquals(entry.checksum, buckets64[i])
Rich Lane55408072014-01-09 10:12:36 -0800648
Rich Laneeda1a4a2014-01-09 12:26:27 -0800649class SetBucketsSizeError(BaseGenTableTest):
650 """
651 Test error cases in setting the checksum buckets size
652 """
653 def setUp(self):
654 BaseGenTableTest.setUp(self)
655 self.do_set_buckets_size(64)
656 do_barrier(self.controller)
657
658 def tearDown(self):
659 self.do_set_buckets_size(64)
660 do_barrier(self.controller)
661 BaseGenTableTest.tearDown(self)
662
663 def runTest(self):
664 # Zero buckets size
665 self.do_set_buckets_size(0)
666 do_barrier(self.controller)
667
668 error, _ = self.controller.poll(ofp.OFPT_ERROR, 0)
669 self.assertIsInstance(error, ofp.message.bad_request_error_msg)
670 self.assertEquals(error.code, ofp.OFPBRC_EPERM)
671
672 # Non power of 2 buckets size
673 self.do_set_buckets_size(7)
674 do_barrier(self.controller)
675
676 error, _ = self.controller.poll(ofp.OFPT_ERROR, 0)
677 self.assertIsInstance(error, ofp.message.bad_request_error_msg)
678 self.assertEquals(error.code, ofp.OFPBRC_EPERM)
679
Rich Lane55408072014-01-09 10:12:36 -0800680class AddError(BaseGenTableTest):
681 """
682 Test failure adding entries
683 """
684 def runTest(self):
685 # Invalid key
686 self.do_add(vlan_vid=10000, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, 5))
687 do_barrier(self.controller)
688
689 error, _ = self.controller.poll(ofp.OFPT_ERROR, 0)
690 self.assertIsInstance(error, ofp.message.bad_request_error_msg)
691 self.assertEquals(error.code, ofp.OFPBRC_EPERM)
692
693 self.assertEquals(len(self.do_entry_desc_stats()), 0)
694
695 # Invalid value
696 self.do_add(vlan_vid=100, ipv4=0x12345678, mac=(1, 1, 2, 3, 4, 5))
697 do_barrier(self.controller)
698
699 error, _ = self.controller.poll(ofp.OFPT_ERROR, 0)
700 self.assertIsInstance(error, ofp.message.bad_request_error_msg)
701 self.assertEquals(error.code, ofp.OFPBRC_EPERM)
702
703 self.assertEquals(len(self.do_entry_desc_stats()), 0)
704
705class ModifyError(BaseGenTableTest):
706 """
707 Test failure modifying entries
708 """
709 def runTest(self):
710 # Add a valid entry we'll try to modify
711 self.do_add(vlan_vid=100, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, 5))
712 do_barrier(self.controller)
713 verify_no_errors(self.controller)
714
715 orig_entries = self.do_entry_desc_stats()
716 self.assertEquals(len(orig_entries), 1)
717
718 # Invalid value
719 self.do_add(vlan_vid=100, ipv4=0x12345678, mac=(1, 1, 2, 3, 4, 5))
720 do_barrier(self.controller)
721
722 error, _ = self.controller.poll(ofp.OFPT_ERROR, 0)
723 self.assertIsInstance(error, ofp.message.bad_request_error_msg)
724 self.assertEquals(error.code, ofp.OFPBRC_EPERM)
725
726 # Check that the table wasn't modified
727 new_entries = self.do_entry_desc_stats()
728 self.assertEquals(len(new_entries), 1)
729 self.assertEquals(new_entries, orig_entries)
Rich Lane14e4c142014-01-09 10:31:08 -0800730
Rich Laneb1186cc2014-01-09 11:20:26 -0800731class DeleteNonexistentError(BaseGenTableTest):
732 """
733 Test failure deleting a nonexistent entry
734 """
735 def runTest(self):
736 self.do_delete(vlan_vid=1000, ipv4=0x12345678)
737 do_barrier(self.controller)
738
739 error, _ = self.controller.poll(ofp.OFPT_ERROR, 0)
Rich Lanea49c4de2014-02-05 14:18:40 -0800740 self.assertEquals(error, None)
Rich Laneb1186cc2014-01-09 11:20:26 -0800741
Rich Lane9f6c6272014-01-09 12:16:08 -0800742class DeleteFailureError(BaseGenTableTest):
743 """
744 Test failure deleting a nonexistent entry
745
746 The very special idle_notification TLV will cause the entry to fail
747 being deleted the first time. This behavior is only there to help
748 test this error path.
749 """
750 def runTest(self):
751 self.do_add(vlan_vid=1000, ipv4=0x12345678,
752 mac=(0, 1, 2, 3, 4, 5), idle_notification=True)
753 do_barrier(self.controller)
754 verify_no_errors(self.controller)
755
756 orig_entries = self.do_entry_desc_stats()
757 self.assertEquals(len(orig_entries), 1)
758
759 # This will fail
760 self.do_delete(vlan_vid=1000, ipv4=0x12345678)
761 do_barrier(self.controller)
762
763 error, _ = self.controller.poll(ofp.OFPT_ERROR, 0)
764 self.assertIsInstance(error, ofp.message.bad_request_error_msg)
765 self.assertEquals(error.code, ofp.OFPBRC_EPERM)
766
767 # Check that the table wasn't modified
768 new_entries = self.do_entry_desc_stats()
769 self.assertEquals(len(new_entries), 1)
770 self.assertEquals(new_entries, orig_entries)
771
772 # This will succeed
773 self.do_delete(vlan_vid=1000, ipv4=0x12345678)
774 do_barrier(self.controller)
775 verify_no_errors(self.controller)
776
Rich Lane14e4c142014-01-09 10:31:08 -0800777class BadTableIdError(BaseGenTableTest):
778 """
779 Test failure of each message when specifying a nonexistent table id
780 """
781 def runTest(self):
782 def check_error(msg):
783 reply, _ = self.controller.transact(msg)
784 self.assertIsInstance(reply, ofp.message.bad_request_error_msg)
785 self.assertEquals(reply.code, ofp.OFPBRC_BAD_TABLE_ID)
786
787 valid_table_ids = set([x.table_id for x in self.do_table_desc_stats()])
788 invalid_table_id = TABLE_ID
789 while invalid_table_id in valid_table_ids:
790 invalid_table_id = random.randrange(65536)
791
792 logging.debug("Using invalid table id %d", invalid_table_id)
793
794 check_error(ofp.message.bsn_gentable_clear_request(
795 table_id=invalid_table_id))
796
797 check_error(ofp.message.bsn_gentable_entry_add(
798 table_id=invalid_table_id))
799
800 check_error(ofp.message.bsn_gentable_entry_delete(
801 table_id=invalid_table_id))
802
803 check_error(ofp.message.bsn_gentable_entry_stats_request(
804 table_id=invalid_table_id))
805
806 check_error(ofp.message.bsn_gentable_entry_desc_stats_request(
807 table_id=invalid_table_id))
808
809 check_error(ofp.message.bsn_gentable_bucket_stats_request(
810 table_id=invalid_table_id))
811
812 check_error(ofp.message.bsn_gentable_set_buckets_size(
813 table_id=invalid_table_id))