blob: 4cc6b3a18620b4c921bc95c4bdc4cb45a6046a14 [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 Lane284dc4d2014-01-06 15:24:07 -08009
10from oftest import config
11import oftest.base_tests as base_tests
12import ofp
13
14from oftest.testutils import *
15
16# Hardcoded in the switch to ease testing
17TABLE_ID = 0
18
Rich Laneb2c5bf62014-01-06 17:18:40 -080019def tlv_dict(tlvs):
20 d = {}
21 for tlv in tlvs:
22 d[tlv.__class__] = tlv.value
23 return d
24
Rich Lane64c4e602014-01-07 11:27:06 -080025def make_checksum(hi, lo):
26 """
27 Place 'hi' in the upper 8 bits and 'lo' in the lower bits.
28 """
29 return ((hi & 0xff) << 120) | lo
30
31assert make_checksum(0xab, 0xcd) == 0xab0000000000000000000000000000cd
32
Rich Lane284dc4d2014-01-06 15:24:07 -080033class BaseGenTableTest(base_tests.SimpleProtocol):
34 def setUp(self):
35 base_tests.SimpleProtocol.setUp(self)
Rich Laneb2c5bf62014-01-06 17:18:40 -080036 self.do_clear()
Rich Lane284dc4d2014-01-06 15:24:07 -080037
38 def tearDown(self):
Rich Laneb2c5bf62014-01-06 17:18:40 -080039 self.do_clear()
Rich Lane284dc4d2014-01-06 15:24:07 -080040 base_tests.SimpleProtocol.tearDown(self)
41
Rich Laneb2c5bf62014-01-06 17:18:40 -080042 def do_clear(self, checksum=0, checksum_mask=0):
43 request = ofp.message.bsn_gentable_clear_request(
44 table_id=TABLE_ID,
45 checksum=0,
46 checksum_mask=0)
Rich Lane284dc4d2014-01-06 15:24:07 -080047 response, _ = self.controller.transact(request)
48 self.assertIsInstance(response, ofp.message.bsn_gentable_clear_reply)
49 self.assertEquals(response.error_count, 0)
50
Rich Laneb2c5bf62014-01-06 17:18:40 -080051 def do_add(self, vlan_vid, ipv4, mac, idle_notification=False, checksum=0):
Rich Lane284dc4d2014-01-06 15:24:07 -080052 msg = ofp.message.bsn_gentable_entry_add(
53 table_id=TABLE_ID,
54 key=[
55 ofp.bsn_tlv.vlan_vid(vlan_vid),
56 ofp.bsn_tlv.ipv4(ipv4)],
57 value=[
58 ofp.bsn_tlv.mac(mac)],
Rich Laneb2c5bf62014-01-06 17:18:40 -080059 checksum=checksum)
Rich Lane284dc4d2014-01-06 15:24:07 -080060 if idle_notification:
61 msg.value.append(ofp.bsn_tlv.idle_notification())
62 self.controller.message_send(msg)
63
64 def do_delete(self, vlan_vid, ipv4):
65 msg = ofp.message.bsn_gentable_entry_delete(
66 table_id=TABLE_ID,
67 key=[
68 ofp.bsn_tlv.vlan_vid(vlan_vid),
69 ofp.bsn_tlv.ipv4(ipv4)])
70 self.controller.message_send(msg)
71
Rich Laneb2c5bf62014-01-06 17:18:40 -080072 def do_entry_stats(self, checksum=0, checksum_mask=0):
73 request = ofp.message.bsn_gentable_entry_stats_request(
74 table_id=TABLE_ID,
75 checksum=checksum,
76 checksum_mask=checksum_mask)
77 return get_stats(self, request)
78
79 def do_entry_desc_stats(self, checksum=0, checksum_mask=0):
80 request = ofp.message.bsn_gentable_entry_desc_stats_request(
81 table_id=TABLE_ID,
82 checksum=checksum,
83 checksum_mask=checksum_mask)
84 return get_stats(self, request)
85
Rich Lane4e691ad2014-01-06 17:45:20 -080086 def do_table_desc_stats(self):
87 request = ofp.message.bsn_gentable_desc_stats_request()
88 return get_stats(self, request)
89
Rich Lanea8f56672014-01-06 17:50:39 -080090 def do_table_stats(self):
91 request = ofp.message.bsn_gentable_stats_request()
92 return get_stats(self, request)
93
Rich Lane64c4e602014-01-07 11:27:06 -080094 def do_test_table_stats(self):
95 entries = self.do_table_stats()
96 for entry in entries:
97 if entry.table_id == TABLE_ID:
98 return entry
99 raise AssertionError("did not find test table")
100
Rich Lane232d2ab2014-01-07 12:23:16 -0800101 def do_bucket_stats(self):
102 request = ofp.message.bsn_gentable_bucket_stats_request(table_id=TABLE_ID)
103 return get_stats(self, request)
104
Rich Lane78bd3772014-01-08 11:51:13 -0800105 def do_set_buckets_size(self, buckets_size):
106 msg = ofp.message.bsn_gentable_set_buckets_size(
107 table_id=TABLE_ID,
108 buckets_size=buckets_size)
109 self.controller.message_send(msg)
110
Rich Lane284dc4d2014-01-06 15:24:07 -0800111class ClearAll(BaseGenTableTest):
112 """
113 Test clearing entire table
114 """
115 def runTest(self):
116 # Add a few entries
117 for i in range(0, 3):
118 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i))
119
120 do_barrier(self.controller)
121 verify_no_errors(self.controller)
122
123 # Delete all entries
124 request = ofp.message.bsn_gentable_clear_request(table_id=TABLE_ID)
125 response, _ = self.controller.transact(request)
126 self.assertIsInstance(response, ofp.message.bsn_gentable_clear_reply)
127 self.assertEquals(response.error_count, 0)
128 self.assertEquals(response.deleted_count, 3)
129
130class AddDelete(BaseGenTableTest):
131 """
132 Test adding and deleting entries
133 """
134 def runTest(self):
135 # Add a few entries
136 for i in range(0, 3):
137 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i))
138
139 do_barrier(self.controller)
140 verify_no_errors(self.controller)
141
142 # Delete each entry
143 for i in range(0, 3):
144 self.do_delete(vlan_vid=i, ipv4=0x12345678)
145
146 do_barrier(self.controller)
147 verify_no_errors(self.controller)
148
149 # Clear table, but expect it to have already been empty
150 request = ofp.message.bsn_gentable_clear_request(table_id=TABLE_ID)
151 response, _ = self.controller.transact(request)
152 self.assertIsInstance(response, ofp.message.bsn_gentable_clear_reply)
153 self.assertEquals(response.error_count, 0)
154 self.assertEquals(response.deleted_count, 0)
Rich Laneb2c5bf62014-01-06 17:18:40 -0800155
156class EntryStats(BaseGenTableTest):
157 """
158 Test retrieving entry stats
159 """
160 def runTest(self):
161 # Add a few entries
162 for i in range(0, 3):
163 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i))
164
165 do_barrier(self.controller)
166 verify_no_errors(self.controller)
167
168 entries = self.do_entry_stats()
169 seen = set()
170 for entry in entries:
171 logging.debug(entry.show())
172 key = tlv_dict(entry.key)
173 stats = tlv_dict(entry.stats)
174 self.assertIn(ofp.bsn_tlv.vlan_vid, key)
175 self.assertIn(ofp.bsn_tlv.ipv4, key)
176 self.assertIn(ofp.bsn_tlv.rx_packets, stats)
177 self.assertIn(ofp.bsn_tlv.tx_packets, stats)
178 vlan_vid = key[ofp.bsn_tlv.vlan_vid]
179 seen.add(vlan_vid)
180 self.assertEqual(key[ofp.bsn_tlv.ipv4], 0x12345678)
181 self.assertEqual(stats[ofp.bsn_tlv.rx_packets], 100 * vlan_vid)
182 self.assertEqual(stats[ofp.bsn_tlv.tx_packets], 101 * vlan_vid)
183
184 self.assertEquals(seen, set([0, 1, 2]))
185
Rich Lane790cc202014-01-08 14:54:25 -0800186class EntryStatsMasked(BaseGenTableTest):
187 """
188 Test retrieving entry stats with a checksum mask
189 """
190 def runTest(self):
191 def get_range(checksum, checksum_mask):
192 entries = self.do_entry_stats(checksum, checksum_mask)
193 vlan_vids = []
194 for entry in entries:
195 key = tlv_dict(entry.key)
196 vlan_vids.append(key[ofp.bsn_tlv.vlan_vid])
197 return sorted(vlan_vids)
198
199 # Add 4 entries to each checksum bucket
200 for i in range(0, 256):
201 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i),
202 checksum=make_checksum(i, i))
203
204 do_barrier(self.controller)
205 verify_no_errors(self.controller)
206
207 # Check first bucket
208 self.assertEquals(get_range(make_checksum(0, 0), make_checksum(0xFC, 0)),
209 [0, 1, 2, 3])
210
211 # Check last bucket
212 self.assertEquals(get_range(make_checksum(0xFC, 0), make_checksum(0xFC, 0)),
213 [252, 253, 254, 255])
214
215 # Check first half of first bucket
216 self.assertEquals(get_range(make_checksum(0x00, 0), make_checksum(0xFE, 0)),
217 [0, 1])
218
219 # Check second half of first bucket
220 self.assertEquals(get_range(make_checksum(0x02, 0), make_checksum(0xFE, 0)),
221 [2, 3])
222
223 # Check first half of last bucket
224 self.assertEquals(get_range(make_checksum(0xFC, 0), make_checksum(0xFE, 0)),
225 [252, 253])
226
227 # Check second half of last bucket
228 self.assertEquals(get_range(make_checksum(0xFE, 0), make_checksum(0xFE, 0)),
229 [254, 255])
230
231 # Check first two buckets
232 self.assertEquals(get_range(make_checksum(0, 0), make_checksum(0xF8, 0)),
233 [0, 1, 2, 3, 4, 5, 6, 7])
234
235 # Check last two buckets
236 self.assertEquals(get_range(make_checksum(0xF8, 0), make_checksum(0xF8, 0)),
237 [248, 249, 250, 251, 252, 253, 254, 255])
238
239 # Check matching on low bits
240 self.assertEquals(get_range(make_checksum(0x00, 0x00), ~1), [0])
241 self.assertEquals(get_range(make_checksum(0x01, 0x00), ~1), [1])
242 self.assertEquals(get_range(make_checksum(0x01, 0x02), ~1), [])
243
244
Rich Laneb2c5bf62014-01-06 17:18:40 -0800245class EntryDescStats(BaseGenTableTest):
246 """
247 Test retrieving entry desc stats
248 """
249 def runTest(self):
250 # Add a few entries
251 for i in range(0, 3):
252 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i),
253 checksum=0xfedcba9876543210fedcba9876543210 + i)
254
255 do_barrier(self.controller)
256 verify_no_errors(self.controller)
257
258 entries = self.do_entry_desc_stats()
259 seen = set()
260 for entry in entries:
261 logging.debug(entry.show())
262 key = tlv_dict(entry.key)
263 value = tlv_dict(entry.value)
264 self.assertIn(ofp.bsn_tlv.vlan_vid, key)
265 self.assertIn(ofp.bsn_tlv.ipv4, key)
266 self.assertIn(ofp.bsn_tlv.mac, value)
267 vlan_vid = key[ofp.bsn_tlv.vlan_vid]
268 seen.add(vlan_vid)
269 self.assertEqual(key[ofp.bsn_tlv.ipv4], 0x12345678)
270 self.assertEqual(value[ofp.bsn_tlv.mac], [0, 1, 2, 3, 4, vlan_vid])
271 self.assertEqual(entry.checksum, 0xfedcba9876543210fedcba9876543210 + vlan_vid)
272
273 self.assertEquals(seen, set([0, 1, 2]))
Rich Lane4e691ad2014-01-06 17:45:20 -0800274
Rich Lane790cc202014-01-08 14:54:25 -0800275class EntryDescStatsMasked(BaseGenTableTest):
276 """
277 Test retrieving entry desc stats with a checksum mask
278 """
279 def runTest(self):
280 def get_range(checksum, checksum_mask):
281 entries = self.do_entry_desc_stats(checksum, checksum_mask)
282 vlan_vids = []
283 for entry in entries:
284 key = tlv_dict(entry.key)
285 vlan_vids.append(key[ofp.bsn_tlv.vlan_vid])
286 return sorted(vlan_vids)
287
288 # Add 4 entries to each checksum bucket
289 for i in range(0, 256):
290 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i),
291 checksum=make_checksum(i, i*31))
292
293 do_barrier(self.controller)
294 verify_no_errors(self.controller)
295
296 # Check first bucket
297 self.assertEquals(get_range(make_checksum(0, 0), make_checksum(0xFC, 0)),
298 [0, 1, 2, 3])
299
300 # Check last bucket
301 self.assertEquals(get_range(make_checksum(0xFC, 0), make_checksum(0xFC, 0)),
302 [252, 253, 254, 255])
303
304 # Check first half of first bucket
305 self.assertEquals(get_range(make_checksum(0x00, 0), make_checksum(0xFE, 0)),
306 [0, 1])
307
308 # Check second half of first bucket
309 self.assertEquals(get_range(make_checksum(0x02, 0), make_checksum(0xFE, 0)),
310 [2, 3])
311
312 # Check first half of last bucket
313 self.assertEquals(get_range(make_checksum(0xFC, 0), make_checksum(0xFE, 0)),
314 [252, 253])
315
316 # Check second half of last bucket
317 self.assertEquals(get_range(make_checksum(0xFE, 0), make_checksum(0xFE, 0)),
318 [254, 255])
319
320 # Check first two buckets
321 self.assertEquals(get_range(make_checksum(0, 0), make_checksum(0xF8, 0)),
322 [0, 1, 2, 3, 4, 5, 6, 7])
323
324 # Check last two buckets
325 self.assertEquals(get_range(make_checksum(0xF8, 0), make_checksum(0xF8, 0)),
326 [248, 249, 250, 251, 252, 253, 254, 255])
327
328 # Check matching on low bits
329 self.assertEquals(get_range(make_checksum(0x00, 0x00), ~1), [0])
330 self.assertEquals(get_range(make_checksum(0x01, 0x00), ~1), [1])
331 self.assertEquals(get_range(make_checksum(0x01, 0x02), ~1), [])
332
Rich Lane4e691ad2014-01-06 17:45:20 -0800333class TableDescStats(BaseGenTableTest):
334 """
335 Test retrieving table desc stats
336 """
337 def runTest(self):
338 entries = self.do_table_desc_stats()
339 seen = set()
340 for entry in entries:
341 logging.debug(entry.show())
342 self.assertNotIn(entry.table_id, seen)
343 self.assertNotIn(entry.name, seen)
344 seen.add(entry.table_id)
345 seen.add(entry.name)
346 if entry.table_id == TABLE_ID:
347 self.assertEqual(entry.name, "test")
348 self.assertEqual(entry.buckets_size, 64)
349 self.assertEqual(entry.max_entries, 1000)
350
351 self.assertIn(TABLE_ID, seen)
Rich Lanea8f56672014-01-06 17:50:39 -0800352
353class TableStats(BaseGenTableTest):
354 """
355 Test retrieving table stats
356 """
357 def runTest(self):
Rich Lane64c4e602014-01-07 11:27:06 -0800358 # Verify we have the test table and no duplicates
Rich Lanea8f56672014-01-06 17:50:39 -0800359 entries = self.do_table_stats()
360 seen = set()
361 for entry in entries:
362 logging.debug(entry.show())
363 self.assertNotIn(entry.table_id, seen)
364 seen.add(entry.table_id)
365 if entry.table_id == TABLE_ID:
366 self.assertEqual(entry.entry_count, 0)
367 self.assertEqual(entry.checksum, 0)
Rich Lanea8f56672014-01-06 17:50:39 -0800368 self.assertIn(TABLE_ID, seen)
Rich Lane64c4e602014-01-07 11:27:06 -0800369
370 table_checksum = 0
371
372 # Add a bunch of entries, spread among the checksum buckets
373 for i in range(0, 256):
374 table_checksum ^= make_checksum(i, i*31)
375 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i),
376 checksum=make_checksum(i, i*31))
377
378 do_barrier(self.controller)
379 verify_no_errors(self.controller)
380
381 table_stats = self.do_test_table_stats()
382 self.assertEqual(table_stats.entry_count, 256)
383 self.assertEqual(table_stats.checksum, table_checksum)
384
385 # Modify an entry, changing its checksum
386 i = 30
387 table_checksum ^= make_checksum(i, i*31) # subtract old checksum
388 table_checksum ^= make_checksum(i, i*37) # add new checksum
389 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 4, 3, 2, 1, i),
390 checksum=make_checksum(i, i*37))
391
392 do_barrier(self.controller)
393 verify_no_errors(self.controller)
394
395 table_stats = self.do_test_table_stats()
396 self.assertEqual(table_stats.entry_count, 256)
397 self.assertEqual(table_stats.checksum, table_checksum)
398
399 # Delete an entry
400 i = 87
401 table_checksum ^= make_checksum(i, i*31)
402 self.do_delete(vlan_vid=i, ipv4=0x12345678)
403
404 do_barrier(self.controller)
405 verify_no_errors(self.controller)
406
407 table_stats = self.do_test_table_stats()
408 self.assertEqual(table_stats.entry_count, 255)
409 self.assertEqual(table_stats.checksum, table_checksum)
Rich Lane232d2ab2014-01-07 12:23:16 -0800410
411class BucketStats(BaseGenTableTest):
412 """
413 Test retrieving checksum bucket stats
414 """
415 def runTest(self):
416 # Verify initial state
417 entries = self.do_bucket_stats()
418 self.assertEquals(len(entries), 64)
419 for entry in entries:
420 self.assertEquals(entry.checksum, 0)
421
422 buckets = [0] * len(entries)
423 checksum_bits = int(math.log(len(buckets), 2))
424
425 def update_bucket(checksum):
426 index = checksum >> (128 - checksum_bits)
427 buckets[index] ^= checksum
428
429 # Add a bunch of entries, spread among the checksum buckets
430 for i in range(0, 256):
431 update_bucket(make_checksum(i, i*31))
432 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i),
433 checksum=make_checksum(i, i*31))
434
435 entries = self.do_bucket_stats()
436 self.assertEquals(len(entries), 64)
437 for i, entry in enumerate(entries):
438 self.assertEquals(entry.checksum, buckets[i])
439
440 # Modify an entry, changing its checksum
441 i = 30
442 update_bucket(make_checksum(i, i*31)) # subtract old checksum
443 update_bucket(make_checksum(i, i*37)) # add new checksum
444 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 4, 3, 2, 1, i),
445 checksum=make_checksum(i, i*37))
446
447 do_barrier(self.controller)
448 verify_no_errors(self.controller)
449
450 entries = self.do_bucket_stats()
451 self.assertEquals(len(entries), 64)
452 for i, entry in enumerate(entries):
453 self.assertEquals(entry.checksum, buckets[i])
454
455 # Delete an entry
456 i = 87
457 update_bucket(make_checksum(i, i*31))
458 self.do_delete(vlan_vid=i, ipv4=0x12345678)
459
460 do_barrier(self.controller)
461 verify_no_errors(self.controller)
462
463 entries = self.do_bucket_stats()
464 self.assertEquals(len(entries), 64)
465 for i, entry in enumerate(entries):
466 self.assertEquals(entry.checksum, buckets[i])
Rich Lane78bd3772014-01-08 11:51:13 -0800467
468class SetBucketsSize(BaseGenTableTest):
469 """
470 Test setting the checksum buckets size
471 """
472 def setUp(self):
473 BaseGenTableTest.setUp(self)
474 self.do_set_buckets_size(64)
475 do_barrier(self.controller)
476
477 def tearDown(self):
478 self.do_set_buckets_size(64)
479 do_barrier(self.controller)
480 BaseGenTableTest.tearDown(self)
481
482 def runTest(self):
483 # Verify initial state
484 entries = self.do_bucket_stats()
485 self.assertEquals(len(entries), 64)
486 for entry in entries:
487 self.assertEquals(entry.checksum, 0)
488
489 buckets32 = [0] * 32
490 buckets64 = [0] * 64
491
492 def update_bucket(checksum):
493 buckets32[checksum >> (128 - int(math.log(32, 2)))] ^= checksum
494 buckets64[checksum >> (128 - int(math.log(64, 2)))] ^= checksum
495
496 # Add a bunch of entries, spread among the checksum buckets
497 for i in range(0, 256):
498 update_bucket(make_checksum(i, i*31))
499 self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i),
500 checksum=make_checksum(i, i*31))
501
502 entries = self.do_bucket_stats()
503 self.assertEquals(len(entries), 64)
504 for i, entry in enumerate(entries):
505 self.assertEquals(entry.checksum, buckets64[i])
506
507 self.do_set_buckets_size(32)
508 do_barrier(self.controller)
509
510 entries = self.do_bucket_stats()
511 self.assertEquals(len(entries), 32)
512 for i, entry in enumerate(entries):
513 self.assertEquals(entry.checksum, buckets32[i])
514
515 self.do_set_buckets_size(64)
516 do_barrier(self.controller)
517
518 entries = self.do_bucket_stats()
519 self.assertEquals(len(entries), 64)
520 for i, entry in enumerate(entries):
521 self.assertEquals(entry.checksum, buckets64[i])