update pyloxi to 026ff024585f1588a7f11fa4c1a9a48d44dc098d
diff --git a/src/python/loxi/of13/common.py b/src/python/loxi/of13/common.py
index 08fe0ec..8d86467 100644
--- a/src/python/loxi/of13/common.py
+++ b/src/python/loxi/of13/common.py
@@ -2,116 +2,24 @@
 # Copyright (c) 2011, 2012 Open Networking Foundation
 # Copyright (c) 2012, 2013 Big Switch Networks, Inc.
 # See the file LICENSE.pyloxi which should have been included in the source distribution
-# Automatically generated by LOXI from template common.py
+
+# Automatically generated by LOXI from template module.py
 # Do not modify
 
-import sys
 import struct
-import action
-import instruction # for unpack_list
-import meter_band # for unpack_list
+import loxi
 import const
+import common
+import action
+import instruction
+import oxm
+import action_id
+import instruction_id
+import meter_band
 import util
 import loxi.generic_util
 
-import oxm
-
-# HACK make this module visible as 'common' to simplify code generation
-common = sys.modules[__name__]
-
-def unpack_list_flow_stats_entry(reader):
-    return loxi.generic_util.unpack_list_lv16(reader, flow_stats_entry.unpack)
-
-def unpack_list_queue_prop(reader):
-    def deserializer(reader, typ):
-        if typ == const.OFPQT_MIN_RATE:
-            return queue_prop_min_rate.unpack(reader)
-        else:
-            raise loxi.ProtocolError("unknown queue prop %d" % typ)
-    return loxi.generic_util.unpack_list_tlv16(reader, deserializer)
-
-def unpack_list_packet_queue(reader):
-    def wrapper(reader):
-        length, = reader.peek('!4xH')
-        return packet_queue.unpack(reader.slice(length))
-    return loxi.generic_util.unpack_list(reader, wrapper)
-
-def unpack_list_hello_elem(reader):
-    def deserializer(reader, typ):
-        if typ == const.OFPHET_VERSIONBITMAP:
-            return hello_elem_versionbitmap.unpack(reader)
-        else:
-            return None
-    return [x for x in loxi.generic_util.unpack_list_tlv16(reader, deserializer) if x != None]
-
-def unpack_list_bucket(reader):
-    return loxi.generic_util.unpack_list_lv16(reader, bucket.unpack)
-
-def unpack_list_group_desc_stats_entry(reader):
-    return loxi.generic_util.unpack_list_lv16(reader, group_desc_stats_entry.unpack)
-
-def unpack_list_group_stats_entry(reader):
-    return loxi.generic_util.unpack_list_lv16(reader, group_stats_entry.unpack)
-
-def unpack_list_meter_stats(reader):
-    def wrapper(reader):
-        length, = reader.peek('!4xH')
-        return meter_stats.unpack(reader.slice(length))
-    return loxi.generic_util.unpack_list(reader, wrapper)
-
-class action_id(object):
-
-    def __init__(self, type=None):
-        if type != None:
-            self.type = type
-        else:
-            self.type = 0
-        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('\x00' * 4)
-        length = sum([len(x) for x in packed])
-        packed[1] = struct.pack("!H", length)
-        return ''.join(packed)
-
-    @staticmethod
-    def unpack(buf):
-        obj = action_id()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
-        obj.type = reader.read("!H")[0]
-        _len = reader.read("!H")[0]
-        reader.skip(4)
-        return obj
-
-    def __eq__(self, other):
-        if type(self) != type(other): return False
-        if self.type != other.type: return False
-        return True
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
-    def pretty_print(self, q):
-        q.text("action_id {")
-        with q.group():
-            with q.indent(2):
-                q.breakable()
-                q.text("type = ");
-                q.text("%#x" % self.type)
-            q.breakable()
-        q.text('}')
-
-class bsn_interface(object):
+class bsn_interface(loxi.OFObject):
 
     def __init__(self, hw_addr=None, name=None, ipv4_addr=None, ipv4_netmask=None):
         if hw_addr != None:
@@ -142,12 +50,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_interface()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         obj.hw_addr = list(reader.read('!6B'))
         reader.skip(2)
         obj.name = reader.read("!16s")[0].rstrip("\x00")
@@ -163,13 +67,6 @@
         if self.ipv4_netmask != other.ipv4_netmask: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_interface {")
         with q.group():
@@ -189,7 +86,8 @@
             q.breakable()
         q.text('}')
 
-class bsn_lacp_stats_entry(object):
+
+class bsn_lacp_stats_entry(loxi.OFObject):
 
     def __init__(self, port_no=None, actor_sys_priority=None, actor_sys_mac=None, actor_port_priority=None, actor_port_num=None, actor_key=None, convergence_status=None, partner_sys_priority=None, partner_sys_mac=None, partner_port_priority=None, partner_port_num=None, partner_key=None):
         if port_no != None:
@@ -261,12 +159,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_lacp_stats_entry()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         obj.port_no = util.unpack_port_no(reader)
         obj.actor_sys_priority = reader.read("!H")[0]
         obj.actor_sys_mac = list(reader.read('!6B'))
@@ -299,13 +193,6 @@
         if self.partner_key != other.partner_key: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_lacp_stats_entry {")
         with q.group():
@@ -349,7 +236,111 @@
             q.breakable()
         q.text('}')
 
-class bsn_vport_q_in_q(object):
+
+class bsn_port_counter_stats_entry(loxi.OFObject):
+
+    def __init__(self, port_no=None, values=None):
+        if port_no != None:
+            self.port_no = port_no
+        else:
+            self.port_no = 0
+        if values != None:
+            self.values = values
+        else:
+            self.values = []
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!H", 0)) # placeholder for length at index 0
+        packed.append('\x00' * 2)
+        packed.append(util.pack_port_no(self.port_no))
+        packed.append(loxi.generic_util.pack_list(self.values))
+        length = sum([len(x) for x in packed])
+        packed[0] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_port_counter_stats_entry()
+        _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (0 + 2))
+        reader.skip(2)
+        obj.port_no = util.unpack_port_no(reader)
+        obj.values = loxi.generic_util.unpack_list(reader, common.uint64.unpack)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.port_no != other.port_no: return False
+        if self.values != other.values: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_port_counter_stats_entry {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("port_no = ");
+                q.text(util.pretty_port(self.port_no))
+                q.text(","); q.breakable()
+                q.text("values = ");
+                q.pp(self.values)
+            q.breakable()
+        q.text('}')
+
+
+class bsn_switch_pipeline_stats_entry(loxi.OFObject):
+
+    def __init__(self, pipeline=None):
+        if pipeline != None:
+            self.pipeline = pipeline
+        else:
+            self.pipeline = ""
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!256s", self.pipeline))
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_switch_pipeline_stats_entry()
+        obj.pipeline = reader.read("!256s")[0].rstrip("\x00")
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.pipeline != other.pipeline: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_switch_pipeline_stats_entry {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("pipeline = ");
+                q.pp(self.pipeline)
+            q.breakable()
+        q.text('}')
+
+
+class bsn_vport(loxi.OFObject):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 0)
+        try:
+            subclass = bsn_vport.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown bsn_vport subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+
+class bsn_vport_q_in_q(bsn_vport):
     type = 0
 
     def __init__(self, port_no=None, ingress_tpid=None, ingress_vlan_id=None, egress_tpid=None, egress_vlan_id=None, if_name=None):
@@ -394,15 +385,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_vport_q_in_q()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 0)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.port_no = reader.read("!L")[0]
         obj.ingress_tpid = reader.read("!H")[0]
         obj.ingress_vlan_id = reader.read("!H")[0]
@@ -421,13 +410,6 @@
         if self.if_name != other.if_name: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_vport_q_in_q {")
         with q.group():
@@ -453,7 +435,63 @@
             q.breakable()
         q.text('}')
 
-class bucket(object):
+bsn_vport.subtypes[0] = bsn_vport_q_in_q
+
+class bsn_vlan_counter_stats_entry(loxi.OFObject):
+
+    def __init__(self, vlan_vid=None, values=None):
+        if vlan_vid != None:
+            self.vlan_vid = vlan_vid
+        else:
+            self.vlan_vid = 0
+        if values != None:
+            self.values = values
+        else:
+            self.values = []
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!H", 0)) # placeholder for length at index 0
+        packed.append(struct.pack("!H", self.vlan_vid))
+        packed.append('\x00' * 4)
+        packed.append(loxi.generic_util.pack_list(self.values))
+        length = sum([len(x) for x in packed])
+        packed[0] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_vlan_counter_stats_entry()
+        _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (0 + 2))
+        obj.vlan_vid = reader.read("!H")[0]
+        reader.skip(4)
+        obj.values = loxi.generic_util.unpack_list(reader, common.uint64.unpack)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.vlan_vid != other.vlan_vid: return False
+        if self.values != other.values: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_vlan_counter_stats_entry {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("vlan_vid = ");
+                q.text("%#x" % self.vlan_vid)
+                q.text(","); q.breakable()
+                q.text("values = ");
+                q.pp(self.values)
+            q.breakable()
+        q.text('}')
+
+
+class bucket(loxi.OFObject):
 
     def __init__(self, weight=None, watch_port=None, watch_group=None, actions=None):
         if weight != None:
@@ -481,24 +519,22 @@
         packed.append(util.pack_port_no(self.watch_port))
         packed.append(struct.pack("!L", self.watch_group))
         packed.append('\x00' * 4)
-        packed.append(util.pack_list(self.actions))
+        packed.append(loxi.generic_util.pack_list(self.actions))
         length = sum([len(x) for x in packed])
         packed[0] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bucket()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (0 + 2))
         obj.weight = reader.read("!H")[0]
         obj.watch_port = util.unpack_port_no(reader)
         obj.watch_group = reader.read("!L")[0]
         reader.skip(4)
-        obj.actions = action.unpack_list(reader)
+        obj.actions = loxi.generic_util.unpack_list(reader, action.action.unpack)
         return obj
 
     def __eq__(self, other):
@@ -509,13 +545,6 @@
         if self.actions != other.actions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bucket {")
         with q.group():
@@ -535,7 +564,8 @@
             q.breakable()
         q.text('}')
 
-class bucket_counter(object):
+
+class bucket_counter(loxi.OFObject):
 
     def __init__(self, packet_count=None, byte_count=None):
         if packet_count != None:
@@ -555,12 +585,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bucket_counter()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         obj.packet_count = reader.read("!Q")[0]
         obj.byte_count = reader.read("!Q")[0]
         return obj
@@ -571,13 +597,6 @@
         if self.byte_count != other.byte_count: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bucket_counter {")
         with q.group():
@@ -591,7 +610,21 @@
             q.breakable()
         q.text('}')
 
-class flow_stats_entry(object):
+
+class experimenter_stats_header(loxi.OFObject):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 0)
+        try:
+            subclass = experimenter_stats_header.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter_stats_header subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+
+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):
         if table_id != None:
@@ -660,19 +693,17 @@
         packed.append(struct.pack("!Q", self.packet_count))
         packed.append(struct.pack("!Q", self.byte_count))
         packed.append(self.match.pack())
-        packed.append(util.pack_list(self.instructions))
+        packed.append(loxi.generic_util.pack_list(self.instructions))
         length = sum([len(x) for x in packed])
         packed[0] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = flow_stats_entry()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (0 + 2))
         obj.table_id = reader.read("!B")[0]
         reader.skip(1)
         obj.duration_sec = reader.read("!L")[0]
@@ -686,7 +717,7 @@
         obj.packet_count = reader.read("!Q")[0]
         obj.byte_count = reader.read("!Q")[0]
         obj.match = common.match.unpack(reader)
-        obj.instructions = instruction.unpack_list(reader)
+        obj.instructions = loxi.generic_util.unpack_list(reader, instruction.instruction.unpack)
         return obj
 
     def __eq__(self, other):
@@ -705,13 +736,6 @@
         if self.instructions != other.instructions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_stats_entry {")
         with q.group():
@@ -755,7 +779,8 @@
             q.breakable()
         q.text('}')
 
-class group_desc_stats_entry(object):
+
+class group_desc_stats_entry(loxi.OFObject):
 
     def __init__(self, group_type=None, group_id=None, buckets=None):
         if group_type != None:
@@ -778,23 +803,21 @@
         packed.append(struct.pack("!B", self.group_type))
         packed.append('\x00' * 1)
         packed.append(struct.pack("!L", self.group_id))
-        packed.append(util.pack_list(self.buckets))
+        packed.append(loxi.generic_util.pack_list(self.buckets))
         length = sum([len(x) for x in packed])
         packed[0] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = group_desc_stats_entry()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (0 + 2))
         obj.group_type = reader.read("!B")[0]
         reader.skip(1)
         obj.group_id = reader.read("!L")[0]
-        obj.buckets = common.unpack_list_bucket(reader)
+        obj.buckets = loxi.generic_util.unpack_list(reader, common.bucket.unpack)
         return obj
 
     def __eq__(self, other):
@@ -804,13 +827,6 @@
         if self.buckets != other.buckets: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_desc_stats_entry {")
         with q.group():
@@ -827,7 +843,8 @@
             q.breakable()
         q.text('}')
 
-class group_stats_entry(object):
+
+class group_stats_entry(loxi.OFObject):
 
     def __init__(self, group_id=None, ref_count=None, packet_count=None, byte_count=None, duration_sec=None, duration_nsec=None, bucket_stats=None):
         if group_id != None:
@@ -871,19 +888,17 @@
         packed.append(struct.pack("!Q", self.byte_count))
         packed.append(struct.pack("!L", self.duration_sec))
         packed.append(struct.pack("!L", self.duration_nsec))
-        packed.append(util.pack_list(self.bucket_stats))
+        packed.append(loxi.generic_util.pack_list(self.bucket_stats))
         length = sum([len(x) for x in packed])
         packed[0] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = group_stats_entry()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (0 + 2))
         reader.skip(2)
         obj.group_id = reader.read("!L")[0]
         obj.ref_count = reader.read("!L")[0]
@@ -906,13 +921,6 @@
         if self.bucket_stats != other.bucket_stats: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_stats_entry {")
         with q.group():
@@ -941,7 +949,21 @@
             q.breakable()
         q.text('}')
 
-class hello_elem_versionbitmap(object):
+
+class hello_elem(loxi.OFObject):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 0)
+        try:
+            subclass = hello_elem.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown hello_elem subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+
+class hello_elem_versionbitmap(hello_elem):
     type = 1
 
     def __init__(self, bitmaps=None):
@@ -955,21 +977,19 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for length at index 1
-        packed.append(util.pack_list(self.bitmaps))
+        packed.append(loxi.generic_util.pack_list(self.bitmaps))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = hello_elem_versionbitmap()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.bitmaps = loxi.generic_util.unpack_list(reader, common.uint32.unpack)
         return obj
 
@@ -978,13 +998,6 @@
         if self.bitmaps != other.bitmaps: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("hello_elem_versionbitmap {")
         with q.group():
@@ -995,7 +1008,9 @@
             q.breakable()
         q.text('}')
 
-class match_v3(object):
+hello_elem.subtypes[1] = hello_elem_versionbitmap
+
+class match_v3(loxi.OFObject):
     type = 1
 
     def __init__(self, oxm_list=None):
@@ -1009,24 +1024,22 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for length at index 1
-        packed.append(util.pack_list(self.oxm_list))
+        packed.append(loxi.generic_util.pack_list(self.oxm_list))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         packed.append(loxi.generic_util.pad_to(8, length))
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = match_v3()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
-        obj.oxm_list = oxm.unpack_list(reader.slice(_length-4))
-        reader.skip_align()
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
+        obj.oxm_list = loxi.generic_util.unpack_list(reader, oxm.oxm.unpack)
+        orig_reader.skip_align()
         return obj
 
     def __eq__(self, other):
@@ -1034,13 +1047,6 @@
         if self.oxm_list != other.oxm_list: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("match_v3 {")
         with q.group():
@@ -1051,7 +1057,8 @@
             q.breakable()
         q.text('}')
 
-class meter_band_stats(object):
+
+class meter_band_stats(loxi.OFObject):
 
     def __init__(self, packet_band_count=None, byte_band_count=None):
         if packet_band_count != None:
@@ -1071,12 +1078,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = meter_band_stats()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         obj.packet_band_count = reader.read("!Q")[0]
         obj.byte_band_count = reader.read("!Q")[0]
         return obj
@@ -1087,13 +1090,6 @@
         if self.byte_band_count != other.byte_band_count: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("meter_band_stats {")
         with q.group():
@@ -1107,7 +1103,8 @@
             q.breakable()
         q.text('}')
 
-class meter_config(object):
+
+class meter_config(loxi.OFObject):
 
     def __init__(self, flags=None, meter_id=None, entries=None):
         if flags != None:
@@ -1129,22 +1126,20 @@
         packed.append(struct.pack("!H", 0)) # placeholder for length at index 0
         packed.append(struct.pack("!H", self.flags))
         packed.append(struct.pack("!L", self.meter_id))
-        packed.append(util.pack_list(self.entries))
+        packed.append(loxi.generic_util.pack_list(self.entries))
         length = sum([len(x) for x in packed])
         packed[0] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = meter_config()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (0 + 2))
         obj.flags = reader.read("!H")[0]
         obj.meter_id = reader.read("!L")[0]
-        obj.entries = meter_band.unpack_list(reader)
+        obj.entries = loxi.generic_util.unpack_list(reader, meter_band.meter_band.unpack)
         return obj
 
     def __eq__(self, other):
@@ -1154,13 +1149,6 @@
         if self.entries != other.entries: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("meter_config {")
         with q.group():
@@ -1177,7 +1165,8 @@
             q.breakable()
         q.text('}')
 
-class meter_features(object):
+
+class meter_features(loxi.OFObject):
 
     def __init__(self, max_meter=None, band_types=None, capabilities=None, max_bands=None, max_color=None):
         if max_meter != None:
@@ -1213,12 +1202,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = meter_features()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         obj.max_meter = reader.read("!L")[0]
         obj.band_types = reader.read("!L")[0]
         obj.capabilities = reader.read("!L")[0]
@@ -1236,13 +1221,6 @@
         if self.max_color != other.max_color: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("meter_features {")
         with q.group():
@@ -1265,7 +1243,8 @@
             q.breakable()
         q.text('}')
 
-class meter_stats(object):
+
+class meter_stats(loxi.OFObject):
 
     def __init__(self, meter_id=None, flow_count=None, packet_in_count=None, byte_in_count=None, duration_sec=None, duration_nsec=None, band_stats=None):
         if meter_id != None:
@@ -1308,20 +1287,18 @@
         packed.append(struct.pack("!Q", self.byte_in_count))
         packed.append(struct.pack("!L", self.duration_sec))
         packed.append(struct.pack("!L", self.duration_nsec))
-        packed.append(util.pack_list(self.band_stats))
+        packed.append(loxi.generic_util.pack_list(self.band_stats))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = meter_stats()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         obj.meter_id = reader.read("!L")[0]
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (4 + 2))
         reader.skip(6)
         obj.flow_count = reader.read("!L")[0]
         obj.packet_in_count = reader.read("!Q")[0]
@@ -1342,13 +1319,6 @@
         if self.band_stats != other.band_stats: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("meter_stats {")
         with q.group():
@@ -1377,7 +1347,8 @@
             q.breakable()
         q.text('}')
 
-class packet_queue(object):
+
+class packet_queue(loxi.OFObject):
 
     def __init__(self, queue_id=None, port=None, properties=None):
         if queue_id != None:
@@ -1400,23 +1371,21 @@
         packed.append(util.pack_port_no(self.port))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 2
         packed.append('\x00' * 6)
-        packed.append(util.pack_list(self.properties))
+        packed.append(loxi.generic_util.pack_list(self.properties))
         length = sum([len(x) for x in packed])
         packed[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = packet_queue()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         obj.queue_id = reader.read("!L")[0]
         obj.port = util.unpack_port_no(reader)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (8 + 2))
         reader.skip(6)
-        obj.properties = common.unpack_list_queue_prop(reader)
+        obj.properties = loxi.generic_util.unpack_list(reader, common.queue_prop.unpack)
         return obj
 
     def __eq__(self, other):
@@ -1426,13 +1395,6 @@
         if self.properties != other.properties: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("packet_queue {")
         with q.group():
@@ -1449,7 +1411,8 @@
             q.breakable()
         q.text('}')
 
-class port_desc(object):
+
+class port_desc(loxi.OFObject):
 
     def __init__(self, port_no=None, hw_addr=None, name=None, config=None, state=None, curr=None, advertised=None, supported=None, peer=None, curr_speed=None, max_speed=None):
         if port_no != None:
@@ -1516,12 +1479,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = port_desc()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         obj.port_no = util.unpack_port_no(reader)
         reader.skip(4)
         obj.hw_addr = list(reader.read('!6B'))
@@ -1552,13 +1511,6 @@
         if self.max_speed != other.max_speed: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_desc {")
         with q.group():
@@ -1599,7 +1551,8 @@
             q.breakable()
         q.text('}')
 
-class port_stats_entry(object):
+
+class port_stats_entry(loxi.OFObject):
 
     def __init__(self, port_no=None, rx_packets=None, tx_packets=None, rx_bytes=None, tx_bytes=None, rx_dropped=None, tx_dropped=None, rx_errors=None, tx_errors=None, rx_frame_err=None, rx_over_err=None, rx_crc_err=None, collisions=None, duration_sec=None, duration_nsec=None):
         if port_no != None:
@@ -1685,12 +1638,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = port_stats_entry()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         obj.port_no = util.unpack_port_no(reader)
         reader.skip(4)
         obj.rx_packets = reader.read("!Q")[0]
@@ -1728,13 +1677,6 @@
         if self.duration_nsec != other.duration_nsec: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_stats_entry {")
         with q.group():
@@ -1787,7 +1729,35 @@
             q.breakable()
         q.text('}')
 
-class queue_prop_max_rate(object):
+
+class queue_prop(loxi.OFObject):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 0)
+        try:
+            subclass = queue_prop.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown queue_prop subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+
+class queue_prop_experimenter(queue_prop):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 8)
+        try:
+            subclass = queue_prop_experimenter.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown queue_prop_experimenter queue_prop subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+queue_prop.subtypes[65535] = queue_prop_experimenter
+
+class queue_prop_max_rate(queue_prop):
     type = 2
 
     def __init__(self, rate=None):
@@ -1809,15 +1779,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = queue_prop_max_rate()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 2)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         obj.rate = reader.read("!H")[0]
         reader.skip(6)
@@ -1828,13 +1796,6 @@
         if self.rate != other.rate: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_prop_max_rate {")
         with q.group():
@@ -1845,7 +1806,9 @@
             q.breakable()
         q.text('}')
 
-class queue_prop_min_rate(object):
+queue_prop.subtypes[2] = queue_prop_max_rate
+
+class queue_prop_min_rate(queue_prop):
     type = 1
 
     def __init__(self, rate=None):
@@ -1867,15 +1830,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = queue_prop_min_rate()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 1)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         obj.rate = reader.read("!H")[0]
         reader.skip(6)
@@ -1886,13 +1847,6 @@
         if self.rate != other.rate: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_prop_min_rate {")
         with q.group():
@@ -1903,7 +1857,9 @@
             q.breakable()
         q.text('}')
 
-class queue_stats_entry(object):
+queue_prop.subtypes[1] = queue_prop_min_rate
+
+class queue_stats_entry(loxi.OFObject):
 
     def __init__(self, port_no=None, queue_id=None, tx_bytes=None, tx_packets=None, tx_errors=None, duration_sec=None, duration_nsec=None):
         if port_no != None:
@@ -1948,12 +1904,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = queue_stats_entry()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         obj.port_no = util.unpack_port_no(reader)
         obj.queue_id = reader.read("!L")[0]
         obj.tx_bytes = reader.read("!Q")[0]
@@ -1974,13 +1926,6 @@
         if self.duration_nsec != other.duration_nsec: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_stats_entry {")
         with q.group():
@@ -2009,7 +1954,21 @@
             q.breakable()
         q.text('}')
 
-class table_feature_prop_apply_actions(object):
+
+class table_feature_prop(loxi.OFObject):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 0)
+        try:
+            subclass = table_feature_prop.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown table_feature_prop subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+
+class table_feature_prop_apply_actions(table_feature_prop):
     type = 6
 
     def __init__(self, action_ids=None):
@@ -2023,22 +1982,20 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for length at index 1
-        packed.append(util.pack_list(self.action_ids))
+        packed.append(loxi.generic_util.pack_list(self.action_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = table_feature_prop_apply_actions()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 6)
         _length = reader.read("!H")[0]
-        obj.action_ids = loxi.unimplemented('unpack list(of_action_id_t)')
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
+        obj.action_ids = loxi.generic_util.unpack_list(reader, action_id.action_id.unpack)
         return obj
 
     def __eq__(self, other):
@@ -2046,13 +2003,6 @@
         if self.action_ids != other.action_ids: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_feature_prop_apply_actions {")
         with q.group():
@@ -2063,7 +2013,9 @@
             q.breakable()
         q.text('}')
 
-class table_feature_prop_apply_actions_miss(object):
+table_feature_prop.subtypes[6] = table_feature_prop_apply_actions
+
+class table_feature_prop_apply_actions_miss(table_feature_prop):
     type = 7
 
     def __init__(self, action_ids=None):
@@ -2077,22 +2029,20 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for length at index 1
-        packed.append(util.pack_list(self.action_ids))
+        packed.append(loxi.generic_util.pack_list(self.action_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = table_feature_prop_apply_actions_miss()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 7)
         _length = reader.read("!H")[0]
-        obj.action_ids = loxi.unimplemented('unpack list(of_action_id_t)')
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
+        obj.action_ids = loxi.generic_util.unpack_list(reader, action_id.action_id.unpack)
         return obj
 
     def __eq__(self, other):
@@ -2100,13 +2050,6 @@
         if self.action_ids != other.action_ids: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_feature_prop_apply_actions_miss {")
         with q.group():
@@ -2117,7 +2060,9 @@
             q.breakable()
         q.text('}')
 
-class table_feature_prop_apply_setfield(object):
+table_feature_prop.subtypes[7] = table_feature_prop_apply_actions_miss
+
+class table_feature_prop_apply_setfield(table_feature_prop):
     type = 14
 
     def __init__(self, oxm_ids=None):
@@ -2131,21 +2076,19 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for length at index 1
-        packed.append(util.pack_list(self.oxm_ids))
+        packed.append(loxi.generic_util.pack_list(self.oxm_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = table_feature_prop_apply_setfield()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 14)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.oxm_ids = loxi.generic_util.unpack_list(reader, common.uint32.unpack)
         return obj
 
@@ -2154,13 +2097,6 @@
         if self.oxm_ids != other.oxm_ids: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_feature_prop_apply_setfield {")
         with q.group():
@@ -2171,7 +2107,9 @@
             q.breakable()
         q.text('}')
 
-class table_feature_prop_apply_setfield_miss(object):
+table_feature_prop.subtypes[14] = table_feature_prop_apply_setfield
+
+class table_feature_prop_apply_setfield_miss(table_feature_prop):
     type = 15
 
     def __init__(self, oxm_ids=None):
@@ -2185,21 +2123,19 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for length at index 1
-        packed.append(util.pack_list(self.oxm_ids))
+        packed.append(loxi.generic_util.pack_list(self.oxm_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = table_feature_prop_apply_setfield_miss()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 15)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.oxm_ids = loxi.generic_util.unpack_list(reader, common.uint32.unpack)
         return obj
 
@@ -2208,13 +2144,6 @@
         if self.oxm_ids != other.oxm_ids: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_feature_prop_apply_setfield_miss {")
         with q.group():
@@ -2225,7 +2154,9 @@
             q.breakable()
         q.text('}')
 
-class table_feature_prop_experimenter(object):
+table_feature_prop.subtypes[15] = table_feature_prop_apply_setfield_miss
+
+class table_feature_prop_experimenter(table_feature_prop):
     type = 65535
 
     def __init__(self, experimenter=None, subtype=None, experimenter_data=None):
@@ -2255,15 +2186,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = table_feature_prop_experimenter()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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())
@@ -2276,13 +2205,6 @@
         if self.experimenter_data != other.experimenter_data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_feature_prop_experimenter {")
         with q.group():
@@ -2299,7 +2221,9 @@
             q.breakable()
         q.text('}')
 
-class table_feature_prop_instructions(object):
+table_feature_prop.subtypes[65535] = table_feature_prop_experimenter
+
+class table_feature_prop_instructions(table_feature_prop):
     type = 0
 
     def __init__(self, instruction_ids=None):
@@ -2313,22 +2237,20 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for length at index 1
-        packed.append(util.pack_list(self.instruction_ids))
+        packed.append(loxi.generic_util.pack_list(self.instruction_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = table_feature_prop_instructions()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 0)
         _length = reader.read("!H")[0]
-        obj.instruction_ids = instruction.unpack_list(reader)
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
+        obj.instruction_ids = loxi.generic_util.unpack_list(reader, instruction.instruction.unpack)
         return obj
 
     def __eq__(self, other):
@@ -2336,13 +2258,6 @@
         if self.instruction_ids != other.instruction_ids: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_feature_prop_instructions {")
         with q.group():
@@ -2353,7 +2268,9 @@
             q.breakable()
         q.text('}')
 
-class table_feature_prop_instructions_miss(object):
+table_feature_prop.subtypes[0] = table_feature_prop_instructions
+
+class table_feature_prop_instructions_miss(table_feature_prop):
     type = 1
 
     def __init__(self, instruction_ids=None):
@@ -2367,22 +2284,20 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for length at index 1
-        packed.append(util.pack_list(self.instruction_ids))
+        packed.append(loxi.generic_util.pack_list(self.instruction_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = table_feature_prop_instructions_miss()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
-        obj.instruction_ids = instruction.unpack_list(reader)
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
+        obj.instruction_ids = loxi.generic_util.unpack_list(reader, instruction.instruction.unpack)
         return obj
 
     def __eq__(self, other):
@@ -2390,13 +2305,6 @@
         if self.instruction_ids != other.instruction_ids: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_feature_prop_instructions_miss {")
         with q.group():
@@ -2407,7 +2315,9 @@
             q.breakable()
         q.text('}')
 
-class table_feature_prop_match(object):
+table_feature_prop.subtypes[1] = table_feature_prop_instructions_miss
+
+class table_feature_prop_match(table_feature_prop):
     type = 8
 
     def __init__(self, oxm_ids=None):
@@ -2421,21 +2331,19 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for length at index 1
-        packed.append(util.pack_list(self.oxm_ids))
+        packed.append(loxi.generic_util.pack_list(self.oxm_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = table_feature_prop_match()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 8)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.oxm_ids = loxi.generic_util.unpack_list(reader, common.uint32.unpack)
         return obj
 
@@ -2444,13 +2352,6 @@
         if self.oxm_ids != other.oxm_ids: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_feature_prop_match {")
         with q.group():
@@ -2461,7 +2362,9 @@
             q.breakable()
         q.text('}')
 
-class table_feature_prop_next_tables(object):
+table_feature_prop.subtypes[8] = table_feature_prop_match
+
+class table_feature_prop_next_tables(table_feature_prop):
     type = 2
 
     def __init__(self, next_table_ids=None):
@@ -2475,21 +2378,19 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for length at index 1
-        packed.append(util.pack_list(self.next_table_ids))
+        packed.append(loxi.generic_util.pack_list(self.next_table_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = table_feature_prop_next_tables()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 2)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.next_table_ids = loxi.generic_util.unpack_list(reader, common.uint8.unpack)
         return obj
 
@@ -2498,13 +2399,6 @@
         if self.next_table_ids != other.next_table_ids: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_feature_prop_next_tables {")
         with q.group():
@@ -2515,7 +2409,9 @@
             q.breakable()
         q.text('}')
 
-class table_feature_prop_next_tables_miss(object):
+table_feature_prop.subtypes[2] = table_feature_prop_next_tables
+
+class table_feature_prop_next_tables_miss(table_feature_prop):
     type = 3
 
     def __init__(self, next_table_ids=None):
@@ -2529,21 +2425,19 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for length at index 1
-        packed.append(util.pack_list(self.next_table_ids))
+        packed.append(loxi.generic_util.pack_list(self.next_table_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = table_feature_prop_next_tables_miss()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 3)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.next_table_ids = loxi.generic_util.unpack_list(reader, common.uint8.unpack)
         return obj
 
@@ -2552,13 +2446,6 @@
         if self.next_table_ids != other.next_table_ids: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_feature_prop_next_tables_miss {")
         with q.group():
@@ -2569,7 +2456,9 @@
             q.breakable()
         q.text('}')
 
-class table_feature_prop_wildcards(object):
+table_feature_prop.subtypes[3] = table_feature_prop_next_tables_miss
+
+class table_feature_prop_wildcards(table_feature_prop):
     type = 10
 
     def __init__(self, oxm_ids=None):
@@ -2583,21 +2472,19 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for length at index 1
-        packed.append(util.pack_list(self.oxm_ids))
+        packed.append(loxi.generic_util.pack_list(self.oxm_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = table_feature_prop_wildcards()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 10)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.oxm_ids = loxi.generic_util.unpack_list(reader, common.uint32.unpack)
         return obj
 
@@ -2606,13 +2493,6 @@
         if self.oxm_ids != other.oxm_ids: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_feature_prop_wildcards {")
         with q.group():
@@ -2623,7 +2503,9 @@
             q.breakable()
         q.text('}')
 
-class table_feature_prop_write_actions(object):
+table_feature_prop.subtypes[10] = table_feature_prop_wildcards
+
+class table_feature_prop_write_actions(table_feature_prop):
     type = 4
 
     def __init__(self, action_ids=None):
@@ -2637,22 +2519,20 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for length at index 1
-        packed.append(util.pack_list(self.action_ids))
+        packed.append(loxi.generic_util.pack_list(self.action_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = table_feature_prop_write_actions()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 4)
         _length = reader.read("!H")[0]
-        obj.action_ids = loxi.unimplemented('unpack list(of_action_id_t)')
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
+        obj.action_ids = loxi.generic_util.unpack_list(reader, action_id.action_id.unpack)
         return obj
 
     def __eq__(self, other):
@@ -2660,13 +2540,6 @@
         if self.action_ids != other.action_ids: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_feature_prop_write_actions {")
         with q.group():
@@ -2677,7 +2550,9 @@
             q.breakable()
         q.text('}')
 
-class table_feature_prop_write_actions_miss(object):
+table_feature_prop.subtypes[4] = table_feature_prop_write_actions
+
+class table_feature_prop_write_actions_miss(table_feature_prop):
     type = 5
 
     def __init__(self, action_ids=None):
@@ -2691,22 +2566,20 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for length at index 1
-        packed.append(util.pack_list(self.action_ids))
+        packed.append(loxi.generic_util.pack_list(self.action_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = table_feature_prop_write_actions_miss()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 5)
         _length = reader.read("!H")[0]
-        obj.action_ids = loxi.unimplemented('unpack list(of_action_id_t)')
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
+        obj.action_ids = loxi.generic_util.unpack_list(reader, action_id.action_id.unpack)
         return obj
 
     def __eq__(self, other):
@@ -2714,13 +2587,6 @@
         if self.action_ids != other.action_ids: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_feature_prop_write_actions_miss {")
         with q.group():
@@ -2731,7 +2597,9 @@
             q.breakable()
         q.text('}')
 
-class table_feature_prop_write_setfield(object):
+table_feature_prop.subtypes[5] = table_feature_prop_write_actions_miss
+
+class table_feature_prop_write_setfield(table_feature_prop):
     type = 12
 
     def __init__(self, oxm_ids=None):
@@ -2745,21 +2613,19 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for length at index 1
-        packed.append(util.pack_list(self.oxm_ids))
+        packed.append(loxi.generic_util.pack_list(self.oxm_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = table_feature_prop_write_setfield()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 12)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.oxm_ids = loxi.generic_util.unpack_list(reader, common.uint32.unpack)
         return obj
 
@@ -2768,13 +2634,6 @@
         if self.oxm_ids != other.oxm_ids: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_feature_prop_write_setfield {")
         with q.group():
@@ -2785,7 +2644,9 @@
             q.breakable()
         q.text('}')
 
-class table_feature_prop_write_setfield_miss(object):
+table_feature_prop.subtypes[12] = table_feature_prop_write_setfield
+
+class table_feature_prop_write_setfield_miss(table_feature_prop):
     type = 13
 
     def __init__(self, oxm_ids=None):
@@ -2799,21 +2660,19 @@
         packed = []
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for length at index 1
-        packed.append(util.pack_list(self.oxm_ids))
+        packed.append(loxi.generic_util.pack_list(self.oxm_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = table_feature_prop_write_setfield_miss()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 13)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.oxm_ids = loxi.generic_util.unpack_list(reader, common.uint32.unpack)
         return obj
 
@@ -2822,13 +2681,6 @@
         if self.oxm_ids != other.oxm_ids: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_feature_prop_write_setfield_miss {")
         with q.group():
@@ -2839,7 +2691,9 @@
             q.breakable()
         q.text('}')
 
-class table_features(object):
+table_feature_prop.subtypes[13] = table_feature_prop_write_setfield_miss
+
+class table_features(loxi.OFObject):
 
     def __init__(self, table_id=None, name=None, metadata_match=None, metadata_write=None, config=None, max_entries=None, properties=None):
         if table_id != None:
@@ -2882,19 +2736,17 @@
         packed.append(struct.pack("!Q", self.metadata_write))
         packed.append(struct.pack("!L", self.config))
         packed.append(struct.pack("!L", self.max_entries))
-        packed.append(util.pack_list(self.properties))
+        packed.append(loxi.generic_util.pack_list(self.properties))
         length = sum([len(x) for x in packed])
         packed[0] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = table_features()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (0 + 2))
         obj.table_id = reader.read("!B")[0]
         reader.skip(5)
         obj.name = reader.read("!32s")[0].rstrip("\x00")
@@ -2902,7 +2754,7 @@
         obj.metadata_write = reader.read("!Q")[0]
         obj.config = reader.read("!L")[0]
         obj.max_entries = reader.read("!L")[0]
-        obj.properties = loxi.unimplemented('unpack list(of_table_feature_prop_t)')
+        obj.properties = loxi.generic_util.unpack_list(reader, common.table_feature_prop.unpack)
         return obj
 
     def __eq__(self, other):
@@ -2916,13 +2768,6 @@
         if self.properties != other.properties: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_features {")
         with q.group():
@@ -2951,7 +2796,8 @@
             q.breakable()
         q.text('}')
 
-class table_stats_entry(object):
+
+class table_stats_entry(loxi.OFObject):
 
     def __init__(self, table_id=None, active_count=None, lookup_count=None, matched_count=None):
         if table_id != None:
@@ -2982,12 +2828,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = table_stats_entry()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         obj.table_id = reader.read("!B")[0]
         reader.skip(3)
         obj.active_count = reader.read("!L")[0]
@@ -3003,13 +2845,6 @@
         if self.matched_count != other.matched_count: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_stats_entry {")
         with q.group():
@@ -3029,7 +2864,8 @@
             q.breakable()
         q.text('}')
 
-class uint32(object):
+
+class uint32(loxi.OFObject):
 
     def __init__(self, value=None):
         if value != None:
@@ -3044,12 +2880,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = uint32()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         obj.value = reader.read("!L")[0]
         return obj
 
@@ -3058,13 +2890,6 @@
         if self.value != other.value: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("uint32 {")
         with q.group():
@@ -3075,7 +2900,44 @@
             q.breakable()
         q.text('}')
 
-class uint8(object):
+
+class uint64(loxi.OFObject):
+
+    def __init__(self, value=None):
+        if value != None:
+            self.value = value
+        else:
+            self.value = 0
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!Q", self.value))
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = uint64()
+        obj.value = reader.read("!Q")[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("uint64 {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("value = ");
+                q.text("%#x" % self.value)
+            q.breakable()
+        q.text('}')
+
+
+class uint8(loxi.OFObject):
 
     def __init__(self, value=None):
         if value != None:
@@ -3090,12 +2952,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = uint8()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         obj.value = reader.read("!B")[0]
         return obj
 
@@ -3104,13 +2962,6 @@
         if self.value != other.value: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("uint8 {")
         with q.group():
@@ -3122,4 +2973,5 @@
         q.text('}')
 
 
+
 match = match_v3