bsn_gentable: add BucketStats test
diff --git a/tests-1.3/bsn_gentable.py b/tests-1.3/bsn_gentable.py
index 8e4d932..0ea0443 100644
--- a/tests-1.3/bsn_gentable.py
+++ b/tests-1.3/bsn_gentable.py
@@ -5,6 +5,7 @@
 """
 
 import logging
+import math
 
 from oftest import config
 import oftest.base_tests as base_tests
@@ -97,6 +98,10 @@
                 return entry
         raise AssertionError("did not find test table")
 
+    def do_bucket_stats(self):
+        request = ofp.message.bsn_gentable_bucket_stats_request(table_id=TABLE_ID)
+        return get_stats(self, request)
+
 class ClearAll(BaseGenTableTest):
     """
     Test clearing entire table
@@ -279,3 +284,60 @@
         table_stats = self.do_test_table_stats()
         self.assertEqual(table_stats.entry_count, 255)
         self.assertEqual(table_stats.checksum, table_checksum)
+
+class BucketStats(BaseGenTableTest):
+    """
+    Test retrieving checksum bucket stats
+    """
+    def runTest(self):
+        # Verify initial state
+        entries = self.do_bucket_stats()
+        self.assertEquals(len(entries), 64)
+        for entry in entries:
+            self.assertEquals(entry.checksum, 0)
+
+        buckets = [0] * len(entries)
+        checksum_bits = int(math.log(len(buckets), 2))
+
+        def update_bucket(checksum):
+            index = checksum >> (128 - checksum_bits)
+            buckets[index] ^= checksum
+
+        # Add a bunch of entries, spread among the checksum buckets
+        for i in range(0, 256):
+            update_bucket(make_checksum(i, i*31))
+            self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 1, 2, 3, 4, i),
+                        checksum=make_checksum(i, i*31))
+
+        entries = self.do_bucket_stats()
+        self.assertEquals(len(entries), 64)
+        for i, entry in enumerate(entries):
+            self.assertEquals(entry.checksum, buckets[i])
+
+        # Modify an entry, changing its checksum
+        i = 30
+        update_bucket(make_checksum(i, i*31)) # subtract old checksum
+        update_bucket(make_checksum(i, i*37)) # add new checksum
+        self.do_add(vlan_vid=i, ipv4=0x12345678, mac=(0, 4, 3, 2, 1, i),
+                    checksum=make_checksum(i, i*37))
+
+        do_barrier(self.controller)
+        verify_no_errors(self.controller)
+
+        entries = self.do_bucket_stats()
+        self.assertEquals(len(entries), 64)
+        for i, entry in enumerate(entries):
+            self.assertEquals(entry.checksum, buckets[i])
+
+        # Delete an entry
+        i = 87
+        update_bucket(make_checksum(i, i*31))
+        self.do_delete(vlan_vid=i, ipv4=0x12345678)
+
+        do_barrier(self.controller)
+        verify_no_errors(self.controller)
+
+        entries = self.do_bucket_stats()
+        self.assertEquals(len(entries), 64)
+        for i, entry in enumerate(entries):
+            self.assertEquals(entry.checksum, buckets[i])