Merge into master from pull request #107:
Verifiy configuration flag (https://github.com/floodlight/oftest/pull/107)
diff --git a/oft b/oft
index 8a7272b..9d5df6a 100755
--- a/oft
+++ b/oft
@@ -77,14 +77,17 @@
     "log_file"           : "oft.log",
     "log_dir"            : None,
     "debug"              : "verbose",
+    "profile"            : False,
 
     # Test behavior options
     "relax"              : False,
     "test_params"        : "None",
     "fail_skipped"       : False,
-    "default_timeout"    : 2,
+    "default_timeout"    : 2.0,
+    "default_negative_timeout" : 0.01,
     "minsize"            : 0,
     "random_seed"        : None,
+    "disable_ipv6"       : False,
 
     # Other configuration
     "port_map"           : {},
@@ -178,6 +181,7 @@
                      const="verbose", help="Shortcut for --debug=verbose")
     group.add_option("-q", "--quiet", action="store_const", dest="debug",
                      const="warning", help="Shortcut for --debug=warning")
+    group.add_option("--profile", action="store_true", help="Write Python profile to profile.out")
     parser.add_option_group(group)
 
     group = optparse.OptionGroup(parser, "Test behavior options")
@@ -188,12 +192,16 @@
     group.add_option("-t", "--test-params", help=test_params_help)
     group.add_option("--fail-skipped", action="store_true",
                       help="Return failure if any test was skipped")
-    group.add_option("--default-timeout", type="int",
+    group.add_option("--default-timeout", type=float,
                       help="Timeout in seconds for most operations")
+    group.add_option("--default-negative-timeout", type=float,
+                      help="Timeout in seconds for negative checks")
     group.add_option("--minsize", type="int",
                       help="Minimum allowable packet size on the dataplane.")
     group.add_option("--random-seed", type="int",
                       help="Random number generator seed")
+    group.add_option("--disable-ipv6", action="store_true",
+                      help="Disable IPv6 tests")
     parser.add_option_group(group)
 
     # Might need this if other parsers want command line
@@ -488,6 +496,7 @@
 logging.info("OF port map: " + str(config["port_map"]))
 
 oftest.ofutils.default_timeout = config["default_timeout"]
+oftest.ofutils.default_negative_timeout = config["default_negative_timeout"]
 oftest.testutils.MINSIZE = config['minsize']
 
 if os.getuid() != 0 and not config["allow_user"]:
@@ -509,6 +518,11 @@
 signal.signal(signal.SIGINT, signal.SIG_DFL)
 
 if __name__ == "__main__":
+    if config["profile"]:
+        import cProfile
+        profiler = cProfile.Profile()
+        profiler.enable()
+
     # Set up the dataplane
     oftest.dataplane_instance = oftest.dataplane.DataPlane(config)
     pcap_setup(config)
@@ -529,6 +543,10 @@
     oftest.dataplane_instance.kill()
     oftest.dataplane_instance = None
 
+    if config["profile"]:
+        profiler.disable()
+        profiler.dump_stats("profile.out")
+
     if result.failures or result.errors:
         # exit(1) hangs sometimes
         os._exit(1)
diff --git a/src/python/loxi/of12/oxm.py b/src/python/loxi/of12/oxm.py
index f116d1a..9f12fc9 100644
--- a/src/python/loxi/of12/oxm.py
+++ b/src/python/loxi/of12/oxm.py
@@ -517,6 +517,98 @@
 
 oxm.subtypes[2147495688] = arp_tpa_masked
 
+class bsn_egr_port_group_id(oxm):
+    type_len = 200196
+
+    def __init__(self, value=None):
+        if value != None:
+            self.value = value
+        else:
+            self.value = 0
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!L", self.type_len))
+        packed.append(struct.pack("!L", self.value))
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_egr_port_group_id()
+        _type_len = reader.read("!L")[0]
+        assert(_type_len == 200196)
+        obj.value = reader.read("!L")[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.value != other.value: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_egr_port_group_id {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("value = ");
+                q.text("%#x" % self.value)
+            q.breakable()
+        q.text('}')
+
+oxm.subtypes[200196] = bsn_egr_port_group_id
+
+class bsn_egr_port_group_id_masked(oxm):
+    type_len = 200456
+
+    def __init__(self, value=None, value_mask=None):
+        if value != None:
+            self.value = value
+        else:
+            self.value = 0
+        if value_mask != None:
+            self.value_mask = value_mask
+        else:
+            self.value_mask = 0
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!L", self.type_len))
+        packed.append(struct.pack("!L", self.value))
+        packed.append(struct.pack("!L", self.value_mask))
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_egr_port_group_id_masked()
+        _type_len = reader.read("!L")[0]
+        assert(_type_len == 200456)
+        obj.value = reader.read("!L")[0]
+        obj.value_mask = reader.read("!L")[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.value != other.value: return False
+        if self.value_mask != other.value_mask: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_egr_port_group_id_masked {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("value = ");
+                q.text("%#x" % self.value)
+                q.text(","); q.breakable()
+                q.text("value_mask = ");
+                q.text("%#x" % self.value_mask)
+            q.breakable()
+        q.text('}')
+
+oxm.subtypes[200456] = bsn_egr_port_group_id_masked
+
 class bsn_global_vrf_allowed(oxm):
     type_len = 198145
 
diff --git a/src/python/loxi/of13/action_id.py b/src/python/loxi/of13/action_id.py
index e0e495e..b1519f0 100644
--- a/src/python/loxi/of13/action_id.py
+++ b/src/python/loxi/of13/action_id.py
@@ -35,7 +35,6 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
-        packed.append('\x00' * 4)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -52,7 +51,6 @@
         _len = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_len - (2 + 2))
-        reader.skip(4)
         return obj
 
     def __eq__(self, other):
@@ -140,7 +138,6 @@
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
         packed.append(struct.pack("!L", self.experimenter))
         packed.append(struct.pack("!L", self.subtype))
-        packed.append('\x00' * 4)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -161,7 +158,6 @@
         _experimenter = reader.read("!L")[0]
         assert(_experimenter == 6035143)
         obj.subtype = reader.read("!L")[0]
-        reader.skip(4)
         return obj
 
     def __eq__(self, other):
@@ -193,7 +189,6 @@
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
         packed.append(struct.pack("!L", self.experimenter))
         packed.append(struct.pack("!L", self.subtype))
-        packed.append('\x00' * 3)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -210,7 +205,6 @@
         assert(_experimenter == 6035143)
         _subtype = reader.read("!L")[0]
         assert(_subtype == 1)
-        reader.skip(3)
         return obj
 
     def __eq__(self, other):
@@ -283,7 +277,6 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
-        packed.append('\x00' * 4)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -296,7 +289,6 @@
         _len = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_len - (2 + 2))
-        reader.skip(4)
         return obj
 
     def __eq__(self, other):
@@ -323,7 +315,6 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
-        packed.append('\x00' * 4)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -336,7 +327,6 @@
         _len = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_len - (2 + 2))
-        reader.skip(4)
         return obj
 
     def __eq__(self, other):
@@ -363,7 +353,6 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
-        packed.append('\x00' * 4)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -376,7 +365,6 @@
         _len = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_len - (2 + 2))
-        reader.skip(4)
         return obj
 
     def __eq__(self, other):
@@ -403,7 +391,6 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
-        packed.append('\x00' * 4)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -416,7 +403,6 @@
         _len = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_len - (2 + 2))
-        reader.skip(4)
         return obj
 
     def __eq__(self, other):
@@ -490,8 +476,6 @@
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
         packed.append(struct.pack("!L", self.experimenter))
         packed.append(struct.pack("!H", self.subtype))
-        packed.append('\x00' * 2)
-        packed.append('\x00' * 4)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -512,8 +496,6 @@
         _experimenter = reader.read("!L")[0]
         assert(_experimenter == 8992)
         obj.subtype = reader.read("!H")[0]
-        reader.skip(2)
-        reader.skip(4)
         return obj
 
     def __eq__(self, other):
@@ -545,8 +527,6 @@
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
         packed.append(struct.pack("!L", self.experimenter))
         packed.append(struct.pack("!H", self.subtype))
-        packed.append('\x00' * 2)
-        packed.append('\x00' * 4)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -563,8 +543,6 @@
         assert(_experimenter == 8992)
         _subtype = reader.read("!H")[0]
         assert(_subtype == 18)
-        reader.skip(2)
-        reader.skip(4)
         return obj
 
     def __eq__(self, other):
@@ -591,7 +569,6 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
-        packed.append('\x00' * 6)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -604,7 +581,6 @@
         _len = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_len - (2 + 2))
-        reader.skip(6)
         return obj
 
     def __eq__(self, other):
@@ -631,7 +607,6 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
-        packed.append('\x00' * 2)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -644,7 +619,6 @@
         _len = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_len - (2 + 2))
-        reader.skip(2)
         return obj
 
     def __eq__(self, other):
@@ -671,7 +645,6 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
-        packed.append('\x00' * 4)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -684,7 +657,6 @@
         _len = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_len - (2 + 2))
-        reader.skip(4)
         return obj
 
     def __eq__(self, other):
@@ -711,7 +683,6 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
-        packed.append('\x00' * 4)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -724,7 +695,6 @@
         _len = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_len - (2 + 2))
-        reader.skip(4)
         return obj
 
     def __eq__(self, other):
@@ -751,7 +721,6 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
-        packed.append('\x00' * 2)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -764,7 +733,6 @@
         _len = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_len - (2 + 2))
-        reader.skip(2)
         return obj
 
     def __eq__(self, other):
@@ -791,7 +759,6 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
-        packed.append('\x00' * 2)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -804,7 +771,6 @@
         _len = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_len - (2 + 2))
-        reader.skip(2)
         return obj
 
     def __eq__(self, other):
@@ -831,7 +797,6 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
-        packed.append('\x00' * 2)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -844,7 +809,6 @@
         _len = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_len - (2 + 2))
-        reader.skip(2)
         return obj
 
     def __eq__(self, other):
@@ -909,7 +873,6 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
-        packed.append('\x00' * 3)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -922,7 +885,6 @@
         _len = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_len - (2 + 2))
-        reader.skip(3)
         return obj
 
     def __eq__(self, other):
@@ -949,7 +911,6 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
-        packed.append('\x00' * 3)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -962,7 +923,6 @@
         _len = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_len - (2 + 2))
-        reader.skip(3)
         return obj
 
     def __eq__(self, other):
diff --git a/src/python/loxi/of13/bsn_tlv.py b/src/python/loxi/of13/bsn_tlv.py
index dd3eced..f169a6d 100644
--- a/src/python/loxi/of13/bsn_tlv.py
+++ b/src/python/loxi/of13/bsn_tlv.py
@@ -114,6 +114,53 @@
 
 bsn_tlv.subtypes[10] = broadcast_query_timeout
 
+class circuit_id(bsn_tlv):
+    type = 14
+
+    def __init__(self, value=None):
+        if value != None:
+            self.value = value
+        else:
+            self.value = ''
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!H", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for length at index 1
+        packed.append(self.value)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = circuit_id()
+        _type = reader.read("!H")[0]
+        assert(_type == 14)
+        _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
+        obj.value = str(reader.read_all())
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.value != other.value: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("circuit_id {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("value = ");
+                q.pp(self.value)
+            q.breakable()
+        q.text('}')
+
+bsn_tlv.subtypes[14] = circuit_id
+
 class idle_notification(bsn_tlv):
     type = 7
 
diff --git a/src/python/loxi/of13/common.py b/src/python/loxi/of13/common.py
index be5f8cd..c206d24 100644
--- a/src/python/loxi/of13/common.py
+++ b/src/python/loxi/of13/common.py
@@ -88,6 +88,42 @@
         q.text('}')
 
 
+class bsn_flow_checksum_bucket_stats_entry(loxi.OFObject):
+
+    def __init__(self, checksum=None):
+        if checksum != None:
+            self.checksum = checksum
+        else:
+            self.checksum = 0
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!Q", self.checksum))
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_flow_checksum_bucket_stats_entry()
+        obj.checksum = reader.read("!Q")[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.checksum != other.checksum: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_flow_checksum_bucket_stats_entry {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("checksum = ");
+                q.text("%#x" % self.checksum)
+            q.breakable()
+        q.text('}')
+
+
 class bsn_gentable_bucket_stats_entry(loxi.OFObject):
 
     def __init__(self, checksum=None):
@@ -684,6 +720,52 @@
         q.text('}')
 
 
+class bsn_table_checksum_stats_entry(loxi.OFObject):
+
+    def __init__(self, table_id=None, checksum=None):
+        if table_id != None:
+            self.table_id = table_id
+        else:
+            self.table_id = 0
+        if checksum != None:
+            self.checksum = checksum
+        else:
+            self.checksum = 0
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!B", self.table_id))
+        packed.append(struct.pack("!Q", self.checksum))
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_table_checksum_stats_entry()
+        obj.table_id = reader.read("!B")[0]
+        obj.checksum = reader.read("!Q")[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.table_id != other.table_id: return False
+        if self.checksum != other.checksum: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_table_checksum_stats_entry {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("table_id = ");
+                q.text("%#x" % self.table_id)
+                q.text(","); q.breakable()
+                q.text("checksum = ");
+                q.text("%#x" % self.checksum)
+            q.breakable()
+        q.text('}')
+
+
 class bsn_vport(loxi.OFObject):
     subtypes = {}
 
@@ -1002,56 +1084,6 @@
         q.text('}')
 
 
-class experimenter_stats_header(loxi.OFObject):
-    subtypes = {}
-
-
-    def __init__(self, experimenter=None, subtype=None):
-        if experimenter != None:
-            self.experimenter = experimenter
-        else:
-            self.experimenter = 0
-        if subtype != None:
-            self.subtype = subtype
-        else:
-            self.subtype = 0
-        return
-
-    def pack(self):
-        packed = []
-        packed.append(struct.pack("!L", self.experimenter))
-        packed.append(struct.pack("!L", self.subtype))
-        return ''.join(packed)
-
-    @staticmethod
-    def unpack(reader):
-        subtype, = reader.peek('!L', 0)
-        subclass = experimenter_stats_header.subtypes.get(subtype)
-        if subclass:
-            return subclass.unpack(reader)
-
-        obj = experimenter_stats_header()
-        obj.experimenter = reader.read("!L")[0]
-        obj.subtype = reader.read("!L")[0]
-        return obj
-
-    def __eq__(self, other):
-        if type(self) != type(other): return False
-        if self.experimenter != other.experimenter: return False
-        if self.subtype != other.subtype: return False
-        return True
-
-    def pretty_print(self, q):
-        q.text("experimenter_stats_header {")
-        with q.group():
-            with q.indent(2):
-                q.breakable()
-                q.text("subtype = ");
-                q.text("%#x" % self.subtype)
-            q.breakable()
-        q.text('}')
-
-
 class flow_stats_entry(loxi.OFObject):
 
     def __init__(self, table_id=None, duration_sec=None, duration_nsec=None, priority=None, idle_timeout=None, hard_timeout=None, flags=None, cookie=None, packet_count=None, byte_count=None, match=None, instructions=None):
@@ -2740,7 +2772,7 @@
 table_feature_prop.subtypes[15] = table_feature_prop_apply_setfield_miss
 
 class table_feature_prop_experimenter(table_feature_prop):
-    type = 65535
+    type = 65534
 
     def __init__(self, experimenter=None, subtype=None, experimenter_data=None):
         if experimenter != None:
@@ -2772,7 +2804,7 @@
     def unpack(reader):
         obj = table_feature_prop_experimenter()
         _type = reader.read("!H")[0]
-        assert(_type == 65535)
+        assert(_type == 65534)
         _length = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_length - (2 + 2))
@@ -2804,7 +2836,74 @@
             q.breakable()
         q.text('}')
 
-table_feature_prop.subtypes[65535] = table_feature_prop_experimenter
+table_feature_prop.subtypes[65534] = table_feature_prop_experimenter
+
+class table_feature_prop_experimenter_miss(table_feature_prop):
+    type = 65535
+
+    def __init__(self, experimenter=None, subtype=None, experimenter_data=None):
+        if experimenter != None:
+            self.experimenter = experimenter
+        else:
+            self.experimenter = 0
+        if subtype != None:
+            self.subtype = subtype
+        else:
+            self.subtype = 0
+        if experimenter_data != None:
+            self.experimenter_data = experimenter_data
+        else:
+            self.experimenter_data = ''
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!H", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for length at index 1
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        packed.append(self.experimenter_data)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = table_feature_prop_experimenter_miss()
+        _type = reader.read("!H")[0]
+        assert(_type == 65535)
+        _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
+        obj.experimenter = reader.read("!L")[0]
+        obj.subtype = reader.read("!L")[0]
+        obj.experimenter_data = str(reader.read_all())
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.experimenter != other.experimenter: return False
+        if self.subtype != other.subtype: return False
+        if self.experimenter_data != other.experimenter_data: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("table_feature_prop_experimenter_miss {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("experimenter = ");
+                q.text("%#x" % self.experimenter)
+                q.text(","); q.breakable()
+                q.text("subtype = ");
+                q.text("%#x" % self.subtype)
+                q.text(","); q.breakable()
+                q.text("experimenter_data = ");
+                q.pp(self.experimenter_data)
+            q.breakable()
+        q.text('}')
+
+table_feature_prop.subtypes[65535] = table_feature_prop_experimenter_miss
 
 class table_feature_prop_instructions(table_feature_prop):
     type = 0
@@ -2833,7 +2932,7 @@
         _length = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_length - (2 + 2))
-        obj.instruction_ids = loxi.generic_util.unpack_list(reader, instruction.instruction.unpack)
+        obj.instruction_ids = loxi.generic_util.unpack_list(reader, instruction_id.instruction_id.unpack)
         return obj
 
     def __eq__(self, other):
@@ -2880,7 +2979,7 @@
         _length = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_length - (2 + 2))
-        obj.instruction_ids = loxi.generic_util.unpack_list(reader, instruction.instruction.unpack)
+        obj.instruction_ids = loxi.generic_util.unpack_list(reader, instruction_id.instruction_id.unpack)
         return obj
 
     def __eq__(self, other):
diff --git a/src/python/loxi/of13/const.py b/src/python/loxi/of13/const.py
index 404d582..cae3396 100644
--- a/src/python/loxi/of13/const.py
+++ b/src/python/loxi/of13/const.py
@@ -692,6 +692,9 @@
 OFPR_BSN_DEST_PORT_UNREACHABLE = 136
 OFPR_BSN_FRAGMENTATION_REQUIRED = 137
 OFPR_BSN_ARP = 139
+OFPR_BSN_DHCP = 140
+OFPR_BSN_DEBUG = 141
+OFPR_BSN_PACKET_OF_DEATH = 142
 
 ofp_packet_in_reason_map = {
     0: 'OFPR_NO_MATCH',
@@ -708,6 +711,9 @@
     136: 'OFPR_BSN_DEST_PORT_UNREACHABLE',
     137: 'OFPR_BSN_FRAGMENTATION_REQUIRED',
     139: 'OFPR_BSN_ARP',
+    140: 'OFPR_BSN_DHCP',
+    141: 'OFPR_BSN_DEBUG',
+    142: 'OFPR_BSN_PACKET_OF_DEATH',
 }
 
 # Identifiers from group ofp_port
diff --git a/src/python/loxi/of13/instruction.py b/src/python/loxi/of13/instruction.py
index 5d36bda..bc06252 100644
--- a/src/python/loxi/of13/instruction.py
+++ b/src/python/loxi/of13/instruction.py
@@ -283,6 +283,150 @@
 
 bsn.subtypes[1] = bsn_arp_offload
 
+class bsn_deny(bsn):
+    type = 65535
+    experimenter = 6035143
+    subtype = 5
+
+    def __init__(self):
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!H", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        packed.append('\x00' * 4)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_deny()
+        _type = reader.read("!H")[0]
+        assert(_type == 65535)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        _experimenter = reader.read("!L")[0]
+        assert(_experimenter == 6035143)
+        _subtype = reader.read("!L")[0]
+        assert(_subtype == 5)
+        reader.skip(4)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_deny {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+bsn.subtypes[5] = bsn_deny
+
+class bsn_dhcp_offload(bsn):
+    type = 65535
+    experimenter = 6035143
+    subtype = 2
+
+    def __init__(self):
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!H", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        packed.append('\x00' * 4)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_dhcp_offload()
+        _type = reader.read("!H")[0]
+        assert(_type == 65535)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        _experimenter = reader.read("!L")[0]
+        assert(_experimenter == 6035143)
+        _subtype = reader.read("!L")[0]
+        assert(_subtype == 2)
+        reader.skip(4)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_dhcp_offload {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+bsn.subtypes[2] = bsn_dhcp_offload
+
+class bsn_disable_split_horizon_check(bsn):
+    type = 65535
+    experimenter = 6035143
+    subtype = 3
+
+    def __init__(self):
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!H", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        packed.append('\x00' * 4)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_disable_split_horizon_check()
+        _type = reader.read("!H")[0]
+        assert(_type == 65535)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        _experimenter = reader.read("!L")[0]
+        assert(_experimenter == 6035143)
+        _subtype = reader.read("!L")[0]
+        assert(_subtype == 3)
+        reader.skip(4)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_disable_split_horizon_check {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+bsn.subtypes[3] = bsn_disable_split_horizon_check
+
 class bsn_disable_src_mac_check(bsn):
     type = 65535
     experimenter = 6035143
@@ -331,6 +475,102 @@
 
 bsn.subtypes[0] = bsn_disable_src_mac_check
 
+class bsn_packet_of_death(bsn):
+    type = 65535
+    experimenter = 6035143
+    subtype = 6
+
+    def __init__(self):
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!H", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        packed.append('\x00' * 4)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_packet_of_death()
+        _type = reader.read("!H")[0]
+        assert(_type == 65535)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        _experimenter = reader.read("!L")[0]
+        assert(_experimenter == 6035143)
+        _subtype = reader.read("!L")[0]
+        assert(_subtype == 6)
+        reader.skip(4)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_packet_of_death {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+bsn.subtypes[6] = bsn_packet_of_death
+
+class bsn_permit(bsn):
+    type = 65535
+    experimenter = 6035143
+    subtype = 4
+
+    def __init__(self):
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!H", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        packed.append('\x00' * 4)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_permit()
+        _type = reader.read("!H")[0]
+        assert(_type == 65535)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        _experimenter = reader.read("!L")[0]
+        assert(_experimenter == 6035143)
+        _subtype = reader.read("!L")[0]
+        assert(_subtype == 4)
+        reader.skip(4)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_permit {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+bsn.subtypes[4] = bsn_permit
+
 class clear_actions(instruction):
     type = 5
 
diff --git a/src/python/loxi/of13/instruction_id.py b/src/python/loxi/of13/instruction_id.py
index 2c101a1..7d64a9a 100644
--- a/src/python/loxi/of13/instruction_id.py
+++ b/src/python/loxi/of13/instruction_id.py
@@ -77,7 +77,6 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
-        packed.append('\x00' * 4)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -90,7 +89,6 @@
         _len = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_len - (2 + 2))
-        reader.skip(4)
         return obj
 
     def __eq__(self, other):
@@ -178,7 +176,6 @@
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
         packed.append(struct.pack("!L", self.experimenter))
         packed.append(struct.pack("!L", self.subtype))
-        packed.append('\x00' * 4)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -199,7 +196,6 @@
         _experimenter = reader.read("!L")[0]
         assert(_experimenter == 6035143)
         obj.subtype = reader.read("!L")[0]
-        reader.skip(4)
         return obj
 
     def __eq__(self, other):
@@ -231,7 +227,6 @@
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
         packed.append(struct.pack("!L", self.experimenter))
         packed.append(struct.pack("!L", self.subtype))
-        packed.append('\x00' * 4)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -248,7 +243,6 @@
         assert(_experimenter == 6035143)
         _subtype = reader.read("!L")[0]
         assert(_subtype == 1)
-        reader.skip(4)
         return obj
 
     def __eq__(self, other):
@@ -265,6 +259,144 @@
 
 bsn.subtypes[1] = bsn_arp_offload
 
+class bsn_deny(bsn):
+    type = 65535
+    experimenter = 6035143
+    subtype = 5
+
+    def __init__(self):
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!H", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_deny()
+        _type = reader.read("!H")[0]
+        assert(_type == 65535)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        _experimenter = reader.read("!L")[0]
+        assert(_experimenter == 6035143)
+        _subtype = reader.read("!L")[0]
+        assert(_subtype == 5)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_deny {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+bsn.subtypes[5] = bsn_deny
+
+class bsn_dhcp_offload(bsn):
+    type = 65535
+    experimenter = 6035143
+    subtype = 2
+
+    def __init__(self):
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!H", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_dhcp_offload()
+        _type = reader.read("!H")[0]
+        assert(_type == 65535)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        _experimenter = reader.read("!L")[0]
+        assert(_experimenter == 6035143)
+        _subtype = reader.read("!L")[0]
+        assert(_subtype == 2)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_dhcp_offload {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+bsn.subtypes[2] = bsn_dhcp_offload
+
+class bsn_disable_split_horizon_check(bsn):
+    type = 65535
+    experimenter = 6035143
+    subtype = 3
+
+    def __init__(self):
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!H", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_disable_split_horizon_check()
+        _type = reader.read("!H")[0]
+        assert(_type == 65535)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        _experimenter = reader.read("!L")[0]
+        assert(_experimenter == 6035143)
+        _subtype = reader.read("!L")[0]
+        assert(_subtype == 3)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_disable_split_horizon_check {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+bsn.subtypes[3] = bsn_disable_split_horizon_check
+
 class bsn_disable_src_mac_check(bsn):
     type = 65535
     experimenter = 6035143
@@ -279,7 +411,6 @@
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
         packed.append(struct.pack("!L", self.experimenter))
         packed.append(struct.pack("!L", self.subtype))
-        packed.append('\x00' * 4)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -296,7 +427,6 @@
         assert(_experimenter == 6035143)
         _subtype = reader.read("!L")[0]
         assert(_subtype == 0)
-        reader.skip(4)
         return obj
 
     def __eq__(self, other):
@@ -313,6 +443,98 @@
 
 bsn.subtypes[0] = bsn_disable_src_mac_check
 
+class bsn_packet_of_death(bsn):
+    type = 65535
+    experimenter = 6035143
+    subtype = 6
+
+    def __init__(self):
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!H", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_packet_of_death()
+        _type = reader.read("!H")[0]
+        assert(_type == 65535)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        _experimenter = reader.read("!L")[0]
+        assert(_experimenter == 6035143)
+        _subtype = reader.read("!L")[0]
+        assert(_subtype == 6)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_packet_of_death {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+bsn.subtypes[6] = bsn_packet_of_death
+
+class bsn_permit(bsn):
+    type = 65535
+    experimenter = 6035143
+    subtype = 4
+
+    def __init__(self):
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!H", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_permit()
+        _type = reader.read("!H")[0]
+        assert(_type == 65535)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        _experimenter = reader.read("!L")[0]
+        assert(_experimenter == 6035143)
+        _subtype = reader.read("!L")[0]
+        assert(_subtype == 4)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_permit {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+bsn.subtypes[4] = bsn_permit
+
 class clear_actions(instruction_id):
     type = 5
 
@@ -323,7 +545,6 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
-        packed.append('\x00' * 4)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -336,7 +557,6 @@
         _len = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_len - (2 + 2))
-        reader.skip(4)
         return obj
 
     def __eq__(self, other):
@@ -363,7 +583,6 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
-        packed.append('\x00' * 3)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -376,7 +595,6 @@
         _len = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_len - (2 + 2))
-        reader.skip(3)
         return obj
 
     def __eq__(self, other):
@@ -441,7 +659,6 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
-        packed.append('\x00' * 4)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -454,7 +671,6 @@
         _len = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_len - (2 + 2))
-        reader.skip(4)
         return obj
 
     def __eq__(self, other):
@@ -481,7 +697,6 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
-        packed.append('\x00' * 4)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
@@ -494,7 +709,6 @@
         _len = reader.read("!H")[0]
         orig_reader = reader
         reader = orig_reader.slice(_len - (2 + 2))
-        reader.skip(4)
         return obj
 
     def __eq__(self, other):
diff --git a/src/python/loxi/of13/message.py b/src/python/loxi/of13/message.py
index f4716fc..0aaeec6 100644
--- a/src/python/loxi/of13/message.py
+++ b/src/python/loxi/of13/message.py
@@ -2109,6 +2109,546 @@
 
 bsn_header.subtypes[56] = bsn_controller_connections_request
 
+class experimenter_stats_reply(stats_reply):
+    subtypes = {}
+
+    version = 4
+    type = 19
+    stats_type = 65535
+
+    def __init__(self, xid=None, flags=None, experimenter=None, subtype=None):
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        if flags != None:
+            self.flags = flags
+        else:
+            self.flags = 0
+        if experimenter != None:
+            self.experimenter = experimenter
+        else:
+            self.experimenter = 0
+        if subtype != None:
+            self.subtype = subtype
+        else:
+            self.subtype = 0
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!B", self.version))
+        packed.append(struct.pack("!B", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for length at index 2
+        packed.append(struct.pack("!L", self.xid))
+        packed.append(struct.pack("!H", self.stats_type))
+        packed.append(struct.pack("!H", self.flags))
+        packed.append('\x00' * 4)
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        length = sum([len(x) for x in packed])
+        packed[2] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 16)
+        subclass = experimenter_stats_reply.subtypes.get(subtype)
+        if subclass:
+            return subclass.unpack(reader)
+
+        obj = experimenter_stats_reply()
+        _version = reader.read("!B")[0]
+        assert(_version == 4)
+        _type = reader.read("!B")[0]
+        assert(_type == 19)
+        _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
+        obj.xid = reader.read("!L")[0]
+        _stats_type = reader.read("!H")[0]
+        assert(_stats_type == 65535)
+        obj.flags = reader.read("!H")[0]
+        reader.skip(4)
+        obj.experimenter = reader.read("!L")[0]
+        obj.subtype = reader.read("!L")[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.xid != other.xid: return False
+        if self.flags != other.flags: return False
+        if self.experimenter != other.experimenter: return False
+        if self.subtype != other.subtype: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("experimenter_stats_reply {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("xid = ");
+                if self.xid != None:
+                    q.text("%#x" % self.xid)
+                else:
+                    q.text('None')
+                q.text(","); q.breakable()
+                q.text("flags = ");
+                q.text("%#x" % self.flags)
+                q.text(","); q.breakable()
+                q.text("subtype = ");
+                q.text("%#x" % self.subtype)
+            q.breakable()
+        q.text('}')
+
+stats_reply.subtypes[65535] = experimenter_stats_reply
+
+class bsn_stats_reply(experimenter_stats_reply):
+    subtypes = {}
+
+    version = 4
+    type = 19
+    stats_type = 65535
+    experimenter = 6035143
+
+    def __init__(self, xid=None, flags=None, subtype=None):
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        if flags != None:
+            self.flags = flags
+        else:
+            self.flags = 0
+        if subtype != None:
+            self.subtype = subtype
+        else:
+            self.subtype = 0
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!B", self.version))
+        packed.append(struct.pack("!B", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for length at index 2
+        packed.append(struct.pack("!L", self.xid))
+        packed.append(struct.pack("!H", self.stats_type))
+        packed.append(struct.pack("!H", self.flags))
+        packed.append('\x00' * 4)
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        length = sum([len(x) for x in packed])
+        packed[2] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 20)
+        subclass = bsn_stats_reply.subtypes.get(subtype)
+        if subclass:
+            return subclass.unpack(reader)
+
+        obj = bsn_stats_reply()
+        _version = reader.read("!B")[0]
+        assert(_version == 4)
+        _type = reader.read("!B")[0]
+        assert(_type == 19)
+        _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
+        obj.xid = reader.read("!L")[0]
+        _stats_type = reader.read("!H")[0]
+        assert(_stats_type == 65535)
+        obj.flags = reader.read("!H")[0]
+        reader.skip(4)
+        _experimenter = reader.read("!L")[0]
+        assert(_experimenter == 6035143)
+        obj.subtype = reader.read("!L")[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.xid != other.xid: return False
+        if self.flags != other.flags: return False
+        if self.subtype != other.subtype: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_stats_reply {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("xid = ");
+                if self.xid != None:
+                    q.text("%#x" % self.xid)
+                else:
+                    q.text('None')
+                q.text(","); q.breakable()
+                q.text("flags = ");
+                q.text("%#x" % self.flags)
+            q.breakable()
+        q.text('}')
+
+experimenter_stats_reply.subtypes[6035143] = bsn_stats_reply
+
+class bsn_flow_checksum_bucket_stats_reply(bsn_stats_reply):
+    version = 4
+    type = 19
+    stats_type = 65535
+    experimenter = 6035143
+    subtype = 10
+
+    def __init__(self, xid=None, flags=None, entries=None):
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        if flags != None:
+            self.flags = flags
+        else:
+            self.flags = 0
+        if entries != None:
+            self.entries = entries
+        else:
+            self.entries = []
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!B", self.version))
+        packed.append(struct.pack("!B", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for length at index 2
+        packed.append(struct.pack("!L", self.xid))
+        packed.append(struct.pack("!H", self.stats_type))
+        packed.append(struct.pack("!H", self.flags))
+        packed.append('\x00' * 4)
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        packed.append(loxi.generic_util.pack_list(self.entries))
+        length = sum([len(x) for x in packed])
+        packed[2] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_flow_checksum_bucket_stats_reply()
+        _version = reader.read("!B")[0]
+        assert(_version == 4)
+        _type = reader.read("!B")[0]
+        assert(_type == 19)
+        _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
+        obj.xid = reader.read("!L")[0]
+        _stats_type = reader.read("!H")[0]
+        assert(_stats_type == 65535)
+        obj.flags = reader.read("!H")[0]
+        reader.skip(4)
+        _experimenter = reader.read("!L")[0]
+        assert(_experimenter == 6035143)
+        _subtype = reader.read("!L")[0]
+        assert(_subtype == 10)
+        obj.entries = loxi.generic_util.unpack_list(reader, common.bsn_flow_checksum_bucket_stats_entry.unpack)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.xid != other.xid: return False
+        if self.flags != other.flags: return False
+        if self.entries != other.entries: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_flow_checksum_bucket_stats_reply {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("xid = ");
+                if self.xid != None:
+                    q.text("%#x" % self.xid)
+                else:
+                    q.text('None')
+                q.text(","); q.breakable()
+                q.text("flags = ");
+                q.text("%#x" % self.flags)
+                q.text(","); q.breakable()
+                q.text("entries = ");
+                q.pp(self.entries)
+            q.breakable()
+        q.text('}')
+
+bsn_stats_reply.subtypes[10] = bsn_flow_checksum_bucket_stats_reply
+
+class experimenter_stats_request(stats_request):
+    subtypes = {}
+
+    version = 4
+    type = 18
+    stats_type = 65535
+
+    def __init__(self, xid=None, flags=None, experimenter=None, subtype=None):
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        if flags != None:
+            self.flags = flags
+        else:
+            self.flags = 0
+        if experimenter != None:
+            self.experimenter = experimenter
+        else:
+            self.experimenter = 0
+        if subtype != None:
+            self.subtype = subtype
+        else:
+            self.subtype = 0
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!B", self.version))
+        packed.append(struct.pack("!B", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for length at index 2
+        packed.append(struct.pack("!L", self.xid))
+        packed.append(struct.pack("!H", self.stats_type))
+        packed.append(struct.pack("!H", self.flags))
+        packed.append('\x00' * 4)
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        length = sum([len(x) for x in packed])
+        packed[2] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 16)
+        subclass = experimenter_stats_request.subtypes.get(subtype)
+        if subclass:
+            return subclass.unpack(reader)
+
+        obj = experimenter_stats_request()
+        _version = reader.read("!B")[0]
+        assert(_version == 4)
+        _type = reader.read("!B")[0]
+        assert(_type == 18)
+        _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
+        obj.xid = reader.read("!L")[0]
+        _stats_type = reader.read("!H")[0]
+        assert(_stats_type == 65535)
+        obj.flags = reader.read("!H")[0]
+        reader.skip(4)
+        obj.experimenter = reader.read("!L")[0]
+        obj.subtype = reader.read("!L")[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.xid != other.xid: return False
+        if self.flags != other.flags: return False
+        if self.experimenter != other.experimenter: return False
+        if self.subtype != other.subtype: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("experimenter_stats_request {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("xid = ");
+                if self.xid != None:
+                    q.text("%#x" % self.xid)
+                else:
+                    q.text('None')
+                q.text(","); q.breakable()
+                q.text("flags = ");
+                q.text("%#x" % self.flags)
+                q.text(","); q.breakable()
+                q.text("subtype = ");
+                q.text("%#x" % self.subtype)
+            q.breakable()
+        q.text('}')
+
+stats_request.subtypes[65535] = experimenter_stats_request
+
+class bsn_stats_request(experimenter_stats_request):
+    subtypes = {}
+
+    version = 4
+    type = 18
+    stats_type = 65535
+    experimenter = 6035143
+
+    def __init__(self, xid=None, flags=None, subtype=None):
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        if flags != None:
+            self.flags = flags
+        else:
+            self.flags = 0
+        if subtype != None:
+            self.subtype = subtype
+        else:
+            self.subtype = 0
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!B", self.version))
+        packed.append(struct.pack("!B", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for length at index 2
+        packed.append(struct.pack("!L", self.xid))
+        packed.append(struct.pack("!H", self.stats_type))
+        packed.append(struct.pack("!H", self.flags))
+        packed.append('\x00' * 4)
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        length = sum([len(x) for x in packed])
+        packed[2] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 20)
+        subclass = bsn_stats_request.subtypes.get(subtype)
+        if subclass:
+            return subclass.unpack(reader)
+
+        obj = bsn_stats_request()
+        _version = reader.read("!B")[0]
+        assert(_version == 4)
+        _type = reader.read("!B")[0]
+        assert(_type == 18)
+        _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
+        obj.xid = reader.read("!L")[0]
+        _stats_type = reader.read("!H")[0]
+        assert(_stats_type == 65535)
+        obj.flags = reader.read("!H")[0]
+        reader.skip(4)
+        _experimenter = reader.read("!L")[0]
+        assert(_experimenter == 6035143)
+        obj.subtype = reader.read("!L")[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.xid != other.xid: return False
+        if self.flags != other.flags: return False
+        if self.subtype != other.subtype: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_stats_request {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("xid = ");
+                if self.xid != None:
+                    q.text("%#x" % self.xid)
+                else:
+                    q.text('None')
+                q.text(","); q.breakable()
+                q.text("flags = ");
+                q.text("%#x" % self.flags)
+            q.breakable()
+        q.text('}')
+
+experimenter_stats_request.subtypes[6035143] = bsn_stats_request
+
+class bsn_flow_checksum_bucket_stats_request(bsn_stats_request):
+    version = 4
+    type = 18
+    stats_type = 65535
+    experimenter = 6035143
+    subtype = 10
+
+    def __init__(self, xid=None, flags=None, table_id=None):
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        if flags != None:
+            self.flags = flags
+        else:
+            self.flags = 0
+        if table_id != None:
+            self.table_id = table_id
+        else:
+            self.table_id = 0
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!B", self.version))
+        packed.append(struct.pack("!B", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for length at index 2
+        packed.append(struct.pack("!L", self.xid))
+        packed.append(struct.pack("!H", self.stats_type))
+        packed.append(struct.pack("!H", self.flags))
+        packed.append('\x00' * 4)
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        packed.append(struct.pack("!B", self.table_id))
+        length = sum([len(x) for x in packed])
+        packed[2] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_flow_checksum_bucket_stats_request()
+        _version = reader.read("!B")[0]
+        assert(_version == 4)
+        _type = reader.read("!B")[0]
+        assert(_type == 18)
+        _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
+        obj.xid = reader.read("!L")[0]
+        _stats_type = reader.read("!H")[0]
+        assert(_stats_type == 65535)
+        obj.flags = reader.read("!H")[0]
+        reader.skip(4)
+        _experimenter = reader.read("!L")[0]
+        assert(_experimenter == 6035143)
+        _subtype = reader.read("!L")[0]
+        assert(_subtype == 10)
+        obj.table_id = reader.read("!B")[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.xid != other.xid: return False
+        if self.flags != other.flags: return False
+        if self.table_id != other.table_id: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_flow_checksum_bucket_stats_request {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("xid = ");
+                if self.xid != None:
+                    q.text("%#x" % self.xid)
+                else:
+                    q.text('None')
+                q.text(","); q.breakable()
+                q.text("flags = ");
+                q.text("%#x" % self.flags)
+                q.text(","); q.breakable()
+                q.text("table_id = ");
+                q.text("%#x" % self.table_id)
+            q.breakable()
+        q.text('}')
+
+bsn_stats_request.subtypes[10] = bsn_flow_checksum_bucket_stats_request
+
 class bsn_flow_idle(bsn_header):
     version = 4
     type = 4
@@ -2501,188 +3041,6 @@
 
 bsn_header.subtypes[36] = bsn_flow_idle_enable_set_request
 
-class experimenter_stats_reply(stats_reply):
-    subtypes = {}
-
-    version = 4
-    type = 19
-    stats_type = 65535
-
-    def __init__(self, xid=None, flags=None, experimenter=None, subtype=None):
-        if xid != None:
-            self.xid = xid
-        else:
-            self.xid = None
-        if flags != None:
-            self.flags = flags
-        else:
-            self.flags = 0
-        if experimenter != None:
-            self.experimenter = experimenter
-        else:
-            self.experimenter = 0
-        if subtype != None:
-            self.subtype = subtype
-        else:
-            self.subtype = 0
-        return
-
-    def pack(self):
-        packed = []
-        packed.append(struct.pack("!B", self.version))
-        packed.append(struct.pack("!B", self.type))
-        packed.append(struct.pack("!H", 0)) # placeholder for length at index 2
-        packed.append(struct.pack("!L", self.xid))
-        packed.append(struct.pack("!H", self.stats_type))
-        packed.append(struct.pack("!H", self.flags))
-        packed.append('\x00' * 4)
-        packed.append(struct.pack("!L", self.experimenter))
-        packed.append(struct.pack("!L", self.subtype))
-        length = sum([len(x) for x in packed])
-        packed[2] = struct.pack("!H", length)
-        return ''.join(packed)
-
-    @staticmethod
-    def unpack(reader):
-        subtype, = reader.peek('!L', 16)
-        subclass = experimenter_stats_reply.subtypes.get(subtype)
-        if subclass:
-            return subclass.unpack(reader)
-
-        obj = experimenter_stats_reply()
-        _version = reader.read("!B")[0]
-        assert(_version == 4)
-        _type = reader.read("!B")[0]
-        assert(_type == 19)
-        _length = reader.read("!H")[0]
-        orig_reader = reader
-        reader = orig_reader.slice(_length - (2 + 2))
-        obj.xid = reader.read("!L")[0]
-        _stats_type = reader.read("!H")[0]
-        assert(_stats_type == 65535)
-        obj.flags = reader.read("!H")[0]
-        reader.skip(4)
-        obj.experimenter = reader.read("!L")[0]
-        obj.subtype = reader.read("!L")[0]
-        return obj
-
-    def __eq__(self, other):
-        if type(self) != type(other): return False
-        if self.xid != other.xid: return False
-        if self.flags != other.flags: return False
-        if self.experimenter != other.experimenter: return False
-        if self.subtype != other.subtype: return False
-        return True
-
-    def pretty_print(self, q):
-        q.text("experimenter_stats_reply {")
-        with q.group():
-            with q.indent(2):
-                q.breakable()
-                q.text("xid = ");
-                if self.xid != None:
-                    q.text("%#x" % self.xid)
-                else:
-                    q.text('None')
-                q.text(","); q.breakable()
-                q.text("flags = ");
-                q.text("%#x" % self.flags)
-                q.text(","); q.breakable()
-                q.text("subtype = ");
-                q.text("%#x" % self.subtype)
-            q.breakable()
-        q.text('}')
-
-stats_reply.subtypes[65535] = experimenter_stats_reply
-
-class bsn_stats_reply(experimenter_stats_reply):
-    subtypes = {}
-
-    version = 4
-    type = 19
-    stats_type = 65535
-    experimenter = 6035143
-
-    def __init__(self, xid=None, flags=None, subtype=None):
-        if xid != None:
-            self.xid = xid
-        else:
-            self.xid = None
-        if flags != None:
-            self.flags = flags
-        else:
-            self.flags = 0
-        if subtype != None:
-            self.subtype = subtype
-        else:
-            self.subtype = 0
-        return
-
-    def pack(self):
-        packed = []
-        packed.append(struct.pack("!B", self.version))
-        packed.append(struct.pack("!B", self.type))
-        packed.append(struct.pack("!H", 0)) # placeholder for length at index 2
-        packed.append(struct.pack("!L", self.xid))
-        packed.append(struct.pack("!H", self.stats_type))
-        packed.append(struct.pack("!H", self.flags))
-        packed.append('\x00' * 4)
-        packed.append(struct.pack("!L", self.experimenter))
-        packed.append(struct.pack("!L", self.subtype))
-        length = sum([len(x) for x in packed])
-        packed[2] = struct.pack("!H", length)
-        return ''.join(packed)
-
-    @staticmethod
-    def unpack(reader):
-        subtype, = reader.peek('!L', 20)
-        subclass = bsn_stats_reply.subtypes.get(subtype)
-        if subclass:
-            return subclass.unpack(reader)
-
-        obj = bsn_stats_reply()
-        _version = reader.read("!B")[0]
-        assert(_version == 4)
-        _type = reader.read("!B")[0]
-        assert(_type == 19)
-        _length = reader.read("!H")[0]
-        orig_reader = reader
-        reader = orig_reader.slice(_length - (2 + 2))
-        obj.xid = reader.read("!L")[0]
-        _stats_type = reader.read("!H")[0]
-        assert(_stats_type == 65535)
-        obj.flags = reader.read("!H")[0]
-        reader.skip(4)
-        _experimenter = reader.read("!L")[0]
-        assert(_experimenter == 6035143)
-        obj.subtype = reader.read("!L")[0]
-        return obj
-
-    def __eq__(self, other):
-        if type(self) != type(other): return False
-        if self.xid != other.xid: return False
-        if self.flags != other.flags: return False
-        if self.subtype != other.subtype: return False
-        return True
-
-    def pretty_print(self, q):
-        q.text("bsn_stats_reply {")
-        with q.group():
-            with q.indent(2):
-                q.breakable()
-                q.text("xid = ");
-                if self.xid != None:
-                    q.text("%#x" % self.xid)
-                else:
-                    q.text('None')
-                q.text(","); q.breakable()
-                q.text("flags = ");
-                q.text("%#x" % self.flags)
-            q.breakable()
-        q.text('}')
-
-experimenter_stats_reply.subtypes[6035143] = bsn_stats_reply
-
 class bsn_gentable_bucket_stats_reply(bsn_stats_reply):
     version = 4
     type = 19
@@ -2771,188 +3129,6 @@
 
 bsn_stats_reply.subtypes[5] = bsn_gentable_bucket_stats_reply
 
-class experimenter_stats_request(stats_request):
-    subtypes = {}
-
-    version = 4
-    type = 18
-    stats_type = 65535
-
-    def __init__(self, xid=None, flags=None, experimenter=None, subtype=None):
-        if xid != None:
-            self.xid = xid
-        else:
-            self.xid = None
-        if flags != None:
-            self.flags = flags
-        else:
-            self.flags = 0
-        if experimenter != None:
-            self.experimenter = experimenter
-        else:
-            self.experimenter = 0
-        if subtype != None:
-            self.subtype = subtype
-        else:
-            self.subtype = 0
-        return
-
-    def pack(self):
-        packed = []
-        packed.append(struct.pack("!B", self.version))
-        packed.append(struct.pack("!B", self.type))
-        packed.append(struct.pack("!H", 0)) # placeholder for length at index 2
-        packed.append(struct.pack("!L", self.xid))
-        packed.append(struct.pack("!H", self.stats_type))
-        packed.append(struct.pack("!H", self.flags))
-        packed.append('\x00' * 4)
-        packed.append(struct.pack("!L", self.experimenter))
-        packed.append(struct.pack("!L", self.subtype))
-        length = sum([len(x) for x in packed])
-        packed[2] = struct.pack("!H", length)
-        return ''.join(packed)
-
-    @staticmethod
-    def unpack(reader):
-        subtype, = reader.peek('!L', 16)
-        subclass = experimenter_stats_request.subtypes.get(subtype)
-        if subclass:
-            return subclass.unpack(reader)
-
-        obj = experimenter_stats_request()
-        _version = reader.read("!B")[0]
-        assert(_version == 4)
-        _type = reader.read("!B")[0]
-        assert(_type == 18)
-        _length = reader.read("!H")[0]
-        orig_reader = reader
-        reader = orig_reader.slice(_length - (2 + 2))
-        obj.xid = reader.read("!L")[0]
-        _stats_type = reader.read("!H")[0]
-        assert(_stats_type == 65535)
-        obj.flags = reader.read("!H")[0]
-        reader.skip(4)
-        obj.experimenter = reader.read("!L")[0]
-        obj.subtype = reader.read("!L")[0]
-        return obj
-
-    def __eq__(self, other):
-        if type(self) != type(other): return False
-        if self.xid != other.xid: return False
-        if self.flags != other.flags: return False
-        if self.experimenter != other.experimenter: return False
-        if self.subtype != other.subtype: return False
-        return True
-
-    def pretty_print(self, q):
-        q.text("experimenter_stats_request {")
-        with q.group():
-            with q.indent(2):
-                q.breakable()
-                q.text("xid = ");
-                if self.xid != None:
-                    q.text("%#x" % self.xid)
-                else:
-                    q.text('None')
-                q.text(","); q.breakable()
-                q.text("flags = ");
-                q.text("%#x" % self.flags)
-                q.text(","); q.breakable()
-                q.text("subtype = ");
-                q.text("%#x" % self.subtype)
-            q.breakable()
-        q.text('}')
-
-stats_request.subtypes[65535] = experimenter_stats_request
-
-class bsn_stats_request(experimenter_stats_request):
-    subtypes = {}
-
-    version = 4
-    type = 18
-    stats_type = 65535
-    experimenter = 6035143
-
-    def __init__(self, xid=None, flags=None, subtype=None):
-        if xid != None:
-            self.xid = xid
-        else:
-            self.xid = None
-        if flags != None:
-            self.flags = flags
-        else:
-            self.flags = 0
-        if subtype != None:
-            self.subtype = subtype
-        else:
-            self.subtype = 0
-        return
-
-    def pack(self):
-        packed = []
-        packed.append(struct.pack("!B", self.version))
-        packed.append(struct.pack("!B", self.type))
-        packed.append(struct.pack("!H", 0)) # placeholder for length at index 2
-        packed.append(struct.pack("!L", self.xid))
-        packed.append(struct.pack("!H", self.stats_type))
-        packed.append(struct.pack("!H", self.flags))
-        packed.append('\x00' * 4)
-        packed.append(struct.pack("!L", self.experimenter))
-        packed.append(struct.pack("!L", self.subtype))
-        length = sum([len(x) for x in packed])
-        packed[2] = struct.pack("!H", length)
-        return ''.join(packed)
-
-    @staticmethod
-    def unpack(reader):
-        subtype, = reader.peek('!L', 20)
-        subclass = bsn_stats_request.subtypes.get(subtype)
-        if subclass:
-            return subclass.unpack(reader)
-
-        obj = bsn_stats_request()
-        _version = reader.read("!B")[0]
-        assert(_version == 4)
-        _type = reader.read("!B")[0]
-        assert(_type == 18)
-        _length = reader.read("!H")[0]
-        orig_reader = reader
-        reader = orig_reader.slice(_length - (2 + 2))
-        obj.xid = reader.read("!L")[0]
-        _stats_type = reader.read("!H")[0]
-        assert(_stats_type == 65535)
-        obj.flags = reader.read("!H")[0]
-        reader.skip(4)
-        _experimenter = reader.read("!L")[0]
-        assert(_experimenter == 6035143)
-        obj.subtype = reader.read("!L")[0]
-        return obj
-
-    def __eq__(self, other):
-        if type(self) != type(other): return False
-        if self.xid != other.xid: return False
-        if self.flags != other.flags: return False
-        if self.subtype != other.subtype: return False
-        return True
-
-    def pretty_print(self, q):
-        q.text("bsn_stats_request {")
-        with q.group():
-            with q.indent(2):
-                q.breakable()
-                q.text("xid = ");
-                if self.xid != None:
-                    q.text("%#x" % self.xid)
-                else:
-                    q.text('None')
-                q.text(","); q.breakable()
-                q.text("flags = ");
-                q.text("%#x" % self.flags)
-            q.breakable()
-        q.text('}')
-
-experimenter_stats_request.subtypes[6035143] = bsn_stats_request
-
 class bsn_gentable_bucket_stats_request(bsn_stats_request):
     version = 4
     type = 18
@@ -6678,6 +6854,256 @@
 
 bsn_stats_request.subtypes[6] = bsn_switch_pipeline_stats_request
 
+class bsn_table_checksum_stats_reply(bsn_stats_reply):
+    version = 4
+    type = 19
+    stats_type = 65535
+    experimenter = 6035143
+    subtype = 11
+
+    def __init__(self, xid=None, flags=None, entries=None):
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        if flags != None:
+            self.flags = flags
+        else:
+            self.flags = 0
+        if entries != None:
+            self.entries = entries
+        else:
+            self.entries = []
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!B", self.version))
+        packed.append(struct.pack("!B", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for length at index 2
+        packed.append(struct.pack("!L", self.xid))
+        packed.append(struct.pack("!H", self.stats_type))
+        packed.append(struct.pack("!H", self.flags))
+        packed.append('\x00' * 4)
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        packed.append(loxi.generic_util.pack_list(self.entries))
+        length = sum([len(x) for x in packed])
+        packed[2] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_table_checksum_stats_reply()
+        _version = reader.read("!B")[0]
+        assert(_version == 4)
+        _type = reader.read("!B")[0]
+        assert(_type == 19)
+        _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
+        obj.xid = reader.read("!L")[0]
+        _stats_type = reader.read("!H")[0]
+        assert(_stats_type == 65535)
+        obj.flags = reader.read("!H")[0]
+        reader.skip(4)
+        _experimenter = reader.read("!L")[0]
+        assert(_experimenter == 6035143)
+        _subtype = reader.read("!L")[0]
+        assert(_subtype == 11)
+        obj.entries = loxi.generic_util.unpack_list(reader, common.bsn_table_checksum_stats_entry.unpack)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.xid != other.xid: return False
+        if self.flags != other.flags: return False
+        if self.entries != other.entries: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_table_checksum_stats_reply {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("xid = ");
+                if self.xid != None:
+                    q.text("%#x" % self.xid)
+                else:
+                    q.text('None')
+                q.text(","); q.breakable()
+                q.text("flags = ");
+                q.text("%#x" % self.flags)
+                q.text(","); q.breakable()
+                q.text("entries = ");
+                q.pp(self.entries)
+            q.breakable()
+        q.text('}')
+
+bsn_stats_reply.subtypes[11] = bsn_table_checksum_stats_reply
+
+class bsn_table_checksum_stats_request(bsn_stats_request):
+    version = 4
+    type = 18
+    stats_type = 65535
+    experimenter = 6035143
+    subtype = 11
+
+    def __init__(self, xid=None, flags=None):
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        if flags != None:
+            self.flags = flags
+        else:
+            self.flags = 0
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!B", self.version))
+        packed.append(struct.pack("!B", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for length at index 2
+        packed.append(struct.pack("!L", self.xid))
+        packed.append(struct.pack("!H", self.stats_type))
+        packed.append(struct.pack("!H", self.flags))
+        packed.append('\x00' * 4)
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        length = sum([len(x) for x in packed])
+        packed[2] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_table_checksum_stats_request()
+        _version = reader.read("!B")[0]
+        assert(_version == 4)
+        _type = reader.read("!B")[0]
+        assert(_type == 18)
+        _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
+        obj.xid = reader.read("!L")[0]
+        _stats_type = reader.read("!H")[0]
+        assert(_stats_type == 65535)
+        obj.flags = reader.read("!H")[0]
+        reader.skip(4)
+        _experimenter = reader.read("!L")[0]
+        assert(_experimenter == 6035143)
+        _subtype = reader.read("!L")[0]
+        assert(_subtype == 11)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.xid != other.xid: return False
+        if self.flags != other.flags: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_table_checksum_stats_request {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("xid = ");
+                if self.xid != None:
+                    q.text("%#x" % self.xid)
+                else:
+                    q.text('None')
+                q.text(","); q.breakable()
+                q.text("flags = ");
+                q.text("%#x" % self.flags)
+            q.breakable()
+        q.text('}')
+
+bsn_stats_request.subtypes[11] = bsn_table_checksum_stats_request
+
+class bsn_table_set_buckets_size(bsn_header):
+    version = 4
+    type = 4
+    experimenter = 6035143
+    subtype = 61
+
+    def __init__(self, xid=None, table_id=None, buckets_size=None):
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        if table_id != None:
+            self.table_id = table_id
+        else:
+            self.table_id = 0
+        if buckets_size != None:
+            self.buckets_size = buckets_size
+        else:
+            self.buckets_size = 0
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!B", self.version))
+        packed.append(struct.pack("!B", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for length at index 2
+        packed.append(struct.pack("!L", self.xid))
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        packed.append(struct.pack("!H", self.table_id))
+        packed.append('\x00' * 2)
+        packed.append(struct.pack("!L", self.buckets_size))
+        length = sum([len(x) for x in packed])
+        packed[2] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_table_set_buckets_size()
+        _version = reader.read("!B")[0]
+        assert(_version == 4)
+        _type = reader.read("!B")[0]
+        assert(_type == 4)
+        _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
+        obj.xid = reader.read("!L")[0]
+        _experimenter = reader.read("!L")[0]
+        assert(_experimenter == 6035143)
+        _subtype = reader.read("!L")[0]
+        assert(_subtype == 61)
+        obj.table_id = reader.read("!H")[0]
+        reader.skip(2)
+        obj.buckets_size = reader.read("!L")[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.xid != other.xid: return False
+        if self.table_id != other.table_id: return False
+        if self.buckets_size != other.buckets_size: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_table_set_buckets_size {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("xid = ");
+                if self.xid != None:
+                    q.text("%#x" % self.xid)
+                else:
+                    q.text('None')
+                q.text(","); q.breakable()
+                q.text("table_id = ");
+                q.text("%#x" % self.table_id)
+                q.text(","); q.breakable()
+                q.text("buckets_size = ");
+                q.text("%#x" % self.buckets_size)
+            q.breakable()
+        q.text('}')
+
+bsn_header.subtypes[61] = bsn_table_set_buckets_size
+
 class bsn_time_reply(bsn_header):
     version = 4
     type = 4
diff --git a/src/python/loxi/of13/oxm.py b/src/python/loxi/of13/oxm.py
index a2f5053..65536e8 100644
--- a/src/python/loxi/of13/oxm.py
+++ b/src/python/loxi/of13/oxm.py
@@ -521,6 +521,98 @@
 
 oxm.subtypes[2147495688] = arp_tpa_masked
 
+class bsn_egr_port_group_id(oxm):
+    type_len = 200196
+
+    def __init__(self, value=None):
+        if value != None:
+            self.value = value
+        else:
+            self.value = 0
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!L", self.type_len))
+        packed.append(struct.pack("!L", self.value))
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_egr_port_group_id()
+        _type_len = reader.read("!L")[0]
+        assert(_type_len == 200196)
+        obj.value = reader.read("!L")[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.value != other.value: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_egr_port_group_id {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("value = ");
+                q.text("%#x" % self.value)
+            q.breakable()
+        q.text('}')
+
+oxm.subtypes[200196] = bsn_egr_port_group_id
+
+class bsn_egr_port_group_id_masked(oxm):
+    type_len = 200456
+
+    def __init__(self, value=None, value_mask=None):
+        if value != None:
+            self.value = value
+        else:
+            self.value = 0
+        if value_mask != None:
+            self.value_mask = value_mask
+        else:
+            self.value_mask = 0
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!L", self.type_len))
+        packed.append(struct.pack("!L", self.value))
+        packed.append(struct.pack("!L", self.value_mask))
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_egr_port_group_id_masked()
+        _type_len = reader.read("!L")[0]
+        assert(_type_len == 200456)
+        obj.value = reader.read("!L")[0]
+        obj.value_mask = reader.read("!L")[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.value != other.value: return False
+        if self.value_mask != other.value_mask: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_egr_port_group_id_masked {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("value = ");
+                q.text("%#x" % self.value)
+                q.text(","); q.breakable()
+                q.text("value_mask = ");
+                q.text("%#x" % self.value_mask)
+            q.breakable()
+        q.text('}')
+
+oxm.subtypes[200456] = bsn_egr_port_group_id_masked
+
 class bsn_global_vrf_allowed(oxm):
     type_len = 198145
 
diff --git a/src/python/oftest/dataplane.py b/src/python/oftest/dataplane.py
index 12dcfce..740e6aa 100644
--- a/src/python/oftest/dataplane.py
+++ b/src/python/oftest/dataplane.py
@@ -126,7 +126,7 @@
 
     def recv(self):
         (timestamp, pkt) = next(self.pcap)
-        return (pkt, timestamp)
+        return (pkt[:], timestamp)
 
     def send(self, packet):
         return self.pcap.inject(packet, len(packet))
diff --git a/src/python/oftest/ofutils.py b/src/python/oftest/ofutils.py
index 8cf2ae0..f81a2f5 100644
--- a/src/python/oftest/ofutils.py
+++ b/src/python/oftest/ofutils.py
@@ -10,6 +10,7 @@
 import logging
 
 default_timeout = None # set by oft
+default_negative_timeout = None # set by oft
 
 def gen_xid():
     return random.randrange(1,0xffffffff)
@@ -19,11 +20,9 @@
 The condition variable must already be acquired.
 The timeout value -1 means use the default timeout.
 There is deliberately no support for an infinite timeout.
-TODO: get the default timeout from configuration
 """
 def timed_wait(cv, fn, timeout=-1):
     if timeout == -1:
-        # TODO make this configurable
         timeout = default_timeout
 
     end_time = time.time() + timeout
diff --git a/src/python/oftest/packet.py b/src/python/oftest/packet.py
index 9631e02..1ed100f 100644
--- a/src/python/oftest/packet.py
+++ b/src/python/oftest/packet.py
@@ -4,15 +4,17 @@
 """
 Wrap scapy to satisfy pylint
 """
+from oftest import config
 import sys
 
 try:
     import scapy.config
     import scapy.route
-    import scapy.route6
     import scapy.layers.l2
     import scapy.layers.inet
-    import scapy.layers.inet6
+    if not config["disable_ipv6"]:
+        import scapy.route6
+        import scapy.layers.inet6
 except ImportError:
     sys.exit("Need to install scapy for packet parsing")
 
@@ -22,10 +24,12 @@
 Dot1Q = scapy.layers.l2.Dot1Q
 IP = scapy.layers.inet.IP
 IPOption = scapy.layers.inet.IPOption
-IPv6 = scapy.layers.inet6.IPv6
 ARP = scapy.layers.inet.ARP
 TCP = scapy.layers.inet.TCP
 UDP = scapy.layers.inet.UDP
 ICMP = scapy.layers.inet.ICMP
-ICMPv6Unknown = scapy.layers.inet6.ICMPv6Unknown
-ICMPv6EchoRequest = scapy.layers.inet6.ICMPv6EchoRequest
+
+if not config["disable_ipv6"]:
+    IPv6 = scapy.layers.inet6.IPv6
+    ICMPv6Unknown = scapy.layers.inet6.ICMPv6Unknown
+    ICMPv6EchoRequest = scapy.layers.inet6.ICMPv6EchoRequest
diff --git a/src/python/oftest/testutils.py b/src/python/oftest/testutils.py
index d47f81f..57201ce 100644
--- a/src/python/oftest/testutils.py
+++ b/src/python/oftest/testutils.py
@@ -292,9 +292,10 @@
                       ip_dst='192.168.0.2',
                       ip_tos=0,
                       ip_ttl=64,
+                      ip_id=1,  
                       icmp_type=8,
-                      icmp_code=0
-                      ):
+                      icmp_code=0,
+                      icmp_data=''):
     """
     Return a simple ICMP packet
 
@@ -309,8 +310,10 @@
     @param ip_dst IP destination
     @param ip_tos IP ToS
     @param ip_ttl IP TTL
+    @param ip_id IP Identification
     @param icmp_type ICMP type
     @param icmp_code ICMP code
+    @param icmp_data ICMP data
 
     Generates a simple ICMP ECHO REQUEST.  Users
     shouldn't assume anything about this packet other than that
@@ -323,12 +326,12 @@
     if (dl_vlan_enable):
         pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
             scapy.Dot1Q(prio=vlan_pcp, id=0, vlan=vlan_vid)/ \
-            scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
-            scapy.ICMP(type=icmp_type, code=icmp_code)
+            scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos, id=ip_id)/ \
+            scapy.ICMP(type=icmp_type, code=icmp_code)/ icmp_data
     else:
         pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
-            scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos)/ \
-            scapy.ICMP(type=icmp_type, code=icmp_code)
+            scapy.IP(src=ip_src, dst=ip_dst, ttl=ip_ttl, tos=ip_tos, id=ip_id)/ \
+            scapy.ICMP(type=icmp_type, code=icmp_code)/ icmp_data
 
     pkt = pkt/("0" * (pktlen - len(pkt)))
 
@@ -573,11 +576,6 @@
     DEPRECATED in favor in verify_packets
     """
 
-    # Wait this long for packets that we don't expect to receive.
-    # 100ms is (rarely) too short for positive tests on slow
-    # switches but is definitely not too short for a negative test.
-    negative_timeout = 0.1
-
     exp_pkt_arg = None
     if oftest.config["relax"]:
         exp_pkt_arg = pkt
@@ -595,7 +593,7 @@
                              "Received packet does not match expected packet " +
                              "on port " + str(ofport))
     if len(no_ports) > 0:
-        time.sleep(negative_timeout)
+        time.sleep(oftest.ofutils.default_negative_timeout)
     for ofport in no_ports:
         logging.debug("Negative check for pkt on port " + str(ofport))
         (rcv_port, rcv_pkt, pkt_time) = dp.poll(
@@ -1379,7 +1377,6 @@
     return get_stats(test, req)
 
 def verify_flow_stats(test, match, table_id=0xff,
-                      out_port=None,
                       initial=[],
                       pkts=None, bytes=None):
     """
@@ -1389,8 +1386,6 @@
     get_flow_stats(). If 'initial' is not given the counters are assumed to
     begin at 0.
     """
-    if out_port == None:
-        out_port = ofp.OFPP_NONE
 
     def accumulate(stats):
         pkts_acc = bytes_acc = 0
@@ -1404,7 +1399,7 @@
     # Wait 10s for counters to update
     pkt_diff = byte_diff = None
     for i in range(0, 100):
-        stats = get_flow_stats(test, match, table_id=table_id, out_port=out_port)
+        stats = get_flow_stats(test, match, table_id=table_id)
         pkts_after, bytes_after = accumulate(stats)
         pkt_diff = pkts_after - pkts_before
         byte_diff = bytes_after - bytes_before
@@ -1602,7 +1597,7 @@
 
     # Negative test, need to wait a short amount of time before checking we
     # didn't receive the message.
-    time.sleep(0.5)
+    time.sleep(oftest.ofutils.default_negative_timeout)
 
     # Check every packet_in queued in the controller
     while True:
@@ -1645,7 +1640,10 @@
     Check that a particular packet is not received
     """
     logging.debug("Negative check for pkt on port %r", ofport)
-    (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(port_number=ofport, exp_pkt=str(pkt), timeout=0.01)
+    (rcv_port, rcv_pkt, pkt_time) = \
+        test.dataplane.poll(
+            port_number=ofport, exp_pkt=str(pkt),
+            timeout=oftest.ofutils.default_negative_timeout)
     test.assertTrue(rcv_pkt == None, "Received packet on %r" % ofport)
 
 def verify_no_other_packets(test):
@@ -1657,7 +1655,7 @@
     if oftest.config["relax"]:
         return
     logging.debug("Checking for unexpected packets on all ports")
-    (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(timeout=0.01)
+    (rcv_port, rcv_pkt, pkt_time) = test.dataplane.poll(timeout=oftest.ofutils.default_negative_timeout)
     if rcv_pkt != None:
         logging.debug("Received unexpected packet on port %r: %s", rcv_port, format_packet(rcv_pkt))
     test.assertTrue(rcv_pkt == None, "Unexpected packet on port %r" % rcv_port)
@@ -1689,7 +1687,7 @@
 
 def verify_capability(test, capability):
     """
-    Assert that the DUT supports the specified capability.
+    Return True if DUT supports the specified capability.
 
     @param test Instance of base_tests.SimpleProtocol
     @param capability One of ofp_capabilities.
@@ -1707,14 +1705,16 @@
     test.assertEqual(res.type, ofp.OFPT_FEATURES_REPLY,
                      ("Unexpected packet type %d received in response to "
                       "OFPT_FEATURES_REQUEST") % res.type)
-    logging.info("Received features_request.")
+    logging.info("Received features_reply.")
     
-    logging.info("Verifying %s bit is set.", capability_str)
-    test.assertTrue((res.capabilities & capability) > 0,
-                    ("Capabilities bitmask does not support "
-                     "%s.") % capability_str)
-    logging.info(("Switch capabilities bitmask claims to support "
-                  "%s."), capability_str)
+    if (res.capabilities & capability) > 0:
+        logging.info("Switch capabilities bitmask claims to support %s",
+                     capability_str)
+        return True, res.capabilities
+    else:
+        logging.info("Capabilities bitmask does not support %s.",
+                     capability_str)
+        return False, res.capabilities
 
 def verify_configuration_flag(test, flag):
     """
diff --git a/tests-1.3/bsn_controller_connections.py b/tests-1.3/bsn_controller_connections.py
new file mode 100644
index 0000000..ba58596
--- /dev/null
+++ b/tests-1.3/bsn_controller_connections.py
@@ -0,0 +1,24 @@
+"""
+Test the BSN controller connections request
+"""
+import struct
+import unittest
+import logging
+
+import oftest
+from oftest import config
+import oftest.controller as controller
+import ofp
+import oftest.base_tests as base_tests
+
+from oftest.testutils import *
+
+class BsnControllerConnectionsRequest(base_tests.SimpleProtocol):
+    """
+    Verify that the switch sends a bsn_controller_connections_reply in response
+    to the request
+    """
+    def runTest(self):
+        request = ofp.message.bsn_controller_connections_request()
+        response, _ = self.controller.transact(request)
+        self.assertIsInstance(response, ofp.message.bsn_controller_connections_reply)
diff --git a/tests-1.3/bsn_flow_checksum.py b/tests-1.3/bsn_flow_checksum.py
new file mode 100644
index 0000000..11bbedc
--- /dev/null
+++ b/tests-1.3/bsn_flow_checksum.py
@@ -0,0 +1,252 @@
+# Distributed under the OpenFlow Software License (see LICENSE)
+# Copyright (c) 2014 Big Switch Networks, Inc.
+"""
+BSN flow checksum extension test cases
+"""
+
+import logging
+import math
+import random
+
+from oftest import config
+import oftest.base_tests as base_tests
+import ofp
+
+from oftest.testutils import *
+
+TABLE_ID = 0
+
+def make_checksum(hi, lo):
+    """
+    Place 'hi' in the upper 8 bits and 'lo' in the lower bits.
+    """
+    return ((hi & 0xff) << 56) | lo
+
+assert make_checksum(0xab, 0xcd) == 0xab000000000000cd
+
+def shuffled(seq):
+    l = list(seq)[:]
+    random.shuffle(l)
+    return l
+
+class FlowChecksumBase(base_tests.SimpleProtocol):
+    """
+    Base class that maintains the expected table and bucket checksums
+    """
+    checksum_buckets = None
+    table_checksum = None
+    all_checksums = []
+
+    def get_table_checksum(self):
+        for entry in get_stats(self, ofp.message.bsn_table_checksum_stats_request()):
+            if entry.table_id == TABLE_ID:
+                return entry.checksum
+        return None
+
+    def get_checksum_buckets(self):
+        stats = get_stats(self,
+            ofp.message.bsn_flow_checksum_bucket_stats_request(table_id=TABLE_ID))
+        return [x.checksum for x in stats]
+
+    def verify_checksums(self):
+        self.assertEquals(self.get_table_checksum(), self.table_checksum)
+        self.assertEquals(self.get_checksum_buckets(), self.checksum_buckets)
+
+    def update_checksums(self, checksum):
+        self.table_checksum ^= checksum
+        checksum_shift = 64 - int(math.log(len(self.checksum_buckets), 2))
+        self.checksum_buckets[checksum >> checksum_shift] ^= checksum
+
+    def insert_checksum(self, checksum):
+        self.update_checksums(checksum)
+        self.all_checksums.append(checksum)
+
+    def remove_checksum(self, checksum):
+        self.update_checksums(checksum)
+        self.all_checksums.remove(checksum)
+
+    def set_buckets_size(self, buckets_size):
+        self.controller.message_send(
+            ofp.message.bsn_table_set_buckets_size(
+                table_id=TABLE_ID, buckets_size=buckets_size))
+        do_barrier(self.controller)
+        verify_no_errors(self.controller)
+
+        self.checksum_buckets = [0] * buckets_size
+        self.table_checksum = 0
+        for checksum in self.all_checksums:
+            self.update_checksums(checksum)
+
+class FlowChecksum(FlowChecksumBase):
+    """
+    Test flow checksum buckets and table checksums
+    """
+    def runTest(self):
+        delete_all_flows(self.controller)
+
+        # Deleted all flows, table checksum should be 0
+        self.assertEquals(self.get_table_checksum(), 0)
+
+        self.set_buckets_size(8)
+        self.verify_checksums()
+
+        # Interesting checksums
+        checksums = [
+            make_checksum(0, 1),
+            make_checksum(0, 2),
+            make_checksum(1, 0xab),
+            make_checksum(1, 0xab),
+            make_checksum(7, 0xff),
+            make_checksum(7, 0xaa),
+        ]
+
+        # Random checksums
+        for _ in xrange(0, 8):
+            checksums.append(random.randint(0, 2**64-1))
+
+        # Add flows in random order
+        for i, checksum in shuffled(enumerate(checksums)):
+            self.insert_checksum(checksum)
+            request = ofp.message.flow_add(
+                table_id=TABLE_ID,
+                cookie=checksum,
+                buffer_id=ofp.OFP_NO_BUFFER,
+                priority=i)
+            self.controller.message_send(request)
+            do_barrier(self.controller)
+            verify_no_errors(self.controller)
+            self.verify_checksums()
+
+        # Delete flows in random order
+        for i, checksum in shuffled(enumerate(checksums)):
+            self.remove_checksum(checksum)
+            request = ofp.message.flow_delete_strict(
+                table_id=TABLE_ID,
+                priority=i,
+                out_port=ofp.OFPP_ANY,
+                out_group=ofp.OFPG_ANY)
+            self.controller.message_send(request)
+            do_barrier(self.controller)
+            verify_no_errors(self.controller)
+            self.verify_checksums()
+
+        # Deleted all flows, table checksum should be 0
+        self.assertEquals(self.get_table_checksum(), 0)
+
+class Resize(FlowChecksumBase):
+    """
+    Resize the checksum buckets, checking limits and redistribution
+    """
+    def runTest(self):
+        delete_all_flows(self.controller)
+
+        self.assertEquals(self.get_table_checksum(), 0)
+
+        self.set_buckets_size(128)
+        self.verify_checksums()
+
+        checksums = [random.randint(0, 2**64-1) for _ in xrange(0, 128)]
+
+        # Add flows
+        for i, checksum in enumerate(checksums):
+            self.insert_checksum(checksum)
+            request = ofp.message.flow_add(
+                table_id=TABLE_ID,
+                cookie=checksum,
+                buffer_id=ofp.OFP_NO_BUFFER,
+                priority=i)
+            self.controller.message_send(request)
+            if i % 17 == 0:
+                do_barrier(self.controller)
+                verify_no_errors(self.controller)
+                self.verify_checksums()
+
+        do_barrier(self.controller)
+        verify_no_errors(self.controller)
+        self.verify_checksums()
+
+        # Shrink checksum buckets
+        self.set_buckets_size(64)
+        self.verify_checksums()
+
+        # Shrink checksum buckets to minimum
+        self.set_buckets_size(1)
+        self.verify_checksums()
+
+        # Grow checksum buckets
+        self.set_buckets_size(2)
+        self.verify_checksums()
+
+        # Grow checksum buckets
+        self.set_buckets_size(256)
+        self.verify_checksums()
+
+        # Grow checksum buckets to maximum
+        self.set_buckets_size(65536)
+        self.verify_checksums()
+
+        # Delete flows
+        for i, checksum in enumerate(checksums):
+            self.remove_checksum(checksum)
+            request = ofp.message.flow_delete_strict(
+                table_id=TABLE_ID,
+                priority=i,
+                out_port=ofp.OFPP_ANY,
+                out_group=ofp.OFPG_ANY)
+            self.controller.message_send(request)
+            if i % 17 == 0:
+                do_barrier(self.controller)
+                verify_no_errors(self.controller)
+                self.verify_checksums()
+
+        do_barrier(self.controller)
+        verify_no_errors(self.controller)
+        self.verify_checksums()
+
+        # Deleted all flows, table checksum should be 0
+        self.assertEquals(self.get_table_checksum(), 0)
+
+class ResizeError(FlowChecksumBase):
+    """
+    Check that the switch rejects invalid checksum buckets sizes
+    """
+    def runTest(self):
+        # buckets_size = 0
+        self.controller.message_send(
+            ofp.message.bsn_table_set_buckets_size(
+                table_id=TABLE_ID, buckets_size=0))
+        do_barrier(self.controller)
+        error, _ = self.controller.poll(ofp.OFPT_ERROR)
+        self.assertIsInstance(error, ofp.message.error_msg)
+
+        # buckets_size = 3
+        self.controller.message_send(
+            ofp.message.bsn_table_set_buckets_size(
+                table_id=TABLE_ID, buckets_size=3))
+        do_barrier(self.controller)
+        error, _ = self.controller.poll(ofp.OFPT_ERROR)
+        self.assertIsInstance(error, ofp.message.error_msg)
+
+        # buckets_size = 100
+        self.controller.message_send(
+            ofp.message.bsn_table_set_buckets_size(
+                table_id=TABLE_ID, buckets_size=100))
+        do_barrier(self.controller)
+        error, _ = self.controller.poll(ofp.OFPT_ERROR)
+        self.assertIsInstance(error, ofp.message.error_msg)
+
+        # buckets_size = 2**32 - 1
+        self.controller.message_send(
+            ofp.message.bsn_table_set_buckets_size(
+                table_id=TABLE_ID, buckets_size=2**32-1))
+        do_barrier(self.controller)
+        error, _ = self.controller.poll(ofp.OFPT_ERROR)
+        self.assertIsInstance(error, ofp.message.error_msg)
+
+        # buckets_size = 2**31
+        self.controller.message_send(
+            ofp.message.bsn_table_set_buckets_size(
+                table_id=TABLE_ID, buckets_size=2**31))
+        do_barrier(self.controller)
+        error, _ = self.controller.poll(ofp.OFPT_ERROR)
+        self.assertIsInstance(error, ofp.message.error_msg)
diff --git a/tests-1.3/bsn_gentable.py b/tests-1.3/bsn_gentable.py
index e9f3145..915729c 100644
--- a/tests-1.3/bsn_gentable.py
+++ b/tests-1.3/bsn_gentable.py
@@ -702,8 +702,7 @@
         do_barrier(self.controller)
 
         error, _ = self.controller.poll(ofp.OFPT_ERROR, 0)
-        self.assertIsInstance(error, ofp.message.bad_request_error_msg)
-        self.assertEquals(error.code, ofp.OFPBRC_EPERM)
+        self.assertEquals(error, None)
 
 class DeleteFailureError(BaseGenTableTest):
     """
diff --git a/tests-1.3/bsn_role_status.py b/tests-1.3/bsn_role_status.py
new file mode 100644
index 0000000..957738a
--- /dev/null
+++ b/tests-1.3/bsn_role_status.py
@@ -0,0 +1,92 @@
+"""
+Test the BSN role status message
+
+This is a backport of the OpenFlow 1.4 functionality.
+"""
+import struct
+import unittest
+import logging
+
+import oftest
+from oftest import config
+import oftest.controller as controller
+import ofp
+import oftest.base_tests as base_tests
+
+from oftest.testutils import *
+
+def simple_role_request(test, role, gen=None, con=None):
+    """
+    Send a role request we expect to succeed
+    """
+    if con == None:
+        con = test.controller
+    request = ofp.message.role_request(role=role, generation_id=gen)
+    response, _ = con.transact(request)
+    test.assertTrue(isinstance(response, ofp.message.role_reply), "Expected a role reply")
+    if role != ofp.OFPCR_ROLE_NOCHANGE:
+        test.assertEquals(response.role, role)
+    if gen != None:
+        test.assertEquals(response.generation_id, gen)
+    return response.role, response.generation_id
+
+@disabled
+@nonstandard
+class RoleStatus(unittest.TestCase):
+    """
+    Verify that when a connection becomes a master the existing master is
+    downgraded to slave and receives a role-status message.
+
+    Requires the switch to attempt to connect in parallel to ports 6653
+    and 6753 on the configured IP.
+    """
+
+    def setUp(self):
+        host = config["controller_host"]
+        self.controllers = [
+            controller.Controller(host=host,port=6653),
+            controller.Controller(host=host,port=6753)
+        ]
+
+    def runTest(self):
+        # Connect and handshake with both controllers
+        for con in self.controllers:
+            con.start()
+            if not con.connect():
+                raise AssertionError("failed to connect controller %s" % str(con))
+            reply, _ = con.transact(ofp.message.features_request())
+            self.assertTrue(isinstance(reply, ofp.message.features_reply))
+
+        # Assert initial role and get generation IDs
+        role, gen0 = simple_role_request(self, ofp.OFPCR_ROLE_NOCHANGE, con=self.controllers[0])
+        self.assertEqual(role, ofp.OFPCR_ROLE_EQUAL)
+        role, gen1 = simple_role_request(self, ofp.OFPCR_ROLE_NOCHANGE, con=self.controllers[1])
+        self.assertEqual(role, ofp.OFPCR_ROLE_EQUAL)
+
+        # Initial role assignment: controller 0 is master, controller 1 is slave
+        simple_role_request(self, ofp.OFPCR_ROLE_MASTER, gen0, con=self.controllers[0])
+        simple_role_request(self, ofp.OFPCR_ROLE_SLAVE, gen1, con=self.controllers[1])
+        self.verify_role(self.controllers[0], ofp.OFPCR_ROLE_MASTER)
+        self.verify_role(self.controllers[1], ofp.OFPCR_ROLE_SLAVE)
+
+        # Controller 1 requests master
+        # Controller 0 becomes slave
+        simple_role_request(self, ofp.OFPCR_ROLE_MASTER, gen1, con=self.controllers[1])
+        self.verify_role(self.controllers[0], ofp.OFPCR_ROLE_SLAVE)
+        self.verify_role(self.controllers[1], ofp.OFPCR_ROLE_MASTER)
+
+        # Controller 0 should receive a bsn_role_status message
+        msg, _ = self.controllers[0].poll(ofp.OFPT_EXPERIMENTER)
+        self.assertIsInstance(msg, ofp.message.bsn_role_status)
+        self.assertEqual(msg.role, ofp.OFPCR_ROLE_SLAVE)
+        self.assertEqual(msg.reason, ofp.OFP_BSN_CONTROLLER_ROLE_REASON_MASTER_REQUEST)
+        self.assertEqual(msg.generation_id, gen1)
+
+    def verify_role(self, con, role):
+        rcv_role, _ = simple_role_request(self, ofp.OFPCR_ROLE_NOCHANGE, con=con)
+        self.assertEqual(rcv_role, role)
+
+    def tearDown(self):
+        for con in self.controllers:
+            con.shutdown()
+
diff --git a/tests-1.3/flow_mod.py b/tests-1.3/flow_mod.py
new file mode 100644
index 0000000..2f0e711
--- /dev/null
+++ b/tests-1.3/flow_mod.py
@@ -0,0 +1,88 @@
+# Distributed under the OpenFlow Software License (see LICENSE)
+# Copyright (c) 2014 Big Switch Networks, Inc.
+"""
+Flow-mod test cases
+"""
+
+import logging
+
+import oftest
+from oftest import config
+import oftest.base_tests as base_tests
+import ofp
+from loxi.pp import pp
+
+from oftest.testutils import *
+from oftest.parse import parse_ipv6
+
+class Overwrite(base_tests.SimpleDataPlane):
+    """
+    Verify that overwriting a flow changes most fields but preserves stats
+    """
+    def runTest(self):
+        in_port, out_port1, out_port2 = openflow_ports(3)
+
+        delete_all_flows(self.controller)
+
+        table_id = test_param_get("table", 0)
+        match = ofp.match([
+            ofp.oxm.in_port(in_port),
+        ])
+        priority = 1000
+
+        logging.info("Inserting flow")
+        request = ofp.message.flow_add(
+                table_id=table_id,
+                match=match,
+                instructions=[
+                    ofp.instruction.apply_actions([ofp.action.output(out_port1)]),
+                ],
+                buffer_id=ofp.OFP_NO_BUFFER,
+                priority=priority,
+                flags=ofp.OFPFF_SEND_FLOW_REM,
+                cookie=0x1234,
+                hard_timeout=1000,
+                idle_timeout=2000)
+        self.controller.message_send(request)
+        do_barrier(self.controller)
+
+        # Send a packet through so that we can check stats were preserved
+        self.dataplane.send(in_port, str(simple_tcp_packet(pktlen=100)))
+        verify_flow_stats(self, ofp.match(), table_id=table_id, pkts=1)
+
+        # Send a flow-add with the same table_id, match, and priority, causing
+        # an overwrite
+        logging.info("Overwriting flow")
+        request = ofp.message.flow_add(
+                table_id=table_id,
+                match=match,
+                instructions=[
+                    ofp.instruction.apply_actions([ofp.action.output(out_port2)]),
+                ],
+                buffer_id=ofp.OFP_NO_BUFFER,
+                priority=priority,
+                flags=0,
+                cookie=0xabcd,
+                hard_timeout=3000,
+                idle_timeout=4000)
+        self.controller.message_send(request)
+        do_barrier(self.controller)
+
+        # Should not get a flow-removed message
+        msg, _ = self.controller.poll(exp_msg=ofp.message.flow_removed,
+                                      timeout=oftest.ofutils.default_negative_timeout)
+        self.assertEquals(msg, None)
+
+        # Check that the fields in the flow stats entry match the second flow-add
+        stats = get_flow_stats(self, ofp.match())
+        self.assertEquals(len(stats), 1)
+        entry = stats[0]
+        logging.debug(entry.show())
+        self.assertEquals(entry.instructions, request.instructions)
+        self.assertEquals(entry.flags, request.flags)
+        self.assertEquals(entry.cookie, request.cookie)
+        self.assertEquals(entry.hard_timeout, request.hard_timeout)
+        self.assertEquals(entry.idle_timeout, request.idle_timeout)
+
+        # Flow stats should have been preserved
+        verify_flow_stats(self, ofp.match(), table_id=table_id, pkts=1)
diff --git a/tests/latency.py b/tests/latency.py
new file mode 100644
index 0000000..3cf8c5d
--- /dev/null
+++ b/tests/latency.py
@@ -0,0 +1,107 @@
+"""
+Latency tests
+
+These tests are mostly helpful for finding an optimal value for the
+--default-negative-timeout option. If this value is too large it will
+unnecessarily some down testing, but if it is too small then tests
+may pass when they should have failed.
+
+Most of this latency is caused by OFTest. Actual switch latency should be just
+a few microseconds, but OFTest can add milliseconds on top of that.
+"""
+
+import logging
+import unittest
+import time
+
+from oftest import config
+import ofp
+import oftest.base_tests as base_tests
+
+from oftest.testutils import *
+
+class DataplaneLatency(base_tests.SimpleDataPlane):
+    """
+    Measure and assert dataplane latency
+
+    All packets must arrive within the default timeout, and 90% must
+    arrive within the default negative timeout.
+    """
+    def runTest(self):
+        in_port, out_port = openflow_ports(2)
+
+        delete_all_flows(self.controller)
+
+        pkt = str(simple_tcp_packet())
+
+        request = ofp.message.flow_add(
+            match=ofp.match(wildcards=ofp.OFPFW_ALL),
+            buffer_id=0xffffffff,
+            actions=[ofp.action.output(out_port)])
+        
+        self.controller.message_send(request)
+        do_barrier(self.controller)
+
+        latencies = []
+        for i in xrange(0, 1000):
+            start_time = time.time()
+            self.dataplane.send(in_port, pkt)
+            verify_packet(self, pkt, out_port)
+            end_time = time.time()
+            latencies.append(end_time - start_time)
+
+        latencies.sort()
+        
+        latency_min = latencies[0]
+        latency_90 = latencies[int(len(latencies)*0.9)]
+        latency_max = latencies[-1]
+
+        logging.debug("Minimum latency: %f ms", latency_min * 1000.0)
+        logging.debug("90%% latency: %f ms", latency_90 * 1000.0)
+        logging.debug("Maximum latency: %f ms", latency_max * 1000.0)
+
+        self.assertGreater(config["default_timeout"], latency_max)
+        self.assertGreater(config["default_negative_timeout"], latency_90)
+
+class PktinLatency(base_tests.SimpleDataPlane):
+    """
+    Measure and assert packet-in latency
+
+    All packet-ins must arrive within the default timeout, and 90% must
+    arrive within the default negative timeout.
+    """
+    def runTest(self):
+        in_port, = openflow_ports(1)
+
+        delete_all_flows(self.controller)
+
+        pkt = str(simple_tcp_packet())
+
+        request = ofp.message.flow_add(
+            match=ofp.match(wildcards=ofp.OFPFW_ALL),
+            buffer_id=0xffffffff,
+            actions=[ofp.action.output(ofp.OFPP_CONTROLLER)])
+        
+        self.controller.message_send(request)
+        do_barrier(self.controller)
+
+        latencies = []
+        for i in xrange(0, 1000):
+            start_time = time.time()
+            self.dataplane.send(in_port, pkt)
+            verify_packet_in(self, pkt, in_port, ofp.OFPR_ACTION)
+            end_time = time.time()
+            latencies.append(end_time - start_time)
+
+        latencies.sort()
+        
+        latency_min = latencies[0]
+        latency_90 = latencies[int(len(latencies)*0.9)]
+        latency_max = latencies[-1]
+
+        logging.debug("Minimum latency: %f ms", latency_min * 1000.0)
+        logging.debug("90%% latency: %f ms", latency_90 * 1000.0)
+        logging.debug("Maximum latency: %f ms", latency_max * 1000.0)
+
+        self.assertGreater(config["default_timeout"], latency_max)
+        self.assertGreater(config["default_negative_timeout"], latency_90)
diff --git a/tests/openflow_protocol_messages.py b/tests/openflow_protocol_messages.py
index 50c7eae..ded727e 100644
--- a/tests/openflow_protocol_messages.py
+++ b/tests/openflow_protocol_messages.py
@@ -278,30 +278,6 @@
         verify_packet_in(self, str(pkt), ingress_port, ofp.OFPR_NO_MATCH)
 
 
-class Hello(base_tests.SimpleDataPlane):
-    
-    """Test Hello messages are implemented
-    a) Create Hello messages from controller
-    b) Verify switch also exchanges hello message -- (Poll the control plane)
-    d) Verify the version field in the hello messages is openflow 1.0.0 """
-
-    def runTest(self):
-        
-        logging.info("Running Hello test")
-
-        logging.info("Sending Hello")
-        logging.info("Expecting a Hello on the control plane with version--1.0.0")
-        
-        #Send Hello message
-        request = ofp.message.hello()
-        (response, pkt) = self.controller.poll(exp_msg=ofp.OFPT_HELLO,
-                                               timeout=1)
-        self.assertTrue(response is not None, 
-                               'Switch did not exchange hello message in return') 
-        self.assertTrue(response.version == 0x01, 'switch openflow-version field is not 1.0.0')
-
-
-
 class EchoWithoutBody(base_tests.SimpleProtocol):
     
     """Test basic echo-reply is implemented