blob: 4c2fc8a63628be2046552362f31bc2a40e35c2a9 [file] [log] [blame]
Rich Lane284dc4d2014-01-06 15:24:07 -08001# Distributed under the OpenFlow Software License (see LICENSE)
2# Copyright (c) 2012, 2013 Big Switch Networks, Inc.
3"""
4BSN gentable extension test cases
5"""
6
7import logging
Rich Lane232d2ab2014-01-07 12:23:16 -08008import math
Rich Lane14e4c142014-01-09 10:31:08 -08009import random
Rich Lane284dc4d2014-01-06 15:24:07 -080010
11from oftest import config
12import oftest.base_tests as base_tests
13import ofp
14
15from oftest.testutils import *
16
17# Hardcoded in the switch to ease testing
18TABLE_ID = 0
19
Rich Laneb2c5bf62014-01-06 17:18:40 -080020def tlv_dict(tlvs):
21 d = {}
22 for tlv in tlvs:
23 d[tlv.__class__] = tlv.value
24 return d
25
Rich Lane64c4e602014-01-07 11:27:06 -080026def make_checksum(hi, lo):
27 """
28 Place 'hi' in the upper 8 bits and 'lo' in the lower bits.
29 """
30 return ((hi & 0xff) << 120) | lo
31
32assert make_checksum(0xab, 0xcd) == 0xab0000000000000000000000000000cd
33
Rich Lane8f405c22014-06-30 17:17:21 -070034def add_checksum(a, b):
35 return (a + b) % 2**128
36
37def subtract_checksum(a, b):
38 return (a - b) % 2**128
39
40def bucket_index(num_buckets, checksum):
41 """
42 Use the top bits of the checksum to select a bucket index
43 """
44 return checksum >> (128 - int(math.log(num_buckets, 2)))
45
46def add_bucket_checksum(buckets, checksum):
47 """
48 Add the checksum to the correct bucket
49 """
50 index = bucket_index(len(buckets), checksum)
51 buckets[index] = add_checksum(buckets[index], checksum)
52
53def subtract_bucket_checksum(buckets, checksum):
54 """
55 Subtract the checksum from the correct bucket
56 """
57 index = bucket_index(len(buckets), checksum)
58 buckets[index] = subtract_checksum(buckets[index], checksum)
59
Rich Lane284dc4d2014-01-06 15:24:07 -080060class BaseGenTableTest(base_tests.SimpleProtocol):
61 def setUp(self):
62 base_tests.SimpleProtocol.setUp(self)
Rich Laneb2c5bf62014-01-06 17:18:40 -080063 self.do_clear()
Rich Lane284dc4d2014-01-06 15:24:07 -080064
65 def tearDown(self):
Rich Laneb2c5bf62014-01-06 17:18:40 -080066 self.do_clear()
Rich Lane284dc4d2014-01-06 15:24:07 -080067 base_tests.SimpleProtocol.tearDown(self)
68
Rich Laneb2c5bf62014-01-06 17:18:40 -080069 def do_clear(self, checksum=0, checksum_mask=0):
70 request = ofp.message.bsn_gentable_clear_request(
71 table_id=TABLE_ID,
Rich Lane20f6b592014-01-08 15:17:50 -080072 checksum=checksum,
73 checksum_mask=checksum_mask)
Rich Lane284dc4d2014-01-06 15:24:07 -080074 response, _ = self.controller.transact(request)
75 self.assertIsInstance(response, ofp.message.bsn_gentable_clear_reply)
Rich Lane20f6b592014-01-08 15:17:50 -080076 return response.deleted_count, response.error_count
Rich Lane284dc4d2014-01-06 15:24:07 -080077
Rich Laneb2c5bf62014-01-06 17:18:40 -080078 def do_add(self, vlan_vid, ipv4, mac, idle_notification=False, checksum=0):
Rich Lane284dc4d2014-01-06 15:24:07 -080079 msg = ofp.message.bsn_gentable_entry_add(
80 table_id=TABLE_ID,
81 key=[
82 ofp.bsn_tlv.vlan_vid(vlan_vid),
83 ofp.bsn_tlv.ipv4(ipv4)],
84 value=[
85 ofp.bsn_tlv.mac(mac)],
Rich Laneb2c5bf62014-01-06 17:18:40 -080086 checksum=checksum)
Rich Lane284dc4d2014-01-06 15:24:07 -080087 if idle_notification:
88 msg.value.append(ofp.bsn_tlv.idle_notification())
89 self.controller.message_send(msg)
90
91 def do_delete(self, vlan_vid, ipv4):
92 msg = ofp.message.bsn_gentable_entry_delete(
93 table_id=TABLE_ID,
94 key=[
95 ofp.bsn_tlv.vlan_vid(vlan_vid),
96 ofp.bsn_tlv.ipv4(ipv4)])
97 self.controller.message_send(msg)
98
Rich Laneb2c5bf62014-01-06 17:18:40 -080099 def do_entry_stats(self, checksum=0, checksum_mask=0):
100 request = ofp.message.bsn_gentable_entry_stats_request(
101 table_id=TABLE_ID,
102 checksum=checksum,
103 checksum_mask=checksum_mask)
104 return get_stats(self, request)
105
106 def do_entry_desc_stats(self, checksum=0, checksum_mask=0):
107 request = ofp.message.bsn_gentable_entry_desc_stats_request(
108 table_id=TABLE_ID,
109 checksum=checksum,
110 checksum_mask=checksum_mask)
111 return get_stats(self, request)
112
Rich Lane4e691ad2014-01-06 17:45:20 -0800113 def do_table_desc_stats(self):
114 request = ofp.message.bsn_gentable_desc_stats_request()
115 return get_stats(self, request)
116
Rich Lanea8f56672014-01-06 17:50:39 -0800117 def do_table_stats(self):
118 request = ofp.message.bsn_gentable_stats_request()
119 return get_stats(self, request)
120
Rich Lane64c4e602014-01-07 11:27:06 -0800121 def do_test_table_stats(self):
122 entries = self.do_table_stats()
123 for entry in entries:
124 if entry.table_id == TABLE_ID:
125 return entry
126 raise AssertionError("did not find test table")
127
Rich Lane232d2ab2014-01-07 12:23:16 -0800128 def do_bucket_stats(self):
129 request = ofp.message.bsn_gentable_bucket_stats_request(table_id=TABLE_ID)
130 return get_stats(self, request)
131
Rich Lane78bd3772014-01-08 11:51:13 -0800132 def do_set_buckets_size(self, buckets_size):
133 msg = ofp.message.bsn_gentable_set_buckets_size(
134 table_id=TABLE_ID,
135 buckets_size=buckets_size)
136 self.controller.message_send(msg)
137
Rich Lane284dc4d2014-01-06 15:24:07 -0800138class ClearAll(BaseGenTableTest):
139 """
140 Test clearing entire table
141 """
142 def runTest(self):
143 # Add a few entries
144 for i in range(0, 3):
145 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i))
146
147 do_barrier(self.controller)
148 verify_no_errors(self.controller)
149
150 # Delete all entries
Rich Lane20f6b592014-01-08 15:17:50 -0800151 deleted, errors = self.do_clear(checksum=0, checksum_mask=0)
152 self.assertEquals(deleted, 3)
153 self.assertEquals(errors, 0)
154
155class ClearMasked(BaseGenTableTest):
156 """
157 Test clearing with a checksum mask
158 """
159 def runTest(self):
160 # Add 4 entries to each checksum bucket
161 for i in range(0, 256):
162 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i),
163 checksum=make_checksum(i, i*31))
164
165 do_barrier(self.controller)
166 verify_no_errors(self.controller)
167
168 # Delete bucket 0
169 deleted, errors = self.do_clear(make_checksum(0, 0), make_checksum(0xFC, 0))
170 self.assertEquals(deleted, 4)
171 self.assertEquals(errors, 0)
172
173 # Delete buckets 0 (already cleared), 1, 2, 3
174 deleted, errors = self.do_clear(make_checksum(0, 0), make_checksum(0xF0, 0))
175 self.assertEquals(deleted, 12)
176 self.assertEquals(errors, 0)
177
178 # Delete second half of bucket 4
179 deleted, errors = self.do_clear(make_checksum(0x10, 0), make_checksum(0xFE, 0))
180 self.assertEquals(deleted, 2)
181 self.assertEquals(errors, 0)
Rich Lane284dc4d2014-01-06 15:24:07 -0800182
183class AddDelete(BaseGenTableTest):
184 """
185 Test adding and deleting entries
186 """
187 def runTest(self):
188 # Add a few entries
189 for i in range(0, 3):
190 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i))
191
192 do_barrier(self.controller)
193 verify_no_errors(self.controller)
194
195 # Delete each entry
196 for i in range(0, 3):
197 self.do_delete(vlan_vid=i, ipv4=0x12345678)
198
199 do_barrier(self.controller)
200 verify_no_errors(self.controller)
201
202 # Clear table, but expect it to have already been empty
203 request = ofp.message.bsn_gentable_clear_request(table_id=TABLE_ID)
204 response, _ = self.controller.transact(request)
205 self.assertIsInstance(response, ofp.message.bsn_gentable_clear_reply)
206 self.assertEquals(response.error_count, 0)
207 self.assertEquals(response.deleted_count, 0)
Rich Laneb2c5bf62014-01-06 17:18:40 -0800208
209class EntryStats(BaseGenTableTest):
210 """
211 Test retrieving entry stats
212 """
213 def runTest(self):
214 # Add a few entries
215 for i in range(0, 3):
216 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i))
217
218 do_barrier(self.controller)
219 verify_no_errors(self.controller)
220
221 entries = self.do_entry_stats()
222 seen = set()
223 for entry in entries:
224 logging.debug(entry.show())
225 key = tlv_dict(entry.key)
226 stats = tlv_dict(entry.stats)
227 self.assertIn(ofp.bsn_tlv.vlan_vid, key)
228 self.assertIn(ofp.bsn_tlv.ipv4, key)
229 self.assertIn(ofp.bsn_tlv.rx_packets, stats)
230 self.assertIn(ofp.bsn_tlv.tx_packets, stats)
231 vlan_vid = key[ofp.bsn_tlv.vlan_vid]
232 seen.add(vlan_vid)
233 self.assertEqual(key[ofp.bsn_tlv.ipv4], 0x12345678)
234 self.assertEqual(stats[ofp.bsn_tlv.rx_packets], 100 * vlan_vid)
235 self.assertEqual(stats[ofp.bsn_tlv.tx_packets], 101 * vlan_vid)
236
237 self.assertEquals(seen, set([0, 1, 2]))
238
Rich Lane790cc202014-01-08 14:54:25 -0800239class EntryStatsMasked(BaseGenTableTest):
240 """
241 Test retrieving entry stats with a checksum mask
242 """
243 def runTest(self):
244 def get_range(checksum, checksum_mask):
245 entries = self.do_entry_stats(checksum, checksum_mask)
246 vlan_vids = []
247 for entry in entries:
248 key = tlv_dict(entry.key)
249 vlan_vids.append(key[ofp.bsn_tlv.vlan_vid])
250 return sorted(vlan_vids)
251
252 # Add 4 entries to each checksum bucket
253 for i in range(0, 256):
254 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i),
255 checksum=make_checksum(i, i))
256
257 do_barrier(self.controller)
258 verify_no_errors(self.controller)
259
260 # Check first bucket
261 self.assertEquals(get_range(make_checksum(0, 0), make_checksum(0xFC, 0)),
262 [0, 1, 2, 3])
263
264 # Check last bucket
265 self.assertEquals(get_range(make_checksum(0xFC, 0), make_checksum(0xFC, 0)),
266 [252, 253, 254, 255])
267
268 # Check first half of first bucket
269 self.assertEquals(get_range(make_checksum(0x00, 0), make_checksum(0xFE, 0)),
270 [0, 1])
271
272 # Check second half of first bucket
273 self.assertEquals(get_range(make_checksum(0x02, 0), make_checksum(0xFE, 0)),
274 [2, 3])
275
276 # Check first half of last bucket
277 self.assertEquals(get_range(make_checksum(0xFC, 0), make_checksum(0xFE, 0)),
278 [252, 253])
279
280 # Check second half of last bucket
281 self.assertEquals(get_range(make_checksum(0xFE, 0), make_checksum(0xFE, 0)),
282 [254, 255])
283
284 # Check first two buckets
285 self.assertEquals(get_range(make_checksum(0, 0), make_checksum(0xF8, 0)),
286 [0, 1, 2, 3, 4, 5, 6, 7])
287
288 # Check last two buckets
289 self.assertEquals(get_range(make_checksum(0xF8, 0), make_checksum(0xF8, 0)),
290 [248, 249, 250, 251, 252, 253, 254, 255])
291
292 # Check matching on low bits
293 self.assertEquals(get_range(make_checksum(0x00, 0x00), ~1), [0])
294 self.assertEquals(get_range(make_checksum(0x01, 0x00), ~1), [1])
295 self.assertEquals(get_range(make_checksum(0x01, 0x02), ~1), [])
296
Rich Lane464960b2014-01-08 17:30:07 -0800297class EntryStatsFragmented(BaseGenTableTest):
298 """
299 Test retrieving entry stats in mutiple replies
300 """
301 def runTest(self):
302 # Add a bunch of entries
303 # Enough for 3 stats replies
Rich Lane87f54bd2014-01-08 17:53:14 -0800304 for i in range(0, 4095):
Rich Lane464960b2014-01-08 17:30:07 -0800305 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, 5))
306
307 do_barrier(self.controller)
308 verify_no_errors(self.controller)
309
310 entries = self.do_entry_stats()
311 seen = set()
312 for entry in entries:
313 key = tlv_dict(entry.key)
314 vlan_vid = key[ofp.bsn_tlv.vlan_vid]
315 self.assertNotIn(vlan_vid, seen)
316 seen.add(vlan_vid)
317
Rich Lane87f54bd2014-01-08 17:53:14 -0800318 self.assertEquals(seen, set(range(0, 4095)))
Rich Lane790cc202014-01-08 14:54:25 -0800319
Rich Laneb2c5bf62014-01-06 17:18:40 -0800320class EntryDescStats(BaseGenTableTest):
321 """
322 Test retrieving entry desc stats
323 """
324 def runTest(self):
325 # Add a few entries
326 for i in range(0, 3):
327 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i),
328 checksum=0xfedcba9876543210fedcba9876543210 + i)
329
330 do_barrier(self.controller)
331 verify_no_errors(self.controller)
332
333 entries = self.do_entry_desc_stats()
334 seen = set()
335 for entry in entries:
336 logging.debug(entry.show())
337 key = tlv_dict(entry.key)
338 value = tlv_dict(entry.value)
339 self.assertIn(ofp.bsn_tlv.vlan_vid, key)
340 self.assertIn(ofp.bsn_tlv.ipv4, key)
341 self.assertIn(ofp.bsn_tlv.mac, value)
342 vlan_vid = key[ofp.bsn_tlv.vlan_vid]
343 seen.add(vlan_vid)
344 self.assertEqual(key[ofp.bsn_tlv.ipv4], 0x12345678)
345 self.assertEqual(value[ofp.bsn_tlv.mac], [0, 1, 2, 3, 4, vlan_vid])
346 self.assertEqual(entry.checksum, 0xfedcba9876543210fedcba9876543210 + vlan_vid)
347
348 self.assertEquals(seen, set([0, 1, 2]))
Rich Lane4e691ad2014-01-06 17:45:20 -0800349
Rich Lane790cc202014-01-08 14:54:25 -0800350class EntryDescStatsMasked(BaseGenTableTest):
351 """
352 Test retrieving entry desc stats with a checksum mask
353 """
354 def runTest(self):
355 def get_range(checksum, checksum_mask):
356 entries = self.do_entry_desc_stats(checksum, checksum_mask)
357 vlan_vids = []
358 for entry in entries:
359 key = tlv_dict(entry.key)
360 vlan_vids.append(key[ofp.bsn_tlv.vlan_vid])
361 return sorted(vlan_vids)
362
363 # Add 4 entries to each checksum bucket
364 for i in range(0, 256):
365 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i),
Rich Lane8d867ee2014-01-08 17:29:55 -0800366 checksum=make_checksum(i, i))
Rich Lane790cc202014-01-08 14:54:25 -0800367
368 do_barrier(self.controller)
369 verify_no_errors(self.controller)
370
371 # Check first bucket
372 self.assertEquals(get_range(make_checksum(0, 0), make_checksum(0xFC, 0)),
373 [0, 1, 2, 3])
374
375 # Check last bucket
376 self.assertEquals(get_range(make_checksum(0xFC, 0), make_checksum(0xFC, 0)),
377 [252, 253, 254, 255])
378
379 # Check first half of first bucket
380 self.assertEquals(get_range(make_checksum(0x00, 0), make_checksum(0xFE, 0)),
381 [0, 1])
382
383 # Check second half of first bucket
384 self.assertEquals(get_range(make_checksum(0x02, 0), make_checksum(0xFE, 0)),
385 [2, 3])
386
387 # Check first half of last bucket
388 self.assertEquals(get_range(make_checksum(0xFC, 0), make_checksum(0xFE, 0)),
389 [252, 253])
390
391 # Check second half of last bucket
392 self.assertEquals(get_range(make_checksum(0xFE, 0), make_checksum(0xFE, 0)),
393 [254, 255])
394
395 # Check first two buckets
396 self.assertEquals(get_range(make_checksum(0, 0), make_checksum(0xF8, 0)),
397 [0, 1, 2, 3, 4, 5, 6, 7])
398
399 # Check last two buckets
400 self.assertEquals(get_range(make_checksum(0xF8, 0), make_checksum(0xF8, 0)),
401 [248, 249, 250, 251, 252, 253, 254, 255])
402
403 # Check matching on low bits
404 self.assertEquals(get_range(make_checksum(0x00, 0x00), ~1), [0])
405 self.assertEquals(get_range(make_checksum(0x01, 0x00), ~1), [1])
406 self.assertEquals(get_range(make_checksum(0x01, 0x02), ~1), [])
407
Rich Lane5003c292014-01-08 17:34:45 -0800408class EntryDescStatsFragmented(BaseGenTableTest):
409 """
410 Test retrieving entry stats in mutiple replies
411 """
412 def runTest(self):
413 # Add a bunch of entries
414 # Enough for 3 stats replies
Rich Lane87f54bd2014-01-08 17:53:14 -0800415 for i in range(0, 4095):
Rich Lane5003c292014-01-08 17:34:45 -0800416 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, 5))
417
418 do_barrier(self.controller)
419 verify_no_errors(self.controller)
420
421 entries = self.do_entry_desc_stats()
422 seen = set()
423 for entry in entries:
424 key = tlv_dict(entry.key)
425 vlan_vid = key[ofp.bsn_tlv.vlan_vid]
426 self.assertNotIn(vlan_vid, seen)
427 seen.add(vlan_vid)
428
Rich Lane87f54bd2014-01-08 17:53:14 -0800429 self.assertEquals(seen, set(range(0, 4095)))
Rich Lane5003c292014-01-08 17:34:45 -0800430
Rich Lane4e691ad2014-01-06 17:45:20 -0800431class TableDescStats(BaseGenTableTest):
432 """
433 Test retrieving table desc stats
434 """
435 def runTest(self):
436 entries = self.do_table_desc_stats()
437 seen = set()
438 for entry in entries:
439 logging.debug(entry.show())
440 self.assertNotIn(entry.table_id, seen)
441 self.assertNotIn(entry.name, seen)
442 seen.add(entry.table_id)
443 seen.add(entry.name)
444 if entry.table_id == TABLE_ID:
445 self.assertEqual(entry.name, "test")
446 self.assertEqual(entry.buckets_size, 64)
447 self.assertEqual(entry.max_entries, 1000)
448
449 self.assertIn(TABLE_ID, seen)
Rich Lanea8f56672014-01-06 17:50:39 -0800450
451class TableStats(BaseGenTableTest):
452 """
453 Test retrieving table stats
454 """
455 def runTest(self):
Rich Lane64c4e602014-01-07 11:27:06 -0800456 # Verify we have the test table and no duplicates
Rich Lanea8f56672014-01-06 17:50:39 -0800457 entries = self.do_table_stats()
458 seen = set()
459 for entry in entries:
460 logging.debug(entry.show())
461 self.assertNotIn(entry.table_id, seen)
462 seen.add(entry.table_id)
463 if entry.table_id == TABLE_ID:
464 self.assertEqual(entry.entry_count, 0)
465 self.assertEqual(entry.checksum, 0)
Rich Lanea8f56672014-01-06 17:50:39 -0800466 self.assertIn(TABLE_ID, seen)
Rich Lane64c4e602014-01-07 11:27:06 -0800467
468 table_checksum = 0
469
470 # Add a bunch of entries, spread among the checksum buckets
471 for i in range(0, 256):
Rich Lane8f405c22014-06-30 17:17:21 -0700472 table_checksum = add_checksum(table_checksum, make_checksum(i, i*31))
Rich Lane64c4e602014-01-07 11:27:06 -0800473 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i),
474 checksum=make_checksum(i, i*31))
475
476 do_barrier(self.controller)
477 verify_no_errors(self.controller)
478
479 table_stats = self.do_test_table_stats()
480 self.assertEqual(table_stats.entry_count, 256)
481 self.assertEqual(table_stats.checksum, table_checksum)
482
483 # Modify an entry, changing its checksum
484 i = 30
Rich Lane8f405c22014-06-30 17:17:21 -0700485 table_checksum = subtract_checksum(table_checksum, make_checksum(i, i*31)) # subtract old checksum
486 table_checksum = add_checksum(table_checksum, make_checksum(i, i*37)) # add new checksum
Rich Lane64c4e602014-01-07 11:27:06 -0800487 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 4, 3, 2, 1, i),
488 checksum=make_checksum(i, i*37))
489
490 do_barrier(self.controller)
491 verify_no_errors(self.controller)
492
493 table_stats = self.do_test_table_stats()
494 self.assertEqual(table_stats.entry_count, 256)
495 self.assertEqual(table_stats.checksum, table_checksum)
496
497 # Delete an entry
498 i = 87
Rich Lane8f405c22014-06-30 17:17:21 -0700499 table_checksum = subtract_checksum(table_checksum, make_checksum(i, i*31))
Rich Lane64c4e602014-01-07 11:27:06 -0800500 self.do_delete(vlan_vid=i, ipv4=0x12345678)
501
502 do_barrier(self.controller)
503 verify_no_errors(self.controller)
504
505 table_stats = self.do_test_table_stats()
506 self.assertEqual(table_stats.entry_count, 255)
507 self.assertEqual(table_stats.checksum, table_checksum)
Rich Lane232d2ab2014-01-07 12:23:16 -0800508
509class BucketStats(BaseGenTableTest):
510 """
511 Test retrieving checksum bucket stats
512 """
513 def runTest(self):
514 # Verify initial state
515 entries = self.do_bucket_stats()
516 self.assertEquals(len(entries), 64)
517 for entry in entries:
518 self.assertEquals(entry.checksum, 0)
519
520 buckets = [0] * len(entries)
Rich Lane232d2ab2014-01-07 12:23:16 -0800521
522 # Add a bunch of entries, spread among the checksum buckets
523 for i in range(0, 256):
Rich Lane8f405c22014-06-30 17:17:21 -0700524 add_bucket_checksum(buckets, make_checksum(i, i*31))
Rich Lane232d2ab2014-01-07 12:23:16 -0800525 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i),
526 checksum=make_checksum(i, i*31))
527
528 entries = self.do_bucket_stats()
529 self.assertEquals(len(entries), 64)
530 for i, entry in enumerate(entries):
531 self.assertEquals(entry.checksum, buckets[i])
532
533 # Modify an entry, changing its checksum
534 i = 30
Rich Lane8f405c22014-06-30 17:17:21 -0700535 subtract_bucket_checksum(buckets, make_checksum(i, i*31)) # subtract old checksum
536 add_bucket_checksum(buckets, make_checksum(i, i*37)) # add new checksum
Rich Lane232d2ab2014-01-07 12:23:16 -0800537 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 4, 3, 2, 1, i),
538 checksum=make_checksum(i, i*37))
539
540 do_barrier(self.controller)
541 verify_no_errors(self.controller)
542
543 entries = self.do_bucket_stats()
544 self.assertEquals(len(entries), 64)
545 for i, entry in enumerate(entries):
546 self.assertEquals(entry.checksum, buckets[i])
547
548 # Delete an entry
549 i = 87
Rich Lane8f405c22014-06-30 17:17:21 -0700550 subtract_bucket_checksum(buckets, make_checksum(i, i*31))
Rich Lane232d2ab2014-01-07 12:23:16 -0800551 self.do_delete(vlan_vid=i, ipv4=0x12345678)
552
553 do_barrier(self.controller)
554 verify_no_errors(self.controller)
555
556 entries = self.do_bucket_stats()
557 self.assertEquals(len(entries), 64)
558 for i, entry in enumerate(entries):
559 self.assertEquals(entry.checksum, buckets[i])
Rich Lane78bd3772014-01-08 11:51:13 -0800560
Rich Lane7fdc07d2014-01-09 14:24:40 -0800561class BucketStatsFragmented(BaseGenTableTest):
562 """
563 Test retrieving checksum bucket stats in multiple replies
564 """
565
566 def tearDown(self):
567 self.do_set_buckets_size(64)
568 do_barrier(self.controller)
569 BaseGenTableTest.tearDown(self)
570
571 def runTest(self):
572 # Enough for 3 stats messages
573 self.do_set_buckets_size(8192)
574 do_barrier(self.controller)
575 verify_no_errors(self.controller)
576
577 entries = self.do_bucket_stats()
578 self.assertEquals(len(entries), 8192)
579
Rich Lane78bd3772014-01-08 11:51:13 -0800580class SetBucketsSize(BaseGenTableTest):
581 """
582 Test setting the checksum buckets size
583 """
584 def setUp(self):
585 BaseGenTableTest.setUp(self)
586 self.do_set_buckets_size(64)
587 do_barrier(self.controller)
588
589 def tearDown(self):
590 self.do_set_buckets_size(64)
591 do_barrier(self.controller)
592 BaseGenTableTest.tearDown(self)
593
594 def runTest(self):
595 # Verify initial state
596 entries = self.do_bucket_stats()
597 self.assertEquals(len(entries), 64)
598 for entry in entries:
599 self.assertEquals(entry.checksum, 0)
600
601 buckets32 = [0] * 32
602 buckets64 = [0] * 64
603
Rich Lane78bd3772014-01-08 11:51:13 -0800604 # Add a bunch of entries, spread among the checksum buckets
605 for i in range(0, 256):
Rich Lane8f405c22014-06-30 17:17:21 -0700606 checksum = make_checksum(i, i*31)
607 add_bucket_checksum(buckets32, checksum)
608 add_bucket_checksum(buckets64, checksum)
Rich Lane78bd3772014-01-08 11:51:13 -0800609 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i),
Rich Lane8f405c22014-06-30 17:17:21 -0700610 checksum=checksum)
Rich Lane78bd3772014-01-08 11:51:13 -0800611
612 entries = self.do_bucket_stats()
613 self.assertEquals(len(entries), 64)
614 for i, entry in enumerate(entries):
615 self.assertEquals(entry.checksum, buckets64[i])
616
617 self.do_set_buckets_size(32)
618 do_barrier(self.controller)
619
620 entries = self.do_bucket_stats()
621 self.assertEquals(len(entries), 32)
622 for i, entry in enumerate(entries):
623 self.assertEquals(entry.checksum, buckets32[i])
624
625 self.do_set_buckets_size(64)
626 do_barrier(self.controller)
627
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])
Rich Lane55408072014-01-09 10:12:36 -0800632
Rich Laneeda1a4a2014-01-09 12:26:27 -0800633class SetBucketsSizeError(BaseGenTableTest):
634 """
635 Test error cases in setting the checksum buckets size
636 """
637 def setUp(self):
638 BaseGenTableTest.setUp(self)
639 self.do_set_buckets_size(64)
640 do_barrier(self.controller)
641
642 def tearDown(self):
643 self.do_set_buckets_size(64)
644 do_barrier(self.controller)
645 BaseGenTableTest.tearDown(self)
646
647 def runTest(self):
648 # Zero buckets size
649 self.do_set_buckets_size(0)
650 do_barrier(self.controller)
651
652 error, _ = self.controller.poll(ofp.OFPT_ERROR, 0)
653 self.assertIsInstance(error, ofp.message.bad_request_error_msg)
654 self.assertEquals(error.code, ofp.OFPBRC_EPERM)
655
656 # Non power of 2 buckets size
657 self.do_set_buckets_size(7)
658 do_barrier(self.controller)
659
660 error, _ = self.controller.poll(ofp.OFPT_ERROR, 0)
661 self.assertIsInstance(error, ofp.message.bad_request_error_msg)
662 self.assertEquals(error.code, ofp.OFPBRC_EPERM)
663
Rich Lane55408072014-01-09 10:12:36 -0800664class AddError(BaseGenTableTest):
665 """
666 Test failure adding entries
667 """
668 def runTest(self):
669 # Invalid key
670 self.do_add(vlan_vid=10000, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, 5))
671 do_barrier(self.controller)
672
673 error, _ = self.controller.poll(ofp.OFPT_ERROR, 0)
674 self.assertIsInstance(error, ofp.message.bad_request_error_msg)
675 self.assertEquals(error.code, ofp.OFPBRC_EPERM)
676
677 self.assertEquals(len(self.do_entry_desc_stats()), 0)
678
679 # Invalid value
680 self.do_add(vlan_vid=100, ipv4=0x12345678, mac=(1, 1, 2, 3, 4, 5))
681 do_barrier(self.controller)
682
683 error, _ = self.controller.poll(ofp.OFPT_ERROR, 0)
684 self.assertIsInstance(error, ofp.message.bad_request_error_msg)
685 self.assertEquals(error.code, ofp.OFPBRC_EPERM)
686
687 self.assertEquals(len(self.do_entry_desc_stats()), 0)
688
689class ModifyError(BaseGenTableTest):
690 """
691 Test failure modifying entries
692 """
693 def runTest(self):
694 # Add a valid entry we'll try to modify
695 self.do_add(vlan_vid=100, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, 5))
696 do_barrier(self.controller)
697 verify_no_errors(self.controller)
698
699 orig_entries = self.do_entry_desc_stats()
700 self.assertEquals(len(orig_entries), 1)
701
702 # Invalid value
703 self.do_add(vlan_vid=100, ipv4=0x12345678, mac=(1, 1, 2, 3, 4, 5))
704 do_barrier(self.controller)
705
706 error, _ = self.controller.poll(ofp.OFPT_ERROR, 0)
707 self.assertIsInstance(error, ofp.message.bad_request_error_msg)
708 self.assertEquals(error.code, ofp.OFPBRC_EPERM)
709
710 # Check that the table wasn't modified
711 new_entries = self.do_entry_desc_stats()
712 self.assertEquals(len(new_entries), 1)
713 self.assertEquals(new_entries, orig_entries)
Rich Lane14e4c142014-01-09 10:31:08 -0800714
Rich Laneb1186cc2014-01-09 11:20:26 -0800715class DeleteNonexistentError(BaseGenTableTest):
716 """
717 Test failure deleting a nonexistent entry
718 """
719 def runTest(self):
720 self.do_delete(vlan_vid=1000, ipv4=0x12345678)
721 do_barrier(self.controller)
722
723 error, _ = self.controller.poll(ofp.OFPT_ERROR, 0)
Rich Lanea49c4de2014-02-05 14:18:40 -0800724 self.assertEquals(error, None)
Rich Laneb1186cc2014-01-09 11:20:26 -0800725
Rich Lane9f6c6272014-01-09 12:16:08 -0800726class DeleteFailureError(BaseGenTableTest):
727 """
728 Test failure deleting a nonexistent entry
729
730 The very special idle_notification TLV will cause the entry to fail
731 being deleted the first time. This behavior is only there to help
732 test this error path.
733 """
734 def runTest(self):
735 self.do_add(vlan_vid=1000, ipv4=0x12345678,
736 mac=(0, 1, 2, 3, 4, 5), idle_notification=True)
737 do_barrier(self.controller)
738 verify_no_errors(self.controller)
739
740 orig_entries = self.do_entry_desc_stats()
741 self.assertEquals(len(orig_entries), 1)
742
743 # This will fail
744 self.do_delete(vlan_vid=1000, ipv4=0x12345678)
745 do_barrier(self.controller)
746
747 error, _ = self.controller.poll(ofp.OFPT_ERROR, 0)
748 self.assertIsInstance(error, ofp.message.bad_request_error_msg)
749 self.assertEquals(error.code, ofp.OFPBRC_EPERM)
750
751 # Check that the table wasn't modified
752 new_entries = self.do_entry_desc_stats()
753 self.assertEquals(len(new_entries), 1)
754 self.assertEquals(new_entries, orig_entries)
755
756 # This will succeed
757 self.do_delete(vlan_vid=1000, ipv4=0x12345678)
758 do_barrier(self.controller)
759 verify_no_errors(self.controller)
760
Rich Lane14e4c142014-01-09 10:31:08 -0800761class BadTableIdError(BaseGenTableTest):
762 """
763 Test failure of each message when specifying a nonexistent table id
764 """
765 def runTest(self):
766 def check_error(msg):
767 reply, _ = self.controller.transact(msg)
768 self.assertIsInstance(reply, ofp.message.bad_request_error_msg)
769 self.assertEquals(reply.code, ofp.OFPBRC_BAD_TABLE_ID)
770
771 valid_table_ids = set([x.table_id for x in self.do_table_desc_stats()])
772 invalid_table_id = TABLE_ID
773 while invalid_table_id in valid_table_ids:
774 invalid_table_id = random.randrange(65536)
775
776 logging.debug("Using invalid table id %d", invalid_table_id)
777
778 check_error(ofp.message.bsn_gentable_clear_request(
779 table_id=invalid_table_id))
780
781 check_error(ofp.message.bsn_gentable_entry_add(
782 table_id=invalid_table_id))
783
784 check_error(ofp.message.bsn_gentable_entry_delete(
785 table_id=invalid_table_id))
786
787 check_error(ofp.message.bsn_gentable_entry_stats_request(
788 table_id=invalid_table_id))
789
790 check_error(ofp.message.bsn_gentable_entry_desc_stats_request(
791 table_id=invalid_table_id))
792
793 check_error(ofp.message.bsn_gentable_bucket_stats_request(
794 table_id=invalid_table_id))
795
796 check_error(ofp.message.bsn_gentable_set_buckets_size(
797 table_id=invalid_table_id))