Merge into master from pull request #92:
update pyloxi to 026ff024585f1588a7f11fa4c1a9a48d44dc098d (https://github.com/floodlight/oftest/pull/92)
diff --git a/src/python/loxi/__init__.py b/src/python/loxi/__init__.py
index e13e01d..f0a7c25 100644
--- a/src/python/loxi/__init__.py
+++ b/src/python/loxi/__init__.py
@@ -45,3 +45,17 @@
 
 def unimplemented(msg):
     raise Unimplemented(msg)
+
+class OFObject(object):
+    """
+    Superclass of all OpenFlow classes
+    """
+    def __init__(self, *args):
+        raise NotImplementedError("cannot instantiate abstract class")
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def show(self):
+        import loxi.pp
+        return loxi.pp.pp(self)
diff --git a/src/python/loxi/generic_util.py b/src/python/loxi/generic_util.py
index f965e64..aa218a2 100644
--- a/src/python/loxi/generic_util.py
+++ b/src/python/loxi/generic_util.py
@@ -12,6 +12,9 @@
 import loxi
 import struct
 
+def pack_list(values):
+    return "".join([x.pack() for x in values])
+
 def unpack_list(reader, deserializer):
     """
     The deserializer function should take an OFReader and return the new object.
@@ -21,25 +24,6 @@
         entries.append(deserializer(reader))
     return entries
 
-def unpack_list_lv16(reader, deserializer):
-    """
-    The deserializer function should take an OFReader and return the new object.
-    """
-    def wrapper(reader):
-        length, = reader.peek('!H')
-        return deserializer(reader.slice(length))
-    return unpack_list(reader, wrapper)
-
-def unpack_list_tlv16(reader, deserializer):
-    """
-    The deserializer function should take an OFReader and an integer type
-    and return the new object.
-    """
-    def wrapper(reader):
-        typ, length, = reader.peek('!HH')
-        return deserializer(reader.slice(length), typ)
-    return unpack_list(reader, wrapper)
-
 def pad_to(alignment, length):
     """
     Return a string of zero bytes that will pad a string of length 'length' to
@@ -56,50 +40,60 @@
     known field lengths. This class supports efficiently reading
     fields sequentially and is intended to be used recursively by the
     parsers of child objects which will implicitly update the offset.
+
+    buf: buffer object
+    start: initial position in the buffer
+    length: number of bytes after start
+    offset: distance from start
     """
-    def __init__(self, buf):
+    def __init__(self, buf, start=0, length=None):
         self.buf = buf
+        self.start = start
+        if length is None:
+            self.length = len(buf) - start
+        else:
+            self.length = length
         self.offset = 0
 
     def read(self, fmt):
         st = struct.Struct(fmt)
-        if self.offset + st.size > len(self.buf):
+        if self.offset + st.size > self.length:
             raise loxi.ProtocolError("Buffer too short")
-        result = st.unpack_from(self.buf, self.offset)
+        result = st.unpack_from(self.buf, self.start+self.offset)
         self.offset += st.size
         return result
 
     def read_all(self):
-        buf = buffer(self.buf, self.offset)
-        self.offset += len(buf)
-        return str(buf)
+        s = self.buf[(self.start+self.offset):(self.start+self.length)]
+        assert(len(s) == self.length - self.offset)
+        self.offset = self.length
+        return s
 
-    def peek(self, fmt):
+    def peek(self, fmt, offset=0):
         st = struct.Struct(fmt)
-        if self.offset + st.size > len(self.buf):
+        if self.offset + offset + st.size > self.length:
             raise loxi.ProtocolError("Buffer too short")
-        result = st.unpack_from(self.buf, self.offset)
+        result = st.unpack_from(self.buf, self.start + self.offset + offset)
         return result
 
     def skip(self, length):
-        if self.offset + length > len(self.buf):
+        if self.offset + length > self.length:
             raise loxi.ProtocolError("Buffer too short")
         self.offset += length
 
     def skip_align(self):
-        new_offset = (self.offset + 7) / 8 * 8
-        if new_offset > len(self.buf):
+        new_offset = ((self.start + self.offset + 7) / 8 * 8) - self.start
+        if new_offset > self.length:
             raise loxi.ProtocolError("Buffer too short")
         self.offset = new_offset
 
     def is_empty(self):
-        return self.offset == len(self.buf)
+        return self.offset == self.length
 
-    # Used when parsing variable length objects which have external length
-    # fields (e.g. the actions list in an OF 1.0 packet-out message).
+    # Used when parsing objects that have their own length fields
     def slice(self, length):
-        if self.offset + length > len(self.buf):
+        if self.offset + length > self.length:
             raise loxi.ProtocolError("Buffer too short")
-        buf = OFReader(buffer(self.buf, self.offset, length))
+        reader = OFReader(self.buf, self.start + self.offset, length)
         self.offset += length
-        return buf
+        return reader
diff --git a/src/python/loxi/of10/action.py b/src/python/loxi/of10/action.py
index 6a3abfb..38b674c 100644
--- a/src/python/loxi/of10/action.py
+++ b/src/python/loxi/of10/action.py
@@ -3,27 +3,59 @@
 # 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 action.py
+# Automatically generated by LOXI from template module.py
 # Do not modify
 
 import struct
+import loxi
 import const
+import common
+import action
 import util
 import loxi.generic_util
-import loxi
 
-def unpack_list(reader):
-    def deserializer(reader, typ):
-        parser = parsers.get(typ)
-        if not parser: raise loxi.ProtocolError("unknown action type %d" % typ)
-        return parser(reader)
-    return loxi.generic_util.unpack_list_tlv16(reader, deserializer)
+class action(loxi.OFObject):
+    subtypes = {}
 
-class Action(object):
-    type = None # override in subclass
-    pass
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 0)
+        try:
+            subclass = action.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown action subtype %#x" % subtype)
+        return subclass.unpack(reader)
 
-class bsn_mirror(Action):
+
+class experimenter(action):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 4)
+        try:
+            subclass = experimenter.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter action subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+action.subtypes[65535] = experimenter
+
+class bsn(experimenter):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 8)
+        try:
+            subclass = bsn.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown bsn experimenter action subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter.subtypes[6035143] = bsn
+
+class bsn_mirror(bsn):
     type = 65535
     experimenter = 6035143
     subtype = 1
@@ -58,15 +90,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_mirror()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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]
@@ -84,13 +114,6 @@
         if self.copy_stage != other.copy_stage: 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_mirror {")
         with q.group():
@@ -107,7 +130,9 @@
             q.breakable()
         q.text('}')
 
-class bsn_set_tunnel_dst(Action):
+bsn.subtypes[1] = bsn_mirror
+
+class bsn_set_tunnel_dst(bsn):
     type = 65535
     experimenter = 6035143
     subtype = 2
@@ -131,15 +156,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_set_tunnel_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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]
@@ -152,13 +175,6 @@
         if self.dst != other.dst: 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_set_tunnel_dst {")
         with q.group():
@@ -169,7 +185,9 @@
             q.breakable()
         q.text('}')
 
-class enqueue(Action):
+bsn.subtypes[2] = bsn_set_tunnel_dst
+
+class enqueue(action):
     type = 11
 
     def __init__(self, port=None, queue_id=None):
@@ -195,15 +213,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = enqueue()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 11)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.port = util.unpack_port_no(reader)
         reader.skip(6)
         obj.queue_id = reader.read("!L")[0]
@@ -215,13 +231,6 @@
         if self.queue_id != other.queue_id: 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("enqueue {")
         with q.group():
@@ -235,7 +244,23 @@
             q.breakable()
         q.text('}')
 
-class nicira_dec_ttl(Action):
+action.subtypes[11] = enqueue
+
+class nicira(experimenter):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 8)
+        try:
+            subclass = nicira.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown nicira experimenter action subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter.subtypes[8992] = nicira
+
+class nicira_dec_ttl(nicira):
     type = 65535
     experimenter = 8992
     subtype = 18
@@ -256,15 +281,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = nicira_dec_ttl()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 8992)
         _subtype = reader.read("!H")[0]
@@ -277,13 +300,6 @@
         if type(self) != type(other): 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("nicira_dec_ttl {")
         with q.group():
@@ -292,7 +308,9 @@
             q.breakable()
         q.text('}')
 
-class output(Action):
+nicira.subtypes[18] = nicira_dec_ttl
+
+class output(action):
     type = 0
 
     def __init__(self, port=None, max_len=None):
@@ -317,15 +335,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = output()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 0)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.port = util.unpack_port_no(reader)
         obj.max_len = reader.read("!H")[0]
         return obj
@@ -336,13 +352,6 @@
         if self.max_len != other.max_len: 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("output {")
         with q.group():
@@ -356,7 +365,9 @@
             q.breakable()
         q.text('}')
 
-class set_dl_dst(Action):
+action.subtypes[0] = output
+
+class set_dl_dst(action):
     type = 5
 
     def __init__(self, dl_addr=None):
@@ -377,15 +388,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_dl_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 5)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.dl_addr = list(reader.read('!6B'))
         reader.skip(6)
         return obj
@@ -395,13 +404,6 @@
         if self.dl_addr != other.dl_addr: 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("set_dl_dst {")
         with q.group():
@@ -412,7 +414,9 @@
             q.breakable()
         q.text('}')
 
-class set_dl_src(Action):
+action.subtypes[5] = set_dl_dst
+
+class set_dl_src(action):
     type = 4
 
     def __init__(self, dl_addr=None):
@@ -433,15 +437,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_dl_src()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 4)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.dl_addr = list(reader.read('!6B'))
         reader.skip(6)
         return obj
@@ -451,13 +453,6 @@
         if self.dl_addr != other.dl_addr: 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("set_dl_src {")
         with q.group():
@@ -468,7 +463,9 @@
             q.breakable()
         q.text('}')
 
-class set_nw_dst(Action):
+action.subtypes[4] = set_dl_src
+
+class set_nw_dst(action):
     type = 7
 
     def __init__(self, nw_addr=None):
@@ -488,15 +485,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_nw_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 7)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.nw_addr = reader.read("!L")[0]
         return obj
 
@@ -505,13 +500,6 @@
         if self.nw_addr != other.nw_addr: 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("set_nw_dst {")
         with q.group():
@@ -522,7 +510,9 @@
             q.breakable()
         q.text('}')
 
-class set_nw_src(Action):
+action.subtypes[7] = set_nw_dst
+
+class set_nw_src(action):
     type = 6
 
     def __init__(self, nw_addr=None):
@@ -542,15 +532,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_nw_src()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 6)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.nw_addr = reader.read("!L")[0]
         return obj
 
@@ -559,13 +547,6 @@
         if self.nw_addr != other.nw_addr: 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("set_nw_src {")
         with q.group():
@@ -576,7 +557,9 @@
             q.breakable()
         q.text('}')
 
-class set_nw_tos(Action):
+action.subtypes[6] = set_nw_src
+
+class set_nw_tos(action):
     type = 8
 
     def __init__(self, nw_tos=None):
@@ -597,15 +580,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_nw_tos()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 8)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.nw_tos = reader.read("!B")[0]
         reader.skip(3)
         return obj
@@ -615,13 +596,6 @@
         if self.nw_tos != other.nw_tos: 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("set_nw_tos {")
         with q.group():
@@ -632,7 +606,9 @@
             q.breakable()
         q.text('}')
 
-class set_tp_dst(Action):
+action.subtypes[8] = set_nw_tos
+
+class set_tp_dst(action):
     type = 10
 
     def __init__(self, tp_port=None):
@@ -653,15 +629,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_tp_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 10)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.tp_port = reader.read("!H")[0]
         reader.skip(2)
         return obj
@@ -671,13 +645,6 @@
         if self.tp_port != other.tp_port: 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("set_tp_dst {")
         with q.group():
@@ -688,7 +655,9 @@
             q.breakable()
         q.text('}')
 
-class set_tp_src(Action):
+action.subtypes[10] = set_tp_dst
+
+class set_tp_src(action):
     type = 9
 
     def __init__(self, tp_port=None):
@@ -709,15 +678,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_tp_src()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 9)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.tp_port = reader.read("!H")[0]
         reader.skip(2)
         return obj
@@ -727,13 +694,6 @@
         if self.tp_port != other.tp_port: 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("set_tp_src {")
         with q.group():
@@ -744,7 +704,9 @@
             q.breakable()
         q.text('}')
 
-class set_vlan_pcp(Action):
+action.subtypes[9] = set_tp_src
+
+class set_vlan_pcp(action):
     type = 2
 
     def __init__(self, vlan_pcp=None):
@@ -765,15 +727,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_vlan_pcp()
-        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))
         obj.vlan_pcp = reader.read("!B")[0]
         reader.skip(3)
         return obj
@@ -783,13 +743,6 @@
         if self.vlan_pcp != other.vlan_pcp: 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("set_vlan_pcp {")
         with q.group():
@@ -800,7 +753,9 @@
             q.breakable()
         q.text('}')
 
-class set_vlan_vid(Action):
+action.subtypes[2] = set_vlan_pcp
+
+class set_vlan_vid(action):
     type = 1
 
     def __init__(self, vlan_vid=None):
@@ -821,15 +776,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_vlan_vid()
-        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))
         obj.vlan_vid = reader.read("!H")[0]
         reader.skip(2)
         return obj
@@ -839,13 +792,6 @@
         if self.vlan_vid != other.vlan_vid: 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("set_vlan_vid {")
         with q.group():
@@ -856,7 +802,9 @@
             q.breakable()
         q.text('}')
 
-class strip_vlan(Action):
+action.subtypes[1] = set_vlan_vid
+
+class strip_vlan(action):
     type = 3
 
     def __init__(self):
@@ -872,15 +820,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = strip_vlan()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 3)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         return obj
 
@@ -888,13 +834,6 @@
         if type(self) != type(other): 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("strip_vlan {")
         with q.group():
@@ -903,43 +842,6 @@
             q.breakable()
         q.text('}')
 
+action.subtypes[3] = strip_vlan
 
-def parse_experimenter(reader):
-    experimenter, = reader.peek("!4xL")
-    if experimenter == 0x005c16c7: # Big Switch Networks
-        subtype, = reader.peek("!8xL")
-    elif experimenter == 0x00002320: # Nicira
-        subtype, = reader.peek("!8xH")
-    else:
-        raise loxi.ProtocolError("unexpected experimenter id %#x" % experimenter)
 
-    if subtype in experimenter_parsers[experimenter]:
-        return experimenter_parsers[experimenter][subtype](reader)
-    else:
-        raise loxi.ProtocolError("unexpected BSN experimenter subtype %#x" % subtype)
-
-parsers = {
-    const.OFPAT_OUTPUT : output.unpack,
-    const.OFPAT_SET_VLAN_VID : set_vlan_vid.unpack,
-    const.OFPAT_SET_VLAN_PCP : set_vlan_pcp.unpack,
-    const.OFPAT_STRIP_VLAN : strip_vlan.unpack,
-    const.OFPAT_SET_DL_SRC : set_dl_src.unpack,
-    const.OFPAT_SET_DL_DST : set_dl_dst.unpack,
-    const.OFPAT_SET_NW_SRC : set_nw_src.unpack,
-    const.OFPAT_SET_NW_DST : set_nw_dst.unpack,
-    const.OFPAT_SET_NW_TOS : set_nw_tos.unpack,
-    const.OFPAT_SET_TP_SRC : set_tp_src.unpack,
-    const.OFPAT_SET_TP_DST : set_tp_dst.unpack,
-    const.OFPAT_ENQUEUE : enqueue.unpack,
-    const.OFPAT_EXPERIMENTER : parse_experimenter,
-}
-
-experimenter_parsers = {
-    8992 : {
-        18: nicira_dec_ttl.unpack,
-    },
-    6035143 : {
-        1: bsn_mirror.unpack,
-        2: bsn_set_tunnel_dst.unpack,
-    },
-}
diff --git a/src/python/loxi/of10/common.py b/src/python/loxi/of10/common.py
index 481b686..ec788ed 100644
--- a/src/python/loxi/of10/common.py
+++ b/src/python/loxi/of10/common.py
@@ -2,61 +2,19 @@
 # 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 loxi
 import const
+import common
+import action
 import util
 import loxi.generic_util
 
-
-# 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 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:
@@ -87,12 +45,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")
@@ -108,13 +62,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():
@@ -134,7 +81,21 @@
             q.breakable()
         q.text('}')
 
-class bsn_vport_q_in_q(object):
+
+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):
@@ -179,15 +140,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]
@@ -206,13 +165,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():
@@ -238,7 +190,9 @@
             q.breakable()
         q.text('}')
 
-class flow_stats_entry(object):
+bsn_vport.subtypes[0] = bsn_vport_q_in_q
+
+class flow_stats_entry(loxi.OFObject):
 
     def __init__(self, table_id=None, match=None, duration_sec=None, duration_nsec=None, priority=None, idle_timeout=None, hard_timeout=None, cookie=None, packet_count=None, byte_count=None, actions=None):
         if table_id != None:
@@ -302,19 +256,17 @@
         packed.append(struct.pack("!Q", self.cookie))
         packed.append(struct.pack("!Q", self.packet_count))
         packed.append(struct.pack("!Q", self.byte_count))
-        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 = 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.match = common.match.unpack(reader)
@@ -327,7 +279,7 @@
         obj.cookie = reader.read("!Q")[0]
         obj.packet_count = reader.read("!Q")[0]
         obj.byte_count = reader.read("!Q")[0]
-        obj.actions = action.unpack_list(reader)
+        obj.actions = loxi.generic_util.unpack_list(reader, action.action.unpack)
         return obj
 
     def __eq__(self, other):
@@ -345,13 +297,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("flow_stats_entry {")
         with q.group():
@@ -392,7 +337,8 @@
             q.breakable()
         q.text('}')
 
-class match_v1(object):
+
+class match_v1(loxi.OFObject):
 
     def __init__(self, wildcards=None, in_port=None, eth_src=None, eth_dst=None, vlan_vid=None, vlan_pcp=None, eth_type=None, ip_dscp=None, ip_proto=None, ipv4_src=None, ipv4_dst=None, tcp_src=None, tcp_dst=None):
         if wildcards != None:
@@ -469,12 +415,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = match_v1()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         obj.wildcards = util.unpack_wc_bmap(reader)
         obj.in_port = util.unpack_port_no(reader)
         obj.eth_src = list(reader.read('!6B'))
@@ -509,13 +451,6 @@
         if self.tcp_dst != other.tcp_dst: 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_v1 {")
         with q.group():
@@ -562,7 +497,8 @@
             q.breakable()
         q.text('}')
 
-class packet_queue(object):
+
+class packet_queue(loxi.OFObject):
 
     def __init__(self, queue_id=None, properties=None):
         if queue_id != None:
@@ -580,22 +516,20 @@
         packed.append(struct.pack("!L", self.queue_id))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
         packed.append('\x00' * 2)
-        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[1] = 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]
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (4 + 2))
         reader.skip(2)
-        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):
@@ -604,13 +538,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():
@@ -624,7 +551,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):
         if port_no != None:
@@ -679,12 +607,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)
         obj.hw_addr = list(reader.read('!6B'))
         obj.name = reader.read("!16s")[0].rstrip("\x00")
@@ -709,13 +633,6 @@
         if self.peer != other.peer: 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():
@@ -750,7 +667,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):
         if port_no != None:
@@ -826,12 +744,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(6)
         obj.rx_packets = reader.read("!Q")[0]
@@ -865,13 +779,6 @@
         if self.collisions != other.collisions: 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():
@@ -918,7 +825,21 @@
             q.breakable()
         q.text('}')
 
-class queue_prop_min_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_min_rate(queue_prop):
     type = 1
 
     def __init__(self, rate=None):
@@ -940,15 +861,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)
@@ -959,13 +878,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():
@@ -976,7 +888,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):
         if port_no != None:
@@ -1012,12 +926,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)
         reader.skip(2)
         obj.queue_id = reader.read("!L")[0]
@@ -1035,13 +945,6 @@
         if self.tx_errors != other.tx_errors: 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():
@@ -1064,7 +967,8 @@
             q.breakable()
         q.text('}')
 
-class table_stats_entry(object):
+
+class table_stats_entry(loxi.OFObject):
 
     def __init__(self, table_id=None, name=None, wildcards=None, max_entries=None, active_count=None, lookup_count=None, matched_count=None):
         if table_id != None:
@@ -1110,12 +1014,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.name = reader.read("!32s")[0].rstrip("\x00")
@@ -1137,13 +1037,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():
@@ -1173,4 +1066,5 @@
         q.text('}')
 
 
+
 match = match_v1
diff --git a/src/python/loxi/of10/message.py b/src/python/loxi/of10/message.py
index 9b12a07..bbf774a 100644
--- a/src/python/loxi/of10/message.py
+++ b/src/python/loxi/of10/message.py
@@ -3,29 +3,54 @@
 # 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 message.py
+# Automatically generated by LOXI from template module.py
 # Do not modify
 
 import struct
 import loxi
 import const
 import common
-import action # for unpack_list
+import action
 import util
 import loxi.generic_util
 
-class Message(object):
-    version = const.OFP_VERSION
-    type = None # override in subclass
-    xid = None
+class message(loxi.OFObject):
+    subtypes = {}
 
-class aggregate_stats_reply(Message):
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('B', 1)
+        try:
+            subclass = message.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+
+class stats_reply(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 8)
+        try:
+            subclass = stats_reply.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown stats_reply message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[17] = stats_reply
+
+class aggregate_stats_reply(stats_reply):
     version = 1
     type = 17
     stats_type = 2
 
     def __init__(self, xid=None, flags=None, packet_count=None, byte_count=None, flow_count=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -42,6 +67,7 @@
             self.flow_count = flow_count
         else:
             self.flow_count = 0
+        return
 
     def pack(self):
         packed = []
@@ -60,18 +86,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = aggregate_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 17)
         _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 == 2)
@@ -84,8 +107,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.packet_count != other.packet_count: return False
@@ -93,16 +114,6 @@
         if self.flow_count != other.flow_count: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("aggregate_stats_reply {")
         with q.group():
@@ -128,13 +139,32 @@
             q.breakable()
         q.text('}')
 
-class aggregate_stats_request(Message):
+stats_reply.subtypes[2] = aggregate_stats_reply
+
+class stats_request(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 8)
+        try:
+            subclass = stats_request.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown stats_request message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[16] = stats_request
+
+class aggregate_stats_request(stats_request):
     version = 1
     type = 16
     stats_type = 2
 
     def __init__(self, xid=None, flags=None, match=None, table_id=None, out_port=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -151,6 +181,7 @@
             self.out_port = out_port
         else:
             self.out_port = 0
+        return
 
     def pack(self):
         packed = []
@@ -169,18 +200,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = aggregate_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 16)
         _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 == 2)
@@ -193,8 +221,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.match != other.match: return False
@@ -202,16 +228,6 @@
         if self.out_port != other.out_port: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("aggregate_stats_request {")
         with q.group():
@@ -237,13 +253,32 @@
             q.breakable()
         q.text('}')
 
-class bad_action_error_msg(Message):
+stats_request.subtypes[2] = aggregate_stats_request
+
+class error_msg(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 8)
+        try:
+            subclass = error_msg.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown error_msg message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[1] = error_msg
+
+class bad_action_error_msg(error_msg):
     version = 1
     type = 1
     err_type = 2
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -252,6 +287,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -267,18 +303,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bad_action_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 2)
@@ -288,23 +321,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bad_action_error_msg {")
         with q.group():
@@ -324,13 +345,18 @@
             q.breakable()
         q.text('}')
 
-class bad_request_error_msg(Message):
+error_msg.subtypes[2] = bad_action_error_msg
+
+class bad_request_error_msg(error_msg):
     version = 1
     type = 1
     err_type = 1
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -339,6 +365,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -354,18 +381,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bad_request_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 1)
@@ -375,23 +399,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bad_request_error_msg {")
         with q.group():
@@ -411,12 +423,18 @@
             q.breakable()
         q.text('}')
 
-class barrier_reply(Message):
+error_msg.subtypes[1] = bad_request_error_msg
+
+class barrier_reply(message):
     version = 1
     type = 19
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -429,38 +447,23 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = barrier_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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]
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("barrier_reply {")
         with q.group():
@@ -474,12 +477,18 @@
             q.breakable()
         q.text('}')
 
-class barrier_request(Message):
+message.subtypes[19] = barrier_reply
+
+class barrier_request(message):
     version = 1
     type = 18
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -492,38 +501,23 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = barrier_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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]
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("barrier_request {")
         with q.group():
@@ -537,18 +531,52 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_clear_data_reply(Message):
+message.subtypes[18] = barrier_request
+
+class experimenter(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 8)
+        try:
+            subclass = experimenter.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[4] = experimenter
+
+class bsn_header(experimenter):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 12)
+        try:
+            subclass = bsn_header.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown bsn_header experimenter message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter.subtypes[6035143] = bsn_header
+
+class bsn_bw_clear_data_reply(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 22
 
     def __init__(self, xid=None, status=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
             self.status = 0
+        return
 
     def pack(self):
         packed = []
@@ -564,18 +592,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_clear_data_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -586,22 +611,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_clear_data_reply {")
         with q.group():
@@ -618,14 +631,20 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_clear_data_request(Message):
+bsn_header.subtypes[22] = bsn_bw_clear_data_reply
+
+class bsn_bw_clear_data_request(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 21
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -640,18 +659,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_clear_data_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -661,21 +677,9 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_clear_data_request {")
         with q.group():
@@ -689,18 +693,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_enable_get_reply(Message):
+bsn_header.subtypes[21] = bsn_bw_clear_data_request
+
+class bsn_bw_enable_get_reply(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 20
 
     def __init__(self, xid=None, enabled=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if enabled != None:
             self.enabled = enabled
         else:
             self.enabled = 0
+        return
 
     def pack(self):
         packed = []
@@ -716,18 +726,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_enable_get_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -738,22 +745,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.enabled != other.enabled: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_enable_get_reply {")
         with q.group():
@@ -770,14 +765,20 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_enable_get_request(Message):
+bsn_header.subtypes[20] = bsn_bw_enable_get_reply
+
+class bsn_bw_enable_get_request(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 19
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -792,18 +793,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_enable_get_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -813,21 +811,9 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_enable_get_request {")
         with q.group():
@@ -841,14 +827,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_enable_set_reply(Message):
+bsn_header.subtypes[19] = bsn_bw_enable_get_request
+
+class bsn_bw_enable_set_reply(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 23
 
     def __init__(self, xid=None, enable=None, status=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if enable != None:
             self.enable = enable
         else:
@@ -857,6 +848,7 @@
             self.status = status
         else:
             self.status = 0
+        return
 
     def pack(self):
         packed = []
@@ -873,18 +865,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_enable_set_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -896,23 +885,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.enable != other.enable: return False
         if self.status != other.status: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_enable_set_reply {")
         with q.group():
@@ -932,18 +909,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_enable_set_request(Message):
+bsn_header.subtypes[23] = bsn_bw_enable_set_reply
+
+class bsn_bw_enable_set_request(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 18
 
     def __init__(self, xid=None, enable=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if enable != None:
             self.enable = enable
         else:
             self.enable = 0
+        return
 
     def pack(self):
         packed = []
@@ -959,18 +942,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_enable_set_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -981,22 +961,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.enable != other.enable: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_enable_set_request {")
         with q.group():
@@ -1013,18 +981,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_get_interfaces_reply(Message):
+bsn_header.subtypes[18] = bsn_bw_enable_set_request
+
+class bsn_get_interfaces_reply(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 10
 
     def __init__(self, xid=None, interfaces=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if interfaces != None:
             self.interfaces = interfaces
         else:
             self.interfaces = []
+        return
 
     def pack(self):
         packed = []
@@ -1034,24 +1008,21 @@
         packed.append(struct.pack("!L", self.xid))
         packed.append(struct.pack("!L", self.experimenter))
         packed.append(struct.pack("!L", self.subtype))
-        packed.append(util.pack_list(self.interfaces))
+        packed.append(loxi.generic_util.pack_list(self.interfaces))
         length = sum([len(x) for x in packed])
         packed[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_get_interfaces_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -1062,22 +1033,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.interfaces != other.interfaces: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_get_interfaces_reply {")
         with q.group():
@@ -1094,14 +1053,20 @@
             q.breakable()
         q.text('}')
 
-class bsn_get_interfaces_request(Message):
+bsn_header.subtypes[10] = bsn_get_interfaces_reply
+
+class bsn_get_interfaces_request(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 9
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -1116,18 +1081,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_get_interfaces_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -1137,21 +1099,9 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_get_interfaces_request {")
         with q.group():
@@ -1165,14 +1115,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_get_ip_mask_reply(Message):
+bsn_header.subtypes[9] = bsn_get_interfaces_request
+
+class bsn_get_ip_mask_reply(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 2
 
     def __init__(self, xid=None, index=None, mask=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if index != None:
             self.index = index
         else:
@@ -1181,6 +1136,7 @@
             self.mask = mask
         else:
             self.mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -1198,18 +1154,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_get_ip_mask_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -1222,23 +1175,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.index != other.index: return False
         if self.mask != other.mask: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_get_ip_mask_reply {")
         with q.group():
@@ -1258,18 +1199,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_get_ip_mask_request(Message):
+bsn_header.subtypes[2] = bsn_get_ip_mask_reply
+
+class bsn_get_ip_mask_request(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 1
 
     def __init__(self, xid=None, index=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if index != None:
             self.index = index
         else:
             self.index = 0
+        return
 
     def pack(self):
         packed = []
@@ -1286,18 +1233,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_get_ip_mask_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -1309,22 +1253,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.index != other.index: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_get_ip_mask_request {")
         with q.group():
@@ -1341,14 +1273,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_get_l2_table_reply(Message):
+bsn_header.subtypes[1] = bsn_get_ip_mask_request
+
+class bsn_get_l2_table_reply(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 14
 
     def __init__(self, xid=None, l2_table_enable=None, l2_table_priority=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if l2_table_enable != None:
             self.l2_table_enable = l2_table_enable
         else:
@@ -1357,6 +1294,7 @@
             self.l2_table_priority = l2_table_priority
         else:
             self.l2_table_priority = 0
+        return
 
     def pack(self):
         packed = []
@@ -1375,18 +1313,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_get_l2_table_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -1400,23 +1335,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.l2_table_enable != other.l2_table_enable: return False
         if self.l2_table_priority != other.l2_table_priority: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_get_l2_table_reply {")
         with q.group():
@@ -1436,14 +1359,20 @@
             q.breakable()
         q.text('}')
 
-class bsn_get_l2_table_request(Message):
+bsn_header.subtypes[14] = bsn_get_l2_table_reply
+
+class bsn_get_l2_table_request(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 13
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -1458,18 +1387,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_get_l2_table_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -1479,21 +1405,9 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_get_l2_table_request {")
         with q.group():
@@ -1507,18 +1421,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_get_mirroring_reply(Message):
+bsn_header.subtypes[13] = bsn_get_l2_table_request
+
+class bsn_get_mirroring_reply(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 5
 
     def __init__(self, xid=None, report_mirror_ports=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if report_mirror_ports != None:
             self.report_mirror_ports = report_mirror_ports
         else:
             self.report_mirror_ports = 0
+        return
 
     def pack(self):
         packed = []
@@ -1535,18 +1455,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_get_mirroring_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -1558,22 +1475,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.report_mirror_ports != other.report_mirror_ports: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_get_mirroring_reply {")
         with q.group():
@@ -1590,18 +1495,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_get_mirroring_request(Message):
+bsn_header.subtypes[5] = bsn_get_mirroring_reply
+
+class bsn_get_mirroring_request(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 4
 
     def __init__(self, xid=None, report_mirror_ports=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if report_mirror_ports != None:
             self.report_mirror_ports = report_mirror_ports
         else:
             self.report_mirror_ports = 0
+        return
 
     def pack(self):
         packed = []
@@ -1618,18 +1529,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_get_mirroring_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -1641,22 +1549,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.report_mirror_ports != other.report_mirror_ports: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_get_mirroring_request {")
         with q.group():
@@ -1673,14 +1569,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_hybrid_get_reply(Message):
+bsn_header.subtypes[4] = bsn_get_mirroring_request
+
+class bsn_hybrid_get_reply(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 28
 
     def __init__(self, xid=None, hybrid_enable=None, hybrid_version=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if hybrid_enable != None:
             self.hybrid_enable = hybrid_enable
         else:
@@ -1689,6 +1590,7 @@
             self.hybrid_version = hybrid_version
         else:
             self.hybrid_version = 0
+        return
 
     def pack(self):
         packed = []
@@ -1707,18 +1609,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_hybrid_get_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -1732,23 +1631,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.hybrid_enable != other.hybrid_enable: return False
         if self.hybrid_version != other.hybrid_version: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_hybrid_get_reply {")
         with q.group():
@@ -1768,14 +1655,20 @@
             q.breakable()
         q.text('}')
 
-class bsn_hybrid_get_request(Message):
+bsn_header.subtypes[28] = bsn_hybrid_get_reply
+
+class bsn_hybrid_get_request(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 27
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -1790,18 +1683,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_hybrid_get_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -1811,21 +1701,9 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_hybrid_get_request {")
         with q.group():
@@ -1839,14 +1717,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_pdu_rx_reply(Message):
+bsn_header.subtypes[27] = bsn_hybrid_get_request
+
+class bsn_pdu_rx_reply(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 34
 
     def __init__(self, xid=None, status=None, port_no=None, slot_num=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
@@ -1859,6 +1742,7 @@
             self.slot_num = slot_num
         else:
             self.slot_num = 0
+        return
 
     def pack(self):
         packed = []
@@ -1876,18 +1760,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_pdu_rx_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -1900,24 +1781,12 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         if self.port_no != other.port_no: return False
         if self.slot_num != other.slot_num: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_pdu_rx_reply {")
         with q.group():
@@ -1940,14 +1809,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_pdu_rx_request(Message):
+bsn_header.subtypes[34] = bsn_pdu_rx_reply
+
+class bsn_pdu_rx_request(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 33
 
     def __init__(self, xid=None, timeout_ms=None, port_no=None, slot_num=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if timeout_ms != None:
             self.timeout_ms = timeout_ms
         else:
@@ -1964,6 +1838,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -1983,18 +1858,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_pdu_rx_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -2009,8 +1881,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.timeout_ms != other.timeout_ms: return False
         if self.port_no != other.port_no: return False
@@ -2018,16 +1888,6 @@
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_pdu_rx_request {")
         with q.group():
@@ -2053,14 +1913,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_pdu_rx_timeout(Message):
+bsn_header.subtypes[33] = bsn_pdu_rx_request
+
+class bsn_pdu_rx_timeout(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 35
 
     def __init__(self, xid=None, port_no=None, slot_num=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if port_no != None:
             self.port_no = port_no
         else:
@@ -2069,6 +1934,7 @@
             self.slot_num = slot_num
         else:
             self.slot_num = 0
+        return
 
     def pack(self):
         packed = []
@@ -2085,18 +1951,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_pdu_rx_timeout()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -2108,23 +1971,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.port_no != other.port_no: return False
         if self.slot_num != other.slot_num: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_pdu_rx_timeout {")
         with q.group():
@@ -2144,14 +1995,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_pdu_tx_reply(Message):
+bsn_header.subtypes[35] = bsn_pdu_rx_timeout
+
+class bsn_pdu_tx_reply(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 32
 
     def __init__(self, xid=None, status=None, port_no=None, slot_num=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
@@ -2164,6 +2020,7 @@
             self.slot_num = slot_num
         else:
             self.slot_num = 0
+        return
 
     def pack(self):
         packed = []
@@ -2181,18 +2038,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_pdu_tx_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -2205,24 +2059,12 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         if self.port_no != other.port_no: return False
         if self.slot_num != other.slot_num: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_pdu_tx_reply {")
         with q.group():
@@ -2245,14 +2087,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_pdu_tx_request(Message):
+bsn_header.subtypes[32] = bsn_pdu_tx_reply
+
+class bsn_pdu_tx_request(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 31
 
     def __init__(self, xid=None, tx_interval_ms=None, port_no=None, slot_num=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if tx_interval_ms != None:
             self.tx_interval_ms = tx_interval_ms
         else:
@@ -2269,6 +2116,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -2288,18 +2136,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_pdu_tx_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -2314,8 +2159,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.tx_interval_ms != other.tx_interval_ms: return False
         if self.port_no != other.port_no: return False
@@ -2323,16 +2166,6 @@
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_pdu_tx_request {")
         with q.group():
@@ -2358,14 +2191,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_set_ip_mask(Message):
+bsn_header.subtypes[31] = bsn_pdu_tx_request
+
+class bsn_set_ip_mask(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 0
 
     def __init__(self, xid=None, index=None, mask=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if index != None:
             self.index = index
         else:
@@ -2374,6 +2212,7 @@
             self.mask = mask
         else:
             self.mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -2391,18 +2230,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_set_ip_mask()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -2415,23 +2251,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.index != other.index: return False
         if self.mask != other.mask: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_set_ip_mask {")
         with q.group():
@@ -2451,14 +2275,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_set_l2_table_reply(Message):
+bsn_header.subtypes[0] = bsn_set_ip_mask
+
+class bsn_set_l2_table_reply(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 24
 
     def __init__(self, xid=None, l2_table_enable=None, l2_table_priority=None, status=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if l2_table_enable != None:
             self.l2_table_enable = l2_table_enable
         else:
@@ -2471,6 +2300,7 @@
             self.status = status
         else:
             self.status = 0
+        return
 
     def pack(self):
         packed = []
@@ -2489,18 +2319,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_set_l2_table_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -2514,24 +2341,12 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.l2_table_enable != other.l2_table_enable: return False
         if self.l2_table_priority != other.l2_table_priority: return False
         if self.status != other.status: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_set_l2_table_reply {")
         with q.group():
@@ -2554,14 +2369,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_set_l2_table_request(Message):
+bsn_header.subtypes[24] = bsn_set_l2_table_reply
+
+class bsn_set_l2_table_request(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 12
 
     def __init__(self, xid=None, l2_table_enable=None, l2_table_priority=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if l2_table_enable != None:
             self.l2_table_enable = l2_table_enable
         else:
@@ -2570,6 +2390,7 @@
             self.l2_table_priority = l2_table_priority
         else:
             self.l2_table_priority = 0
+        return
 
     def pack(self):
         packed = []
@@ -2588,18 +2409,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_set_l2_table_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -2613,23 +2431,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.l2_table_enable != other.l2_table_enable: return False
         if self.l2_table_priority != other.l2_table_priority: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_set_l2_table_request {")
         with q.group():
@@ -2649,18 +2455,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_set_mirroring(Message):
+bsn_header.subtypes[12] = bsn_set_l2_table_request
+
+class bsn_set_mirroring(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 3
 
     def __init__(self, xid=None, report_mirror_ports=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if report_mirror_ports != None:
             self.report_mirror_ports = report_mirror_ports
         else:
             self.report_mirror_ports = 0
+        return
 
     def pack(self):
         packed = []
@@ -2677,18 +2489,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_set_mirroring()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -2700,22 +2509,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.report_mirror_ports != other.report_mirror_ports: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_set_mirroring {")
         with q.group():
@@ -2732,18 +2529,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_set_pktin_suppression_reply(Message):
+bsn_header.subtypes[3] = bsn_set_mirroring
+
+class bsn_set_pktin_suppression_reply(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 25
 
     def __init__(self, xid=None, status=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
             self.status = 0
+        return
 
     def pack(self):
         packed = []
@@ -2759,18 +2562,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_set_pktin_suppression_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -2781,22 +2581,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_set_pktin_suppression_reply {")
         with q.group():
@@ -2813,14 +2601,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_set_pktin_suppression_request(Message):
+bsn_header.subtypes[25] = bsn_set_pktin_suppression_reply
+
+class bsn_set_pktin_suppression_request(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 11
 
     def __init__(self, xid=None, enabled=None, idle_timeout=None, hard_timeout=None, priority=None, cookie=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if enabled != None:
             self.enabled = enabled
         else:
@@ -2841,6 +2634,7 @@
             self.cookie = cookie
         else:
             self.cookie = 0
+        return
 
     def pack(self):
         packed = []
@@ -2861,18 +2655,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_set_pktin_suppression_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -2888,8 +2679,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.enabled != other.enabled: return False
         if self.idle_timeout != other.idle_timeout: return False
@@ -2898,16 +2687,6 @@
         if self.cookie != other.cookie: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_set_pktin_suppression_request {")
         with q.group():
@@ -2936,14 +2715,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_shell_command(Message):
+bsn_header.subtypes[11] = bsn_set_pktin_suppression_request
+
+class bsn_shell_command(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 6
 
     def __init__(self, xid=None, service=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if service != None:
             self.service = service
         else:
@@ -2952,6 +2736,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -2968,18 +2753,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_shell_command()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -2991,23 +2773,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.service != other.service: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_shell_command {")
         with q.group():
@@ -3027,18 +2797,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_shell_output(Message):
+bsn_header.subtypes[6] = bsn_shell_command
+
+class bsn_shell_output(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 7
 
     def __init__(self, xid=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if data != None:
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -3054,18 +2830,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_shell_output()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -3076,22 +2849,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_shell_output {")
         with q.group():
@@ -3108,18 +2869,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_shell_status(Message):
+bsn_header.subtypes[7] = bsn_shell_output
+
+class bsn_shell_status(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 8
 
     def __init__(self, xid=None, status=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
             self.status = 0
+        return
 
     def pack(self):
         packed = []
@@ -3135,18 +2902,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_shell_status()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -3157,22 +2921,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_shell_status {")
         with q.group():
@@ -3189,14 +2941,75 @@
             q.breakable()
         q.text('}')
 
-class bsn_virtual_port_create_reply(Message):
+bsn_header.subtypes[8] = bsn_shell_status
+
+class experimenter_stats_reply(stats_reply):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 12)
+        try:
+            subclass = experimenter_stats_reply.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter_stats_reply stats_reply message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+stats_reply.subtypes[65535] = experimenter_stats_reply
+
+class bsn_stats_reply(experimenter_stats_reply):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 20)
+        try:
+            subclass = bsn_stats_reply.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown bsn_stats_reply experimenter_stats_reply stats_reply message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter_stats_reply.subtypes[6035143] = bsn_stats_reply
+
+class experimenter_stats_request(stats_request):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 12)
+        try:
+            subclass = experimenter_stats_request.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter_stats_request stats_request message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+stats_request.subtypes[65535] = experimenter_stats_request
+
+class bsn_stats_request(experimenter_stats_request):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 20)
+        try:
+            subclass = bsn_stats_request.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown bsn_stats_request experimenter_stats_request stats_request message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter_stats_request.subtypes[6035143] = bsn_stats_request
+
+class bsn_virtual_port_create_reply(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 16
 
     def __init__(self, xid=None, status=None, vport_no=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
@@ -3205,6 +3018,7 @@
             self.vport_no = vport_no
         else:
             self.vport_no = 0
+        return
 
     def pack(self):
         packed = []
@@ -3221,18 +3035,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_virtual_port_create_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -3244,23 +3055,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         if self.vport_no != other.vport_no: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_virtual_port_create_reply {")
         with q.group():
@@ -3280,18 +3079,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_virtual_port_create_request(Message):
+bsn_header.subtypes[16] = bsn_virtual_port_create_reply
+
+class bsn_virtual_port_create_request(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 15
 
     def __init__(self, xid=None, vport=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if vport != None:
             self.vport = vport
         else:
             self.vport = common.bsn_vport_q_in_q()
+        return
 
     def pack(self):
         packed = []
@@ -3307,18 +3112,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_virtual_port_create_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -3329,22 +3131,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.vport != other.vport: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_virtual_port_create_request {")
         with q.group():
@@ -3361,18 +3151,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_virtual_port_remove_reply(Message):
+bsn_header.subtypes[15] = bsn_virtual_port_create_request
+
+class bsn_virtual_port_remove_reply(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 26
 
     def __init__(self, xid=None, status=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
             self.status = 0
+        return
 
     def pack(self):
         packed = []
@@ -3388,18 +3184,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_virtual_port_remove_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -3410,22 +3203,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_virtual_port_remove_reply {")
         with q.group():
@@ -3442,18 +3223,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_virtual_port_remove_request(Message):
+bsn_header.subtypes[26] = bsn_virtual_port_remove_reply
+
+class bsn_virtual_port_remove_request(bsn_header):
     version = 1
     type = 4
     experimenter = 6035143
     subtype = 17
 
     def __init__(self, xid=None, vport_no=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if vport_no != None:
             self.vport_no = vport_no
         else:
             self.vport_no = 0
+        return
 
     def pack(self):
         packed = []
@@ -3469,18 +3256,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_virtual_port_remove_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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)
@@ -3491,22 +3275,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.vport_no != other.vport_no: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_virtual_port_remove_request {")
         with q.group():
@@ -3523,13 +3295,18 @@
             q.breakable()
         q.text('}')
 
-class desc_stats_reply(Message):
+bsn_header.subtypes[17] = bsn_virtual_port_remove_request
+
+class desc_stats_reply(stats_reply):
     version = 1
     type = 17
     stats_type = 0
 
     def __init__(self, xid=None, flags=None, mfr_desc=None, hw_desc=None, sw_desc=None, serial_num=None, dp_desc=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -3554,6 +3331,7 @@
             self.dp_desc = dp_desc
         else:
             self.dp_desc = ""
+        return
 
     def pack(self):
         packed = []
@@ -3573,18 +3351,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = desc_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 17)
         _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 == 0)
@@ -3598,8 +3373,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.mfr_desc != other.mfr_desc: return False
@@ -3609,16 +3382,6 @@
         if self.dp_desc != other.dp_desc: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("desc_stats_reply {")
         with q.group():
@@ -3650,17 +3413,23 @@
             q.breakable()
         q.text('}')
 
-class desc_stats_request(Message):
+stats_reply.subtypes[0] = desc_stats_reply
+
+class desc_stats_request(stats_request):
     version = 1
     type = 16
     stats_type = 0
 
     def __init__(self, xid=None, flags=None):
-        self.xid = xid
+        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 = []
@@ -3675,18 +3444,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = desc_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 16)
         _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 == 0)
@@ -3695,22 +3461,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("desc_stats_request {")
         with q.group():
@@ -3727,16 +3481,22 @@
             q.breakable()
         q.text('}')
 
-class echo_reply(Message):
+stats_request.subtypes[0] = desc_stats_request
+
+class echo_reply(message):
     version = 1
     type = 3
 
     def __init__(self, xid=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if data != None:
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -3750,40 +3510,25 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = echo_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 3)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.data = str(reader.read_all())
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("echo_reply {")
         with q.group():
@@ -3800,16 +3545,22 @@
             q.breakable()
         q.text('}')
 
-class echo_request(Message):
+message.subtypes[3] = echo_reply
+
+class echo_request(message):
     version = 1
     type = 2
 
     def __init__(self, xid=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if data != None:
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -3823,40 +3574,25 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = echo_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 2)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.data = str(reader.read_all())
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("echo_request {")
         with q.group():
@@ -3873,12 +3609,17 @@
             q.breakable()
         q.text('}')
 
-class features_reply(Message):
+message.subtypes[2] = echo_request
+
+class features_reply(message):
     version = 1
     type = 6
 
     def __init__(self, xid=None, datapath_id=None, n_buffers=None, n_tables=None, capabilities=None, actions=None, ports=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if datapath_id != None:
             self.datapath_id = datapath_id
         else:
@@ -3903,6 +3644,7 @@
             self.ports = ports
         else:
             self.ports = []
+        return
 
     def pack(self):
         packed = []
@@ -3916,24 +3658,21 @@
         packed.append('\x00' * 3)
         packed.append(struct.pack("!L", self.capabilities))
         packed.append(struct.pack("!L", self.actions))
-        packed.append(util.pack_list(self.ports))
+        packed.append(loxi.generic_util.pack_list(self.ports))
         length = sum([len(x) for x in packed])
         packed[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = features_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 6)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.datapath_id = reader.read("!Q")[0]
         obj.n_buffers = reader.read("!L")[0]
@@ -3946,8 +3685,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.datapath_id != other.datapath_id: return False
         if self.n_buffers != other.n_buffers: return False
@@ -3957,16 +3694,6 @@
         if self.ports != other.ports: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("features_reply {")
         with q.group():
@@ -3998,12 +3725,18 @@
             q.breakable()
         q.text('}')
 
-class features_request(Message):
+message.subtypes[6] = features_reply
+
+class features_request(message):
     version = 1
     type = 5
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -4016,38 +3749,23 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = features_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 5)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("features_request {")
         with q.group():
@@ -4061,13 +3779,32 @@
             q.breakable()
         q.text('}')
 
-class flow_add(Message):
+message.subtypes[5] = features_request
+
+class flow_mod(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 56)
+        try:
+            subclass = flow_mod.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown flow_mod message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[14] = flow_mod
+
+class flow_add(flow_mod):
     version = 1
     type = 14
     _command = 0
 
     def __init__(self, xid=None, match=None, cookie=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, flags=None, actions=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if match != None:
             self.match = match
         else:
@@ -4104,6 +3841,7 @@
             self.actions = actions
         else:
             self.actions = []
+        return
 
     def pack(self):
         packed = []
@@ -4120,24 +3858,21 @@
         packed.append(struct.pack("!L", self.buffer_id))
         packed.append(util.pack_port_no(self.out_port))
         packed.append(struct.pack("!H", self.flags))
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_add()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 14)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.match = common.match.unpack(reader)
         obj.cookie = reader.read("!Q")[0]
@@ -4149,13 +3884,11 @@
         obj.buffer_id = reader.read("!L")[0]
         obj.out_port = util.unpack_port_no(reader)
         obj.flags = reader.read("!H")[0]
-        obj.actions = action.unpack_list(reader)
+        obj.actions = loxi.generic_util.unpack_list(reader, action.action.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.match != other.match: return False
         if self.cookie != other.cookie: return False
@@ -4168,16 +3901,6 @@
         if self.actions != other.actions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_add {")
         with q.group():
@@ -4218,13 +3941,18 @@
             q.breakable()
         q.text('}')
 
-class flow_delete(Message):
+flow_mod.subtypes[0] = flow_add
+
+class flow_delete(flow_mod):
     version = 1
     type = 14
     _command = 3
 
     def __init__(self, xid=None, match=None, cookie=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, flags=None, actions=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if match != None:
             self.match = match
         else:
@@ -4261,6 +3989,7 @@
             self.actions = actions
         else:
             self.actions = []
+        return
 
     def pack(self):
         packed = []
@@ -4277,24 +4006,21 @@
         packed.append(struct.pack("!L", self.buffer_id))
         packed.append(util.pack_port_no(self.out_port))
         packed.append(struct.pack("!H", self.flags))
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_delete()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 14)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.match = common.match.unpack(reader)
         obj.cookie = reader.read("!Q")[0]
@@ -4306,13 +4032,11 @@
         obj.buffer_id = reader.read("!L")[0]
         obj.out_port = util.unpack_port_no(reader)
         obj.flags = reader.read("!H")[0]
-        obj.actions = action.unpack_list(reader)
+        obj.actions = loxi.generic_util.unpack_list(reader, action.action.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.match != other.match: return False
         if self.cookie != other.cookie: return False
@@ -4325,16 +4049,6 @@
         if self.actions != other.actions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_delete {")
         with q.group():
@@ -4375,13 +4089,18 @@
             q.breakable()
         q.text('}')
 
-class flow_delete_strict(Message):
+flow_mod.subtypes[3] = flow_delete
+
+class flow_delete_strict(flow_mod):
     version = 1
     type = 14
     _command = 4
 
     def __init__(self, xid=None, match=None, cookie=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, flags=None, actions=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if match != None:
             self.match = match
         else:
@@ -4418,6 +4137,7 @@
             self.actions = actions
         else:
             self.actions = []
+        return
 
     def pack(self):
         packed = []
@@ -4434,24 +4154,21 @@
         packed.append(struct.pack("!L", self.buffer_id))
         packed.append(util.pack_port_no(self.out_port))
         packed.append(struct.pack("!H", self.flags))
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_delete_strict()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 14)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.match = common.match.unpack(reader)
         obj.cookie = reader.read("!Q")[0]
@@ -4463,13 +4180,11 @@
         obj.buffer_id = reader.read("!L")[0]
         obj.out_port = util.unpack_port_no(reader)
         obj.flags = reader.read("!H")[0]
-        obj.actions = action.unpack_list(reader)
+        obj.actions = loxi.generic_util.unpack_list(reader, action.action.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.match != other.match: return False
         if self.cookie != other.cookie: return False
@@ -4482,16 +4197,6 @@
         if self.actions != other.actions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_delete_strict {")
         with q.group():
@@ -4532,13 +4237,18 @@
             q.breakable()
         q.text('}')
 
-class flow_mod_failed_error_msg(Message):
+flow_mod.subtypes[4] = flow_delete_strict
+
+class flow_mod_failed_error_msg(error_msg):
     version = 1
     type = 1
     err_type = 3
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -4547,6 +4257,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -4562,18 +4273,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_mod_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 3)
@@ -4583,23 +4291,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_mod_failed_error_msg {")
         with q.group():
@@ -4619,13 +4315,18 @@
             q.breakable()
         q.text('}')
 
-class flow_modify(Message):
+error_msg.subtypes[3] = flow_mod_failed_error_msg
+
+class flow_modify(flow_mod):
     version = 1
     type = 14
     _command = 1
 
     def __init__(self, xid=None, match=None, cookie=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, flags=None, actions=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if match != None:
             self.match = match
         else:
@@ -4662,6 +4363,7 @@
             self.actions = actions
         else:
             self.actions = []
+        return
 
     def pack(self):
         packed = []
@@ -4678,24 +4380,21 @@
         packed.append(struct.pack("!L", self.buffer_id))
         packed.append(util.pack_port_no(self.out_port))
         packed.append(struct.pack("!H", self.flags))
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_modify()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 14)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.match = common.match.unpack(reader)
         obj.cookie = reader.read("!Q")[0]
@@ -4707,13 +4406,11 @@
         obj.buffer_id = reader.read("!L")[0]
         obj.out_port = util.unpack_port_no(reader)
         obj.flags = reader.read("!H")[0]
-        obj.actions = action.unpack_list(reader)
+        obj.actions = loxi.generic_util.unpack_list(reader, action.action.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.match != other.match: return False
         if self.cookie != other.cookie: return False
@@ -4726,16 +4423,6 @@
         if self.actions != other.actions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_modify {")
         with q.group():
@@ -4776,13 +4463,18 @@
             q.breakable()
         q.text('}')
 
-class flow_modify_strict(Message):
+flow_mod.subtypes[1] = flow_modify
+
+class flow_modify_strict(flow_mod):
     version = 1
     type = 14
     _command = 2
 
     def __init__(self, xid=None, match=None, cookie=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, flags=None, actions=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if match != None:
             self.match = match
         else:
@@ -4819,6 +4511,7 @@
             self.actions = actions
         else:
             self.actions = []
+        return
 
     def pack(self):
         packed = []
@@ -4835,24 +4528,21 @@
         packed.append(struct.pack("!L", self.buffer_id))
         packed.append(util.pack_port_no(self.out_port))
         packed.append(struct.pack("!H", self.flags))
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_modify_strict()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 14)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.match = common.match.unpack(reader)
         obj.cookie = reader.read("!Q")[0]
@@ -4864,13 +4554,11 @@
         obj.buffer_id = reader.read("!L")[0]
         obj.out_port = util.unpack_port_no(reader)
         obj.flags = reader.read("!H")[0]
-        obj.actions = action.unpack_list(reader)
+        obj.actions = loxi.generic_util.unpack_list(reader, action.action.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.match != other.match: return False
         if self.cookie != other.cookie: return False
@@ -4883,16 +4571,6 @@
         if self.actions != other.actions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_modify_strict {")
         with q.group():
@@ -4933,12 +4611,17 @@
             q.breakable()
         q.text('}')
 
-class flow_removed(Message):
+flow_mod.subtypes[2] = flow_modify_strict
+
+class flow_removed(message):
     version = 1
     type = 11
 
     def __init__(self, xid=None, match=None, cookie=None, priority=None, reason=None, duration_sec=None, duration_nsec=None, idle_timeout=None, packet_count=None, byte_count=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if match != None:
             self.match = match
         else:
@@ -4975,6 +4658,7 @@
             self.byte_count = byte_count
         else:
             self.byte_count = 0
+        return
 
     def pack(self):
         packed = []
@@ -4998,18 +4682,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_removed()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 11)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.match = common.match.unpack(reader)
         obj.cookie = reader.read("!Q")[0]
@@ -5026,8 +4707,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.match != other.match: return False
         if self.cookie != other.cookie: return False
@@ -5040,16 +4719,6 @@
         if self.byte_count != other.byte_count: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_removed {")
         with q.group():
@@ -5090,13 +4759,18 @@
             q.breakable()
         q.text('}')
 
-class flow_stats_reply(Message):
+message.subtypes[11] = flow_removed
+
+class flow_stats_reply(stats_reply):
     version = 1
     type = 17
     stats_type = 1
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -5105,6 +4779,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -5114,50 +4789,35 @@
         packed.append(struct.pack("!L", self.xid))
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 17)
         _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 == 1)
         obj.flags = reader.read("!H")[0]
-        obj.entries = common.unpack_list_flow_stats_entry(reader)
+        obj.entries = loxi.generic_util.unpack_list(reader, common.flow_stats_entry.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_stats_reply {")
         with q.group():
@@ -5177,13 +4837,18 @@
             q.breakable()
         q.text('}')
 
-class flow_stats_request(Message):
+stats_reply.subtypes[1] = flow_stats_reply
+
+class flow_stats_request(stats_request):
     version = 1
     type = 16
     stats_type = 1
 
     def __init__(self, xid=None, flags=None, match=None, table_id=None, out_port=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -5200,6 +4865,7 @@
             self.out_port = out_port
         else:
             self.out_port = 0
+        return
 
     def pack(self):
         packed = []
@@ -5218,18 +4884,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 16)
         _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 == 1)
@@ -5242,8 +4905,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.match != other.match: return False
@@ -5251,16 +4912,6 @@
         if self.out_port != other.out_port: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_stats_request {")
         with q.group():
@@ -5286,12 +4937,17 @@
             q.breakable()
         q.text('}')
 
-class get_config_reply(Message):
+stats_request.subtypes[1] = flow_stats_request
+
+class get_config_reply(message):
     version = 1
     type = 8
 
     def __init__(self, xid=None, flags=None, miss_send_len=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -5300,6 +4956,7 @@
             self.miss_send_len = miss_send_len
         else:
             self.miss_send_len = 0
+        return
 
     def pack(self):
         packed = []
@@ -5314,18 +4971,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = get_config_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 8)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.flags = reader.read("!H")[0]
         obj.miss_send_len = reader.read("!H")[0]
@@ -5333,23 +4987,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.miss_send_len != other.miss_send_len: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("get_config_reply {")
         with q.group():
@@ -5369,12 +5011,18 @@
             q.breakable()
         q.text('}')
 
-class get_config_request(Message):
+message.subtypes[8] = get_config_reply
+
+class get_config_request(message):
     version = 1
     type = 7
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -5387,38 +5035,23 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = get_config_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 7)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("get_config_request {")
         with q.group():
@@ -5432,12 +5065,18 @@
             q.breakable()
         q.text('}')
 
-class hello(Message):
+message.subtypes[7] = get_config_request
+
+class hello(message):
     version = 1
     type = 0
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -5450,38 +5089,23 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = hello()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 0)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("hello {")
         with q.group():
@@ -5495,13 +5119,18 @@
             q.breakable()
         q.text('}')
 
-class hello_failed_error_msg(Message):
+message.subtypes[0] = hello
+
+class hello_failed_error_msg(error_msg):
     version = 1
     type = 1
     err_type = 0
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -5510,6 +5139,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -5525,18 +5155,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = hello_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 0)
@@ -5546,23 +5173,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("hello_failed_error_msg {")
         with q.group():
@@ -5582,18 +5197,38 @@
             q.breakable()
         q.text('}')
 
-class nicira_controller_role_reply(Message):
+error_msg.subtypes[0] = hello_failed_error_msg
+
+class nicira_header(experimenter):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 12)
+        try:
+            subclass = nicira_header.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown nicira_header experimenter message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter.subtypes[8992] = nicira_header
+
+class nicira_controller_role_reply(nicira_header):
     version = 1
     type = 4
     experimenter = 8992
     subtype = 11
 
     def __init__(self, xid=None, role=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if role != None:
             self.role = role
         else:
             self.role = 0
+        return
 
     def pack(self):
         packed = []
@@ -5609,18 +5244,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = nicira_controller_role_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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 == 8992)
@@ -5631,22 +5263,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.role != other.role: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("nicira_controller_role_reply {")
         with q.group():
@@ -5663,18 +5283,24 @@
             q.breakable()
         q.text('}')
 
-class nicira_controller_role_request(Message):
+nicira_header.subtypes[11] = nicira_controller_role_reply
+
+class nicira_controller_role_request(nicira_header):
     version = 1
     type = 4
     experimenter = 8992
     subtype = 10
 
     def __init__(self, xid=None, role=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if role != None:
             self.role = role
         else:
             self.role = 0
+        return
 
     def pack(self):
         packed = []
@@ -5690,18 +5316,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = nicira_controller_role_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _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 == 8992)
@@ -5712,22 +5335,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.role != other.role: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("nicira_controller_role_request {")
         with q.group():
@@ -5744,12 +5355,17 @@
             q.breakable()
         q.text('}')
 
-class packet_in(Message):
+nicira_header.subtypes[10] = nicira_controller_role_request
+
+class packet_in(message):
     version = 1
     type = 10
 
     def __init__(self, xid=None, buffer_id=None, total_len=None, in_port=None, reason=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if buffer_id != None:
             self.buffer_id = buffer_id
         else:
@@ -5770,6 +5386,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -5788,18 +5405,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = packet_in()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 10)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.buffer_id = reader.read("!L")[0]
         obj.total_len = reader.read("!H")[0]
@@ -5811,8 +5425,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.buffer_id != other.buffer_id: return False
         if self.total_len != other.total_len: return False
@@ -5821,16 +5433,6 @@
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("packet_in {")
         with q.group():
@@ -5859,12 +5461,17 @@
             q.breakable()
         q.text('}')
 
-class packet_out(Message):
+message.subtypes[10] = packet_in
+
+class packet_out(message):
     version = 1
     type = 13
 
     def __init__(self, xid=None, buffer_id=None, in_port=None, actions=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if buffer_id != None:
             self.buffer_id = buffer_id
         else:
@@ -5881,6 +5488,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -5891,7 +5499,7 @@
         packed.append(struct.pack("!L", self.buffer_id))
         packed.append(util.pack_port_no(self.in_port))
         packed.append(struct.pack("!H", 0)) # placeholder for actions_len at index 6
-        packed.append(util.pack_list(self.actions))
+        packed.append(loxi.generic_util.pack_list(self.actions))
         packed[6] = struct.pack("!H", len(packed[-1]))
         packed.append(self.data)
         length = sum([len(x) for x in packed])
@@ -5899,30 +5507,25 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = packet_out()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 13)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.buffer_id = reader.read("!L")[0]
         obj.in_port = util.unpack_port_no(reader)
         _actions_len = reader.read("!H")[0]
-        obj.actions = action.unpack_list(reader.slice(_actions_len))
+        obj.actions = loxi.generic_util.unpack_list(reader.slice(_actions_len), action.action.unpack)
         obj.data = str(reader.read_all())
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.buffer_id != other.buffer_id: return False
         if self.in_port != other.in_port: return False
@@ -5930,16 +5533,6 @@
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("packet_out {")
         with q.group():
@@ -5965,12 +5558,17 @@
             q.breakable()
         q.text('}')
 
-class port_mod(Message):
+message.subtypes[13] = packet_out
+
+class port_mod(message):
     version = 1
     type = 15
 
     def __init__(self, xid=None, port_no=None, hw_addr=None, config=None, mask=None, advertise=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if port_no != None:
             self.port_no = port_no
         else:
@@ -5991,6 +5589,7 @@
             self.advertise = advertise
         else:
             self.advertise = 0
+        return
 
     def pack(self):
         packed = []
@@ -6009,18 +5608,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_mod()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 15)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.port_no = util.unpack_port_no(reader)
         obj.hw_addr = list(reader.read('!6B'))
@@ -6032,8 +5628,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.port_no != other.port_no: return False
         if self.hw_addr != other.hw_addr: return False
@@ -6042,16 +5636,6 @@
         if self.advertise != other.advertise: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_mod {")
         with q.group():
@@ -6080,13 +5664,18 @@
             q.breakable()
         q.text('}')
 
-class port_mod_failed_error_msg(Message):
+message.subtypes[15] = port_mod
+
+class port_mod_failed_error_msg(error_msg):
     version = 1
     type = 1
     err_type = 4
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -6095,6 +5684,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -6110,18 +5700,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_mod_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 4)
@@ -6131,23 +5718,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_mod_failed_error_msg {")
         with q.group():
@@ -6167,13 +5742,18 @@
             q.breakable()
         q.text('}')
 
-class port_stats_reply(Message):
+error_msg.subtypes[4] = port_mod_failed_error_msg
+
+class port_stats_reply(stats_reply):
     version = 1
     type = 17
     stats_type = 4
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -6182,6 +5762,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -6191,24 +5772,21 @@
         packed.append(struct.pack("!L", self.xid))
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 17)
         _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 == 4)
@@ -6218,23 +5796,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_stats_reply {")
         with q.group():
@@ -6254,13 +5820,18 @@
             q.breakable()
         q.text('}')
 
-class port_stats_request(Message):
+stats_reply.subtypes[4] = port_stats_reply
+
+class port_stats_request(stats_request):
     version = 1
     type = 16
     stats_type = 4
 
     def __init__(self, xid=None, flags=None, port_no=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -6269,6 +5840,7 @@
             self.port_no = port_no
         else:
             self.port_no = 0
+        return
 
     def pack(self):
         packed = []
@@ -6285,18 +5857,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 16)
         _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 == 4)
@@ -6307,23 +5876,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.port_no != other.port_no: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_stats_request {")
         with q.group():
@@ -6343,12 +5900,17 @@
             q.breakable()
         q.text('}')
 
-class port_status(Message):
+stats_request.subtypes[4] = port_stats_request
+
+class port_status(message):
     version = 1
     type = 12
 
     def __init__(self, xid=None, reason=None, desc=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if reason != None:
             self.reason = reason
         else:
@@ -6357,6 +5919,7 @@
             self.desc = desc
         else:
             self.desc = common.port_desc()
+        return
 
     def pack(self):
         packed = []
@@ -6372,18 +5935,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_status()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 12)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.reason = reader.read("!B")[0]
         reader.skip(7)
@@ -6392,23 +5952,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.reason != other.reason: return False
         if self.desc != other.desc: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_status {")
         with q.group():
@@ -6428,12 +5976,17 @@
             q.breakable()
         q.text('}')
 
-class queue_get_config_reply(Message):
+message.subtypes[12] = port_status
+
+class queue_get_config_reply(message):
     version = 1
     type = 21
 
     def __init__(self, xid=None, port=None, queues=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if port != None:
             self.port = port
         else:
@@ -6442,6 +5995,7 @@
             self.queues = queues
         else:
             self.queues = []
+        return
 
     def pack(self):
         packed = []
@@ -6451,49 +6005,34 @@
         packed.append(struct.pack("!L", self.xid))
         packed.append(util.pack_port_no(self.port))
         packed.append('\x00' * 6)
-        packed.append(util.pack_list(self.queues))
+        packed.append(loxi.generic_util.pack_list(self.queues))
         length = sum([len(x) for x in packed])
         packed[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = queue_get_config_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 21)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.port = util.unpack_port_no(reader)
         reader.skip(6)
-        obj.queues = common.unpack_list_packet_queue(reader)
+        obj.queues = loxi.generic_util.unpack_list(reader, common.packet_queue.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.port != other.port: return False
         if self.queues != other.queues: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_get_config_reply {")
         with q.group():
@@ -6513,16 +6052,22 @@
             q.breakable()
         q.text('}')
 
-class queue_get_config_request(Message):
+message.subtypes[21] = queue_get_config_reply
+
+class queue_get_config_request(message):
     version = 1
     type = 20
 
     def __init__(self, xid=None, port=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if port != None:
             self.port = port
         else:
             self.port = 0
+        return
 
     def pack(self):
         packed = []
@@ -6537,18 +6082,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = queue_get_config_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 20)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.port = util.unpack_port_no(reader)
         reader.skip(2)
@@ -6556,22 +6098,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.port != other.port: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_get_config_request {")
         with q.group():
@@ -6588,13 +6118,18 @@
             q.breakable()
         q.text('}')
 
-class queue_op_failed_error_msg(Message):
+message.subtypes[20] = queue_get_config_request
+
+class queue_op_failed_error_msg(error_msg):
     version = 1
     type = 1
     err_type = 5
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -6603,6 +6138,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -6618,18 +6154,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = queue_op_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 5)
@@ -6639,23 +6172,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_op_failed_error_msg {")
         with q.group():
@@ -6675,13 +6196,18 @@
             q.breakable()
         q.text('}')
 
-class queue_stats_reply(Message):
+error_msg.subtypes[5] = queue_op_failed_error_msg
+
+class queue_stats_reply(stats_reply):
     version = 1
     type = 17
     stats_type = 5
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -6690,6 +6216,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -6699,24 +6226,21 @@
         packed.append(struct.pack("!L", self.xid))
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = queue_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 17)
         _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 == 5)
@@ -6726,23 +6250,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_stats_reply {")
         with q.group():
@@ -6762,13 +6274,18 @@
             q.breakable()
         q.text('}')
 
-class queue_stats_request(Message):
+stats_reply.subtypes[5] = queue_stats_reply
+
+class queue_stats_request(stats_request):
     version = 1
     type = 16
     stats_type = 5
 
     def __init__(self, xid=None, flags=None, port_no=None, queue_id=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -6781,6 +6298,7 @@
             self.queue_id = queue_id
         else:
             self.queue_id = 0
+        return
 
     def pack(self):
         packed = []
@@ -6798,18 +6316,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = queue_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 16)
         _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 == 5)
@@ -6821,24 +6336,12 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.port_no != other.port_no: return False
         if self.queue_id != other.queue_id: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_stats_request {")
         with q.group():
@@ -6861,12 +6364,17 @@
             q.breakable()
         q.text('}')
 
-class set_config(Message):
+stats_request.subtypes[5] = queue_stats_request
+
+class set_config(message):
     version = 1
     type = 9
 
     def __init__(self, xid=None, flags=None, miss_send_len=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -6875,6 +6383,7 @@
             self.miss_send_len = miss_send_len
         else:
             self.miss_send_len = 0
+        return
 
     def pack(self):
         packed = []
@@ -6889,18 +6398,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = set_config()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 9)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.flags = reader.read("!H")[0]
         obj.miss_send_len = reader.read("!H")[0]
@@ -6908,23 +6414,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.miss_send_len != other.miss_send_len: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("set_config {")
         with q.group():
@@ -6944,12 +6438,17 @@
             q.breakable()
         q.text('}')
 
-class table_mod(Message):
+message.subtypes[9] = set_config
+
+class table_mod(message):
     version = 1
     type = 22
 
     def __init__(self, xid=None, table_id=None, config=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if table_id != None:
             self.table_id = table_id
         else:
@@ -6958,6 +6457,7 @@
             self.config = config
         else:
             self.config = 0
+        return
 
     def pack(self):
         packed = []
@@ -6973,18 +6473,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = table_mod()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 22)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.table_id = reader.read("!B")[0]
         reader.skip(3)
@@ -6993,23 +6490,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.table_id != other.table_id: return False
         if self.config != other.config: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_mod {")
         with q.group():
@@ -7029,13 +6514,18 @@
             q.breakable()
         q.text('}')
 
-class table_stats_reply(Message):
+message.subtypes[22] = table_mod
+
+class table_stats_reply(stats_reply):
     version = 1
     type = 17
     stats_type = 3
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -7044,6 +6534,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -7053,24 +6544,21 @@
         packed.append(struct.pack("!L", self.xid))
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = table_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 17)
         _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 == 3)
@@ -7080,23 +6568,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_stats_reply {")
         with q.group():
@@ -7116,17 +6592,23 @@
             q.breakable()
         q.text('}')
 
-class table_stats_request(Message):
+stats_reply.subtypes[3] = table_stats_reply
+
+class table_stats_request(stats_request):
     version = 1
     type = 16
     stats_type = 3
 
     def __init__(self, xid=None, flags=None):
-        self.xid = xid
+        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 = []
@@ -7141,18 +6623,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = table_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 1)
         _type = reader.read("!B")[0]
         assert(_type == 16)
         _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 == 3)
@@ -7161,22 +6640,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_stats_request {")
         with q.group():
@@ -7193,6 +6660,8 @@
             q.breakable()
         q.text('}')
 
+stats_request.subtypes[3] = table_stats_request
+
 
 def parse_header(buf):
     if len(buf) < 8:
@@ -7205,211 +6674,4 @@
         raise loxi.ProtocolError("wrong OpenFlow version (expected %d, got %d)" % (const.OFP_VERSION, msg_ver))
     if len(buf) != msg_len:
         raise loxi.ProtocolError("incorrect message size")
-    if msg_type in parsers:
-        return parsers[msg_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected message type")
-
-def parse_error(buf):
-    if len(buf) < 8 + 2:
-        raise loxi.ProtocolError("message too short")
-    err_type, = struct.unpack_from("!H", buf, 8)
-    if err_type in error_msg_parsers:
-        return error_msg_parsers[err_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected error type %u" % err_type)
-
-def parse_flow_mod(buf):
-    if len(buf) < 57 + 1:
-        raise loxi.ProtocolError("message too short")
-    # Technically uint16_t for OF 1.0
-    cmd, = struct.unpack_from("!B", buf, 57)
-    if cmd in flow_mod_parsers:
-        return flow_mod_parsers[cmd](buf)
-    else:
-        raise loxi.ProtocolError("unexpected flow mod cmd %u" % cmd)
-
-def parse_group_mod(buf):
-    if len(buf) < 8 + 2:
-        raise loxi.ProtocolError("message too short")
-    cmd, = struct.unpack_from("!H", buf, 8)
-    if cmd in flow_mod_parsers:
-        return group_mod_parsers[cmd](buf)
-    else:
-        raise loxi.ProtocolError("unexpected group mod cmd %u" % cmd)
-
-def parse_stats_reply(buf):
-    if len(buf) < 8 + 2:
-        raise loxi.ProtocolError("message too short")
-    stats_type, = struct.unpack_from("!H", buf, 8)
-    if stats_type in stats_reply_parsers:
-        return stats_reply_parsers[stats_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected stats type %u" % stats_type)
-
-def parse_stats_request(buf):
-    if len(buf) < 8 + 2:
-        raise loxi.ProtocolError("message too short")
-    stats_type, = struct.unpack_from("!H", buf, 8)
-    if stats_type in stats_request_parsers:
-        return stats_request_parsers[stats_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected stats type %u" % stats_type)
-
-def parse_experimenter_stats_request(buf):
-    if len(buf) < 24:
-        raise loxi.ProtocolError("experimenter stats request message too short")
-
-    experimenter, exp_type = struct.unpack_from("!LL", buf, 16)
-
-    if experimenter in experimenter_stats_request_parsers and \
-            exp_type in experimenter_stats_request_parsers[experimenter]:
-        return experimenter_stats_request_parsers[experimenter][exp_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected stats request experimenter %#x exp_type %#x" % (experimenter, exp_type))
-
-def parse_experimenter_stats_reply(buf):
-    if len(buf) < 24:
-        raise loxi.ProtocolError("experimenter stats reply message too short")
-
-    experimenter, exp_type = struct.unpack_from("!LL", buf, 16)
-
-    if experimenter in experimenter_stats_reply_parsers and \
-            exp_type in experimenter_stats_reply_parsers[experimenter]:
-        return experimenter_stats_reply_parsers[experimenter][exp_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected stats reply experimenter %#x exp_type %#x" % (experimenter, exp_type))
-
-def parse_experimenter(buf):
-    if len(buf) < 16:
-        raise loxi.ProtocolError("experimenter message too short")
-
-    experimenter, = struct.unpack_from("!L", buf, 8)
-    if experimenter == 0x005c16c7: # Big Switch Networks
-        subtype, = struct.unpack_from("!L", buf, 12)
-    elif experimenter == 0x00002320: # Nicira
-        subtype, = struct.unpack_from("!L", buf, 12)
-    else:
-        raise loxi.ProtocolError("unexpected experimenter id %#x" % experimenter)
-
-    if subtype in experimenter_parsers[experimenter]:
-        return experimenter_parsers[experimenter][subtype](buf)
-    else:
-        raise loxi.ProtocolError("unexpected experimenter %#x subtype %#x" % (experimenter, subtype))
-
-parsers = {
-    const.OFPT_HELLO : hello.unpack,
-    const.OFPT_ERROR : parse_error,
-    const.OFPT_ECHO_REQUEST : echo_request.unpack,
-    const.OFPT_ECHO_REPLY : echo_reply.unpack,
-    const.OFPT_EXPERIMENTER : parse_experimenter,
-    const.OFPT_FEATURES_REQUEST : features_request.unpack,
-    const.OFPT_FEATURES_REPLY : features_reply.unpack,
-    const.OFPT_GET_CONFIG_REQUEST : get_config_request.unpack,
-    const.OFPT_GET_CONFIG_REPLY : get_config_reply.unpack,
-    const.OFPT_SET_CONFIG : set_config.unpack,
-    const.OFPT_PACKET_IN : packet_in.unpack,
-    const.OFPT_FLOW_REMOVED : flow_removed.unpack,
-    const.OFPT_PORT_STATUS : port_status.unpack,
-    const.OFPT_PACKET_OUT : packet_out.unpack,
-    const.OFPT_FLOW_MOD : parse_flow_mod,
-    const.OFPT_PORT_MOD : port_mod.unpack,
-    const.OFPT_STATS_REQUEST : parse_stats_request,
-    const.OFPT_STATS_REPLY : parse_stats_reply,
-    const.OFPT_BARRIER_REQUEST : barrier_request.unpack,
-    const.OFPT_BARRIER_REPLY : barrier_reply.unpack,
-    const.OFPT_QUEUE_GET_CONFIG_REQUEST : queue_get_config_request.unpack,
-    const.OFPT_QUEUE_GET_CONFIG_REPLY : queue_get_config_reply.unpack,
-    22 : table_mod.unpack,
-}
-
-error_msg_parsers = {
-    const.OFPET_HELLO_FAILED : hello_failed_error_msg.unpack,
-    const.OFPET_BAD_REQUEST : bad_request_error_msg.unpack,
-    const.OFPET_BAD_ACTION : bad_action_error_msg.unpack,
-    const.OFPET_FLOW_MOD_FAILED : flow_mod_failed_error_msg.unpack,
-    const.OFPET_PORT_MOD_FAILED : port_mod_failed_error_msg.unpack,
-    const.OFPET_QUEUE_OP_FAILED : queue_op_failed_error_msg.unpack,
-}
-
-flow_mod_parsers = {
-    const.OFPFC_ADD : flow_add.unpack,
-    const.OFPFC_MODIFY : flow_modify.unpack,
-    const.OFPFC_MODIFY_STRICT : flow_modify_strict.unpack,
-    const.OFPFC_DELETE : flow_delete.unpack,
-    const.OFPFC_DELETE_STRICT : flow_delete_strict.unpack,
-}
-
-
-stats_reply_parsers = {
-    const.OFPST_DESC : desc_stats_reply.unpack,
-    const.OFPST_FLOW : flow_stats_reply.unpack,
-    const.OFPST_AGGREGATE : aggregate_stats_reply.unpack,
-    const.OFPST_TABLE : table_stats_reply.unpack,
-    const.OFPST_PORT : port_stats_reply.unpack,
-    const.OFPST_QUEUE : queue_stats_reply.unpack,
-    const.OFPST_EXPERIMENTER : parse_experimenter_stats_reply,
-}
-
-stats_request_parsers = {
-    const.OFPST_DESC : desc_stats_request.unpack,
-    const.OFPST_FLOW : flow_stats_request.unpack,
-    const.OFPST_AGGREGATE : aggregate_stats_request.unpack,
-    const.OFPST_TABLE : table_stats_request.unpack,
-    const.OFPST_PORT : port_stats_request.unpack,
-    const.OFPST_QUEUE : queue_stats_request.unpack,
-    const.OFPST_EXPERIMENTER : parse_experimenter_stats_request,
-}
-
-experimenter_parsers = {
-    8992 : {
-        11: nicira_controller_role_reply.unpack,
-        10: nicira_controller_role_request.unpack,
-    },
-    6035143 : {
-        22: bsn_bw_clear_data_reply.unpack,
-        21: bsn_bw_clear_data_request.unpack,
-        20: bsn_bw_enable_get_reply.unpack,
-        19: bsn_bw_enable_get_request.unpack,
-        23: bsn_bw_enable_set_reply.unpack,
-        18: bsn_bw_enable_set_request.unpack,
-        10: bsn_get_interfaces_reply.unpack,
-        9: bsn_get_interfaces_request.unpack,
-        2: bsn_get_ip_mask_reply.unpack,
-        1: bsn_get_ip_mask_request.unpack,
-        14: bsn_get_l2_table_reply.unpack,
-        13: bsn_get_l2_table_request.unpack,
-        5: bsn_get_mirroring_reply.unpack,
-        4: bsn_get_mirroring_request.unpack,
-        28: bsn_hybrid_get_reply.unpack,
-        27: bsn_hybrid_get_request.unpack,
-        34: bsn_pdu_rx_reply.unpack,
-        33: bsn_pdu_rx_request.unpack,
-        35: bsn_pdu_rx_timeout.unpack,
-        32: bsn_pdu_tx_reply.unpack,
-        31: bsn_pdu_tx_request.unpack,
-        0: bsn_set_ip_mask.unpack,
-        24: bsn_set_l2_table_reply.unpack,
-        12: bsn_set_l2_table_request.unpack,
-        3: bsn_set_mirroring.unpack,
-        25: bsn_set_pktin_suppression_reply.unpack,
-        11: bsn_set_pktin_suppression_request.unpack,
-        6: bsn_shell_command.unpack,
-        7: bsn_shell_output.unpack,
-        8: bsn_shell_status.unpack,
-        16: bsn_virtual_port_create_reply.unpack,
-        15: bsn_virtual_port_create_request.unpack,
-        26: bsn_virtual_port_remove_reply.unpack,
-        17: bsn_virtual_port_remove_request.unpack,
-    },
-}
-
-experimenter_stats_request_parsers = {
-    0x005c16c7: {
-    },
-}
-
-experimenter_stats_reply_parsers = {
-    0x005c16c7: {
-    },
-}
+    return message.unpack(loxi.generic_util.OFReader(buf))
diff --git a/src/python/loxi/of10/util.py b/src/python/loxi/of10/util.py
index 7997e38..a9b395f 100644
--- a/src/python/loxi/of10/util.py
+++ b/src/python/loxi/of10/util.py
@@ -5,9 +5,11 @@
 # Automatically generated by LOXI from template util.py
 # Do not modify
 
+import struct
 import loxi
 import const
-import struct
+import common
+import action
 
 def pretty_mac(mac):
     return ':'.join(["%02x" % x for x in mac])
@@ -74,9 +76,6 @@
 def unpack_match_bmap(reader):
     return reader.read("!L")[0]
 
-def pack_list(values):
-    return "".join([x.pack() for x in values])
-
 MASK64 = (1 << 64) - 1
 
 def pack_bitmap_128(value):
@@ -96,3 +95,13 @@
         i += 1
         x >>= 1
     return value
+
+def unpack_list_hello_elem(reader):
+    def deserializer(reader):
+        typ, length, = reader.peek('!HH')
+        reader = reader.slice(length)
+        try:
+            return common.hello_elem.unpack(reader)
+        except loxi.ProtocolError:
+            return None
+    return [x for x in loxi.generic_util.unpack_list(reader, deserializer) if x != None]
diff --git a/src/python/loxi/of11/action.py b/src/python/loxi/of11/action.py
index 644319d..06f6695 100644
--- a/src/python/loxi/of11/action.py
+++ b/src/python/loxi/of11/action.py
@@ -3,27 +3,60 @@
 # 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 action.py
+# Automatically generated by LOXI from template module.py
 # Do not modify
 
 import struct
+import loxi
 import const
+import common
+import action
+import instruction
 import util
 import loxi.generic_util
-import loxi
 
-def unpack_list(reader):
-    def deserializer(reader, typ):
-        parser = parsers.get(typ)
-        if not parser: raise loxi.ProtocolError("unknown action type %d" % typ)
-        return parser(reader)
-    return loxi.generic_util.unpack_list_tlv16(reader, deserializer)
+class action(loxi.OFObject):
+    subtypes = {}
 
-class Action(object):
-    type = None # override in subclass
-    pass
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 0)
+        try:
+            subclass = action.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown action subtype %#x" % subtype)
+        return subclass.unpack(reader)
 
-class bsn_mirror(Action):
+
+class experimenter(action):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 4)
+        try:
+            subclass = experimenter.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter action subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+action.subtypes[65535] = experimenter
+
+class bsn(experimenter):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 8)
+        try:
+            subclass = bsn.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown bsn experimenter action subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter.subtypes[6035143] = bsn
+
+class bsn_mirror(bsn):
     type = 65535
     experimenter = 6035143
     subtype = 1
@@ -58,15 +91,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_mirror()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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]
@@ -84,13 +115,6 @@
         if self.copy_stage != other.copy_stage: 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_mirror {")
         with q.group():
@@ -107,7 +131,9 @@
             q.breakable()
         q.text('}')
 
-class bsn_set_tunnel_dst(Action):
+bsn.subtypes[1] = bsn_mirror
+
+class bsn_set_tunnel_dst(bsn):
     type = 65535
     experimenter = 6035143
     subtype = 2
@@ -131,15 +157,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_set_tunnel_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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]
@@ -152,13 +176,6 @@
         if self.dst != other.dst: 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_set_tunnel_dst {")
         with q.group():
@@ -169,7 +186,9 @@
             q.breakable()
         q.text('}')
 
-class copy_ttl_in(Action):
+bsn.subtypes[2] = bsn_set_tunnel_dst
+
+class copy_ttl_in(action):
     type = 12
 
     def __init__(self):
@@ -185,15 +204,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = copy_ttl_in()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 12)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         return obj
 
@@ -201,13 +218,6 @@
         if type(self) != type(other): 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("copy_ttl_in {")
         with q.group():
@@ -216,7 +226,9 @@
             q.breakable()
         q.text('}')
 
-class copy_ttl_out(Action):
+action.subtypes[12] = copy_ttl_in
+
+class copy_ttl_out(action):
     type = 11
 
     def __init__(self):
@@ -232,15 +244,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = copy_ttl_out()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 11)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         return obj
 
@@ -248,13 +258,6 @@
         if type(self) != type(other): 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("copy_ttl_out {")
         with q.group():
@@ -263,7 +266,9 @@
             q.breakable()
         q.text('}')
 
-class dec_mpls_ttl(Action):
+action.subtypes[11] = copy_ttl_out
+
+class dec_mpls_ttl(action):
     type = 16
 
     def __init__(self):
@@ -279,15 +284,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = dec_mpls_ttl()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 16)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         return obj
 
@@ -295,13 +298,6 @@
         if type(self) != type(other): 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("dec_mpls_ttl {")
         with q.group():
@@ -310,7 +306,9 @@
             q.breakable()
         q.text('}')
 
-class dec_nw_ttl(Action):
+action.subtypes[16] = dec_mpls_ttl
+
+class dec_nw_ttl(action):
     type = 24
 
     def __init__(self):
@@ -326,15 +324,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = dec_nw_ttl()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 24)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         return obj
 
@@ -342,13 +338,6 @@
         if type(self) != type(other): 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("dec_nw_ttl {")
         with q.group():
@@ -357,7 +346,9 @@
             q.breakable()
         q.text('}')
 
-class group(Action):
+action.subtypes[24] = dec_nw_ttl
+
+class group(action):
     type = 22
 
     def __init__(self, group_id=None):
@@ -377,15 +368,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = group()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 22)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.group_id = reader.read("!L")[0]
         return obj
 
@@ -394,13 +383,6 @@
         if self.group_id != other.group_id: 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 {")
         with q.group():
@@ -411,7 +393,23 @@
             q.breakable()
         q.text('}')
 
-class nicira_dec_ttl(Action):
+action.subtypes[22] = group
+
+class nicira(experimenter):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 8)
+        try:
+            subclass = nicira.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown nicira experimenter action subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter.subtypes[8992] = nicira
+
+class nicira_dec_ttl(nicira):
     type = 65535
     experimenter = 8992
     subtype = 18
@@ -432,15 +430,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = nicira_dec_ttl()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 8992)
         _subtype = reader.read("!H")[0]
@@ -453,13 +449,6 @@
         if type(self) != type(other): 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("nicira_dec_ttl {")
         with q.group():
@@ -468,7 +457,9 @@
             q.breakable()
         q.text('}')
 
-class output(Action):
+nicira.subtypes[18] = nicira_dec_ttl
+
+class output(action):
     type = 0
 
     def __init__(self, port=None, max_len=None):
@@ -494,15 +485,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = output()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 0)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.port = util.unpack_port_no(reader)
         obj.max_len = reader.read("!H")[0]
         reader.skip(6)
@@ -514,13 +503,6 @@
         if self.max_len != other.max_len: 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("output {")
         with q.group():
@@ -534,7 +516,9 @@
             q.breakable()
         q.text('}')
 
-class pop_mpls(Action):
+action.subtypes[0] = output
+
+class pop_mpls(action):
     type = 20
 
     def __init__(self, ethertype=None):
@@ -555,15 +539,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = pop_mpls()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 20)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.ethertype = reader.read("!H")[0]
         reader.skip(2)
         return obj
@@ -573,13 +555,6 @@
         if self.ethertype != other.ethertype: 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("pop_mpls {")
         with q.group():
@@ -590,7 +565,9 @@
             q.breakable()
         q.text('}')
 
-class pop_vlan(Action):
+action.subtypes[20] = pop_mpls
+
+class pop_vlan(action):
     type = 18
 
     def __init__(self):
@@ -606,15 +583,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = pop_vlan()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 18)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         return obj
 
@@ -622,13 +597,6 @@
         if type(self) != type(other): 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("pop_vlan {")
         with q.group():
@@ -637,7 +605,9 @@
             q.breakable()
         q.text('}')
 
-class push_mpls(Action):
+action.subtypes[18] = pop_vlan
+
+class push_mpls(action):
     type = 19
 
     def __init__(self, ethertype=None):
@@ -658,15 +628,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = push_mpls()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 19)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.ethertype = reader.read("!H")[0]
         reader.skip(2)
         return obj
@@ -676,13 +644,6 @@
         if self.ethertype != other.ethertype: 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("push_mpls {")
         with q.group():
@@ -693,7 +654,9 @@
             q.breakable()
         q.text('}')
 
-class push_vlan(Action):
+action.subtypes[19] = push_mpls
+
+class push_vlan(action):
     type = 17
 
     def __init__(self, ethertype=None):
@@ -714,15 +677,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = push_vlan()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 17)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.ethertype = reader.read("!H")[0]
         reader.skip(2)
         return obj
@@ -732,13 +693,6 @@
         if self.ethertype != other.ethertype: 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("push_vlan {")
         with q.group():
@@ -749,7 +703,9 @@
             q.breakable()
         q.text('}')
 
-class set_dl_dst(Action):
+action.subtypes[17] = push_vlan
+
+class set_dl_dst(action):
     type = 4
 
     def __init__(self, dl_addr=None):
@@ -770,15 +726,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_dl_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 4)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.dl_addr = list(reader.read('!6B'))
         reader.skip(6)
         return obj
@@ -788,13 +742,6 @@
         if self.dl_addr != other.dl_addr: 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("set_dl_dst {")
         with q.group():
@@ -805,7 +752,9 @@
             q.breakable()
         q.text('}')
 
-class set_dl_src(Action):
+action.subtypes[4] = set_dl_dst
+
+class set_dl_src(action):
     type = 3
 
     def __init__(self, dl_addr=None):
@@ -826,15 +775,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_dl_src()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 3)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.dl_addr = list(reader.read('!6B'))
         reader.skip(6)
         return obj
@@ -844,13 +791,6 @@
         if self.dl_addr != other.dl_addr: 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("set_dl_src {")
         with q.group():
@@ -861,7 +801,9 @@
             q.breakable()
         q.text('}')
 
-class set_mpls_label(Action):
+action.subtypes[3] = set_dl_src
+
+class set_mpls_label(action):
     type = 13
 
     def __init__(self, mpls_label=None):
@@ -881,15 +823,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_mpls_label()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 13)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.mpls_label = reader.read("!L")[0]
         return obj
 
@@ -898,13 +838,6 @@
         if self.mpls_label != other.mpls_label: 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("set_mpls_label {")
         with q.group():
@@ -915,7 +848,9 @@
             q.breakable()
         q.text('}')
 
-class set_mpls_tc(Action):
+action.subtypes[13] = set_mpls_label
+
+class set_mpls_tc(action):
     type = 14
 
     def __init__(self, mpls_tc=None):
@@ -936,15 +871,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_mpls_tc()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 14)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.mpls_tc = reader.read("!B")[0]
         reader.skip(3)
         return obj
@@ -954,13 +887,6 @@
         if self.mpls_tc != other.mpls_tc: 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("set_mpls_tc {")
         with q.group():
@@ -971,7 +897,9 @@
             q.breakable()
         q.text('}')
 
-class set_mpls_ttl(Action):
+action.subtypes[14] = set_mpls_tc
+
+class set_mpls_ttl(action):
     type = 15
 
     def __init__(self, mpls_ttl=None):
@@ -992,15 +920,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_mpls_ttl()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 15)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.mpls_ttl = reader.read("!B")[0]
         reader.skip(3)
         return obj
@@ -1010,13 +936,6 @@
         if self.mpls_ttl != other.mpls_ttl: 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("set_mpls_ttl {")
         with q.group():
@@ -1027,7 +946,9 @@
             q.breakable()
         q.text('}')
 
-class set_nw_dst(Action):
+action.subtypes[15] = set_mpls_ttl
+
+class set_nw_dst(action):
     type = 6
 
     def __init__(self, nw_addr=None):
@@ -1047,15 +968,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_nw_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 6)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.nw_addr = reader.read("!L")[0]
         return obj
 
@@ -1064,13 +983,6 @@
         if self.nw_addr != other.nw_addr: 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("set_nw_dst {")
         with q.group():
@@ -1081,7 +993,9 @@
             q.breakable()
         q.text('}')
 
-class set_nw_ecn(Action):
+action.subtypes[6] = set_nw_dst
+
+class set_nw_ecn(action):
     type = 8
 
     def __init__(self, nw_ecn=None):
@@ -1102,15 +1016,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_nw_ecn()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 8)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.nw_ecn = reader.read("!B")[0]
         reader.skip(3)
         return obj
@@ -1120,13 +1032,6 @@
         if self.nw_ecn != other.nw_ecn: 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("set_nw_ecn {")
         with q.group():
@@ -1137,7 +1042,9 @@
             q.breakable()
         q.text('}')
 
-class set_nw_src(Action):
+action.subtypes[8] = set_nw_ecn
+
+class set_nw_src(action):
     type = 5
 
     def __init__(self, nw_addr=None):
@@ -1157,15 +1064,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_nw_src()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 5)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.nw_addr = reader.read("!L")[0]
         return obj
 
@@ -1174,13 +1079,6 @@
         if self.nw_addr != other.nw_addr: 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("set_nw_src {")
         with q.group():
@@ -1191,7 +1089,9 @@
             q.breakable()
         q.text('}')
 
-class set_nw_tos(Action):
+action.subtypes[5] = set_nw_src
+
+class set_nw_tos(action):
     type = 7
 
     def __init__(self, nw_tos=None):
@@ -1212,15 +1112,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_nw_tos()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 7)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.nw_tos = reader.read("!B")[0]
         reader.skip(3)
         return obj
@@ -1230,13 +1128,6 @@
         if self.nw_tos != other.nw_tos: 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("set_nw_tos {")
         with q.group():
@@ -1247,7 +1138,9 @@
             q.breakable()
         q.text('}')
 
-class set_nw_ttl(Action):
+action.subtypes[7] = set_nw_tos
+
+class set_nw_ttl(action):
     type = 23
 
     def __init__(self, nw_ttl=None):
@@ -1268,15 +1161,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_nw_ttl()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 23)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.nw_ttl = reader.read("!B")[0]
         reader.skip(3)
         return obj
@@ -1286,13 +1177,6 @@
         if self.nw_ttl != other.nw_ttl: 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("set_nw_ttl {")
         with q.group():
@@ -1303,7 +1187,9 @@
             q.breakable()
         q.text('}')
 
-class set_queue(Action):
+action.subtypes[23] = set_nw_ttl
+
+class set_queue(action):
     type = 21
 
     def __init__(self, queue_id=None):
@@ -1323,15 +1209,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_queue()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 21)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.queue_id = reader.read("!L")[0]
         return obj
 
@@ -1340,13 +1224,6 @@
         if self.queue_id != other.queue_id: 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("set_queue {")
         with q.group():
@@ -1357,7 +1234,9 @@
             q.breakable()
         q.text('}')
 
-class set_tp_dst(Action):
+action.subtypes[21] = set_queue
+
+class set_tp_dst(action):
     type = 10
 
     def __init__(self, tp_port=None):
@@ -1378,15 +1257,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_tp_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 10)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.tp_port = reader.read("!H")[0]
         reader.skip(2)
         return obj
@@ -1396,13 +1273,6 @@
         if self.tp_port != other.tp_port: 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("set_tp_dst {")
         with q.group():
@@ -1413,7 +1283,9 @@
             q.breakable()
         q.text('}')
 
-class set_tp_src(Action):
+action.subtypes[10] = set_tp_dst
+
+class set_tp_src(action):
     type = 9
 
     def __init__(self, tp_port=None):
@@ -1434,15 +1306,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_tp_src()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 9)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.tp_port = reader.read("!H")[0]
         reader.skip(2)
         return obj
@@ -1452,13 +1322,6 @@
         if self.tp_port != other.tp_port: 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("set_tp_src {")
         with q.group():
@@ -1469,7 +1332,9 @@
             q.breakable()
         q.text('}')
 
-class set_vlan_pcp(Action):
+action.subtypes[9] = set_tp_src
+
+class set_vlan_pcp(action):
     type = 2
 
     def __init__(self, vlan_pcp=None):
@@ -1490,15 +1355,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_vlan_pcp()
-        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))
         obj.vlan_pcp = reader.read("!B")[0]
         reader.skip(3)
         return obj
@@ -1508,13 +1371,6 @@
         if self.vlan_pcp != other.vlan_pcp: 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("set_vlan_pcp {")
         with q.group():
@@ -1525,7 +1381,9 @@
             q.breakable()
         q.text('}')
 
-class set_vlan_vid(Action):
+action.subtypes[2] = set_vlan_pcp
+
+class set_vlan_vid(action):
     type = 1
 
     def __init__(self, vlan_vid=None):
@@ -1546,15 +1404,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_vlan_vid()
-        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))
         obj.vlan_vid = reader.read("!H")[0]
         reader.skip(2)
         return obj
@@ -1564,13 +1420,6 @@
         if self.vlan_vid != other.vlan_vid: 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("set_vlan_vid {")
         with q.group():
@@ -1581,56 +1430,6 @@
             q.breakable()
         q.text('}')
 
+action.subtypes[1] = set_vlan_vid
 
-def parse_experimenter(reader):
-    experimenter, = reader.peek("!4xL")
-    if experimenter == 0x005c16c7: # Big Switch Networks
-        subtype, = reader.peek("!8xL")
-    elif experimenter == 0x00002320: # Nicira
-        subtype, = reader.peek("!8xH")
-    else:
-        raise loxi.ProtocolError("unexpected experimenter id %#x" % experimenter)
 
-    if subtype in experimenter_parsers[experimenter]:
-        return experimenter_parsers[experimenter][subtype](reader)
-    else:
-        raise loxi.ProtocolError("unexpected BSN experimenter subtype %#x" % subtype)
-
-parsers = {
-    const.OFPAT_OUTPUT : output.unpack,
-    const.OFPAT_SET_VLAN_VID : set_vlan_vid.unpack,
-    const.OFPAT_SET_VLAN_PCP : set_vlan_pcp.unpack,
-    const.OFPAT_SET_DL_SRC : set_dl_src.unpack,
-    const.OFPAT_SET_DL_DST : set_dl_dst.unpack,
-    const.OFPAT_SET_NW_SRC : set_nw_src.unpack,
-    const.OFPAT_SET_NW_DST : set_nw_dst.unpack,
-    const.OFPAT_SET_NW_TOS : set_nw_tos.unpack,
-    const.OFPAT_SET_NW_ECN : set_nw_ecn.unpack,
-    const.OFPAT_SET_TP_SRC : set_tp_src.unpack,
-    const.OFPAT_SET_TP_DST : set_tp_dst.unpack,
-    const.OFPAT_COPY_TTL_OUT : copy_ttl_out.unpack,
-    const.OFPAT_COPY_TTL_IN : copy_ttl_in.unpack,
-    const.OFPAT_SET_MPLS_LABEL : set_mpls_label.unpack,
-    const.OFPAT_SET_MPLS_TC : set_mpls_tc.unpack,
-    const.OFPAT_SET_MPLS_TTL : set_mpls_ttl.unpack,
-    const.OFPAT_DEC_MPLS_TTL : dec_mpls_ttl.unpack,
-    const.OFPAT_PUSH_VLAN : push_vlan.unpack,
-    const.OFPAT_POP_VLAN : pop_vlan.unpack,
-    const.OFPAT_PUSH_MPLS : push_mpls.unpack,
-    const.OFPAT_POP_MPLS : pop_mpls.unpack,
-    const.OFPAT_SET_QUEUE : set_queue.unpack,
-    const.OFPAT_GROUP : group.unpack,
-    const.OFPAT_SET_NW_TTL : set_nw_ttl.unpack,
-    const.OFPAT_DEC_NW_TTL : dec_nw_ttl.unpack,
-    const.OFPAT_EXPERIMENTER : parse_experimenter,
-}
-
-experimenter_parsers = {
-    8992 : {
-        18: nicira_dec_ttl.unpack,
-    },
-    6035143 : {
-        1: bsn_mirror.unpack,
-        2: bsn_set_tunnel_dst.unpack,
-    },
-}
diff --git a/src/python/loxi/of11/common.py b/src/python/loxi/of11/common.py
index 868f86d..548edfd 100644
--- a/src/python/loxi/of11/common.py
+++ b/src/python/loxi/of11/common.py
@@ -2,62 +2,20 @@
 # 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 loxi
 import const
+import common
+import action
+import instruction
 import util
 import loxi.generic_util
 
-
-# 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 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:
@@ -88,12 +46,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")
@@ -109,13 +63,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():
@@ -135,7 +82,21 @@
             q.breakable()
         q.text('}')
 
-class bsn_vport_q_in_q(object):
+
+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):
@@ -180,15 +141,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]
@@ -207,13 +166,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():
@@ -239,7 +191,9 @@
             q.breakable()
         q.text('}')
 
-class bucket(object):
+bsn_vport.subtypes[0] = bsn_vport_q_in_q
+
+class bucket(loxi.OFObject):
 
     def __init__(self, weight=None, watch_port=None, watch_group=None, actions=None):
         if weight != None:
@@ -267,24 +221,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):
@@ -295,13 +247,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():
@@ -321,7 +266,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:
@@ -341,12 +287,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
@@ -357,13 +299,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():
@@ -377,7 +312,8 @@
             q.breakable()
         q.text('}')
 
-class flow_stats_entry(object):
+
+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, cookie=None, packet_count=None, byte_count=None, match=None, instructions=None):
         if table_id != None:
@@ -441,19 +377,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]
@@ -466,7 +400,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):
@@ -484,13 +418,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():
@@ -531,7 +458,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:
@@ -554,23 +482,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):
@@ -580,13 +506,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():
@@ -603,7 +522,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, bucket_stats=None):
         if group_id != None:
@@ -637,19 +557,17 @@
         packed.append('\x00' * 4)
         packed.append(struct.pack("!Q", self.packet_count))
         packed.append(struct.pack("!Q", self.byte_count))
-        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]
@@ -668,13 +586,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():
@@ -697,7 +608,8 @@
             q.breakable()
         q.text('}')
 
-class match_v2(object):
+
+class match_v2(loxi.OFObject):
     type = 0
 
     def __init__(self, in_port=None, wildcards=None, eth_src=None, eth_src_mask=None, eth_dst=None, eth_dst_mask=None, vlan_vid=None, vlan_pcp=None, eth_type=None, ip_dscp=None, ip_proto=None, ipv4_src=None, ipv4_src_mask=None, ipv4_dst=None, ipv4_dst_mask=None, tcp_src=None, tcp_dst=None, mpls_label=None, mpls_tc=None, metadata=None, metadata_mask=None):
@@ -819,15 +731,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = match_v2()
-        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.in_port = util.unpack_port_no(reader)
         obj.wildcards = util.unpack_wc_bmap(reader)
         obj.eth_src = list(reader.read('!6B'))
@@ -878,13 +788,6 @@
         if self.metadata_mask != other.metadata_mask: 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_v2 {")
         with q.group():
@@ -955,7 +858,8 @@
             q.breakable()
         q.text('}')
 
-class packet_queue(object):
+
+class packet_queue(loxi.OFObject):
 
     def __init__(self, queue_id=None, properties=None):
         if queue_id != None:
@@ -973,22 +877,20 @@
         packed.append(struct.pack("!L", self.queue_id))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
         packed.append('\x00' * 2)
-        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[1] = 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]
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (4 + 2))
         reader.skip(2)
-        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):
@@ -997,13 +899,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():
@@ -1017,7 +912,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:
@@ -1084,12 +980,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'))
@@ -1120,13 +1012,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():
@@ -1167,7 +1052,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):
         if port_no != None:
@@ -1243,12 +1129,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]
@@ -1282,13 +1164,6 @@
         if self.collisions != other.collisions: 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():
@@ -1335,7 +1210,21 @@
             q.breakable()
         q.text('}')
 
-class queue_prop_min_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_min_rate(queue_prop):
     type = 1
 
     def __init__(self, rate=None):
@@ -1357,15 +1246,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)
@@ -1376,13 +1263,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():
@@ -1393,7 +1273,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):
         if port_no != None:
@@ -1428,12 +1310,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]
@@ -1450,13 +1328,6 @@
         if self.tx_errors != other.tx_errors: 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():
@@ -1479,7 +1350,8 @@
             q.breakable()
         q.text('}')
 
-class table_stats_entry(object):
+
+class table_stats_entry(loxi.OFObject):
 
     def __init__(self, table_id=None, name=None, wildcards=None, match=None, instructions=None, write_actions=None, apply_actions=None, config=None, max_entries=None, active_count=None, lookup_count=None, matched_count=None):
         if table_id != None:
@@ -1550,12 +1422,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(7)
         obj.name = reader.read("!32s")[0].rstrip("\x00")
@@ -1587,13 +1455,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():
@@ -1638,4 +1499,5 @@
         q.text('}')
 
 
+
 match = match_v2
diff --git a/src/python/loxi/of11/instruction.py b/src/python/loxi/of11/instruction.py
index 38bcdb6..e93e070 100644
--- a/src/python/loxi/of11/instruction.py
+++ b/src/python/loxi/of11/instruction.py
@@ -3,28 +3,32 @@
 # 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 instruction.py
+# Automatically generated by LOXI from template module.py
 # Do not modify
 
 import struct
-import action
+import loxi
 import const
+import common
+import action
+import instruction
 import util
 import loxi.generic_util
-import loxi
 
-def unpack_list(reader):
-    def deserializer(reader, typ):
-        parser = parsers.get(typ)
-        if not parser: raise loxi.ProtocolError("unknown instruction type %d" % typ)
-        return parser(reader)
-    return loxi.generic_util.unpack_list_tlv16(reader, deserializer)
+class instruction(loxi.OFObject):
+    subtypes = {}
 
-class Instruction(object):
-    type = None # override in subclass
-    pass
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 0)
+        try:
+            subclass = instruction.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown instruction subtype %#x" % subtype)
+        return subclass.unpack(reader)
 
-class apply_actions(Instruction):
+
+class apply_actions(instruction):
     type = 4
 
     def __init__(self, actions=None):
@@ -39,23 +43,21 @@
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
         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[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = 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 == 4)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         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):
@@ -63,13 +65,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("apply_actions {")
         with q.group():
@@ -80,7 +75,9 @@
             q.breakable()
         q.text('}')
 
-class clear_actions(Instruction):
+instruction.subtypes[4] = apply_actions
+
+class clear_actions(instruction):
     type = 5
 
     def __init__(self):
@@ -96,15 +93,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = clear_actions()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 5)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         return obj
 
@@ -112,13 +107,6 @@
         if type(self) != type(other): 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("clear_actions {")
         with q.group():
@@ -127,7 +115,23 @@
             q.breakable()
         q.text('}')
 
-class goto_table(Instruction):
+instruction.subtypes[5] = clear_actions
+
+class experimenter(instruction):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 4)
+        try:
+            subclass = experimenter.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter instruction subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+instruction.subtypes[65535] = experimenter
+
+class goto_table(instruction):
     type = 1
 
     def __init__(self, table_id=None):
@@ -148,15 +152,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = goto_table()
-        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))
         obj.table_id = reader.read("!B")[0]
         reader.skip(3)
         return obj
@@ -166,13 +168,6 @@
         if self.table_id != other.table_id: 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("goto_table {")
         with q.group():
@@ -183,7 +178,9 @@
             q.breakable()
         q.text('}')
 
-class write_actions(Instruction):
+instruction.subtypes[1] = goto_table
+
+class write_actions(instruction):
     type = 3
 
     def __init__(self, actions=None):
@@ -198,23 +195,21 @@
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
         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[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = 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 == 3)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         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):
@@ -222,13 +217,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("write_actions {")
         with q.group():
@@ -239,7 +227,9 @@
             q.breakable()
         q.text('}')
 
-class write_metadata(Instruction):
+instruction.subtypes[3] = write_actions
+
+class write_metadata(instruction):
     type = 2
 
     def __init__(self, metadata=None, metadata_mask=None):
@@ -265,15 +255,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = write_metadata()
-        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.metadata = reader.read("!Q")[0]
         obj.metadata_mask = reader.read("!Q")[0]
@@ -285,13 +273,6 @@
         if self.metadata_mask != other.metadata_mask: 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("write_metadata {")
         with q.group():
@@ -305,26 +286,6 @@
             q.breakable()
         q.text('}')
 
+instruction.subtypes[2] = write_metadata
 
-def parse_experimenter(reader):
-    experimenter, = reader.peek("!4xL")
-    if experimenter == 0x005c16c7: # Big Switch Networks
-        subtype, = reader.peek("!8xL")
-    else:
-        raise loxi.ProtocolError("unexpected experimenter id %#x" % experimenter)
 
-    if subtype in experimenter_parsers[experimenter]:
-        return experimenter_parsers[experimenter][subtype](reader)
-    else:
-        raise loxi.ProtocolError("unexpected experimenter id %#x subtype %#x" % (experimenter, subtype))
-
-parsers = {
-    const.OFPIT_GOTO_TABLE : goto_table.unpack,
-    const.OFPIT_WRITE_METADATA : write_metadata.unpack,
-    const.OFPIT_WRITE_ACTIONS : write_actions.unpack,
-    const.OFPIT_APPLY_ACTIONS : apply_actions.unpack,
-    const.OFPIT_CLEAR_ACTIONS : clear_actions.unpack,
-}
-
-experimenter_parsers = {
-}
diff --git a/src/python/loxi/of11/message.py b/src/python/loxi/of11/message.py
index 0566f03..7e2b111 100644
--- a/src/python/loxi/of11/message.py
+++ b/src/python/loxi/of11/message.py
@@ -3,30 +3,55 @@
 # 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 message.py
+# Automatically generated by LOXI from template module.py
 # Do not modify
 
 import struct
 import loxi
 import const
 import common
-import action # for unpack_list
-import instruction # for unpack_list
+import action
+import instruction
 import util
 import loxi.generic_util
 
-class Message(object):
-    version = const.OFP_VERSION
-    type = None # override in subclass
-    xid = None
+class message(loxi.OFObject):
+    subtypes = {}
 
-class aggregate_stats_reply(Message):
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('B', 1)
+        try:
+            subclass = message.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+
+class stats_reply(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 8)
+        try:
+            subclass = stats_reply.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown stats_reply message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[19] = stats_reply
+
+class aggregate_stats_reply(stats_reply):
     version = 2
     type = 19
     stats_type = 2
 
     def __init__(self, xid=None, flags=None, packet_count=None, byte_count=None, flow_count=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -43,6 +68,7 @@
             self.flow_count = flow_count
         else:
             self.flow_count = 0
+        return
 
     def pack(self):
         packed = []
@@ -62,18 +88,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = aggregate_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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 == 2)
@@ -87,8 +110,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.packet_count != other.packet_count: return False
@@ -96,16 +117,6 @@
         if self.flow_count != other.flow_count: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("aggregate_stats_reply {")
         with q.group():
@@ -131,13 +142,32 @@
             q.breakable()
         q.text('}')
 
-class aggregate_stats_request(Message):
+stats_reply.subtypes[2] = aggregate_stats_reply
+
+class stats_request(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 8)
+        try:
+            subclass = stats_request.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown stats_request message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[18] = stats_request
+
+class aggregate_stats_request(stats_request):
     version = 2
     type = 18
     stats_type = 2
 
     def __init__(self, xid=None, flags=None, table_id=None, out_port=None, out_group=None, cookie=None, cookie_mask=None, match=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -166,6 +196,7 @@
             self.match = match
         else:
             self.match = common.match()
+        return
 
     def pack(self):
         packed = []
@@ -189,18 +220,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = aggregate_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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 == 2)
@@ -218,8 +246,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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
@@ -230,16 +256,6 @@
         if self.match != other.match: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("aggregate_stats_request {")
         with q.group():
@@ -274,13 +290,32 @@
             q.breakable()
         q.text('}')
 
-class bad_action_error_msg(Message):
+stats_request.subtypes[2] = aggregate_stats_request
+
+class error_msg(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 8)
+        try:
+            subclass = error_msg.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown error_msg message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[1] = error_msg
+
+class bad_action_error_msg(error_msg):
     version = 2
     type = 1
     err_type = 2
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -289,6 +324,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -304,18 +340,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bad_action_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 2)
@@ -325,23 +358,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bad_action_error_msg {")
         with q.group():
@@ -361,13 +382,18 @@
             q.breakable()
         q.text('}')
 
-class bad_instruction_error_msg(Message):
+error_msg.subtypes[2] = bad_action_error_msg
+
+class bad_instruction_error_msg(error_msg):
     version = 2
     type = 1
     err_type = 3
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -376,6 +402,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -391,18 +418,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bad_instruction_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 3)
@@ -412,23 +436,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bad_instruction_error_msg {")
         with q.group():
@@ -448,13 +460,18 @@
             q.breakable()
         q.text('}')
 
-class bad_match_error_msg(Message):
+error_msg.subtypes[3] = bad_instruction_error_msg
+
+class bad_match_error_msg(error_msg):
     version = 2
     type = 1
     err_type = 4
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -463,6 +480,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -478,18 +496,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bad_match_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 4)
@@ -499,23 +514,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bad_match_error_msg {")
         with q.group():
@@ -535,13 +538,18 @@
             q.breakable()
         q.text('}')
 
-class bad_request_error_msg(Message):
+error_msg.subtypes[4] = bad_match_error_msg
+
+class bad_request_error_msg(error_msg):
     version = 2
     type = 1
     err_type = 1
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -550,6 +558,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -565,18 +574,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bad_request_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 1)
@@ -586,23 +592,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bad_request_error_msg {")
         with q.group():
@@ -622,12 +616,18 @@
             q.breakable()
         q.text('}')
 
-class barrier_reply(Message):
+error_msg.subtypes[1] = bad_request_error_msg
+
+class barrier_reply(message):
     version = 2
     type = 21
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -640,38 +640,23 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = barrier_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 21)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("barrier_reply {")
         with q.group():
@@ -685,12 +670,18 @@
             q.breakable()
         q.text('}')
 
-class barrier_request(Message):
+message.subtypes[21] = barrier_reply
+
+class barrier_request(message):
     version = 2
     type = 20
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -703,38 +694,23 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = barrier_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 20)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("barrier_request {")
         with q.group():
@@ -748,18 +724,52 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_clear_data_reply(Message):
+message.subtypes[20] = barrier_request
+
+class experimenter(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 8)
+        try:
+            subclass = experimenter.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[4] = experimenter
+
+class bsn_header(experimenter):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 12)
+        try:
+            subclass = bsn_header.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown bsn_header experimenter message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter.subtypes[6035143] = bsn_header
+
+class bsn_bw_clear_data_reply(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 22
 
     def __init__(self, xid=None, status=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
             self.status = 0
+        return
 
     def pack(self):
         packed = []
@@ -775,18 +785,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_clear_data_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -797,22 +804,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_clear_data_reply {")
         with q.group():
@@ -829,14 +824,20 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_clear_data_request(Message):
+bsn_header.subtypes[22] = bsn_bw_clear_data_reply
+
+class bsn_bw_clear_data_request(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 21
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -851,18 +852,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_clear_data_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -872,21 +870,9 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_clear_data_request {")
         with q.group():
@@ -900,18 +886,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_enable_get_reply(Message):
+bsn_header.subtypes[21] = bsn_bw_clear_data_request
+
+class bsn_bw_enable_get_reply(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 20
 
     def __init__(self, xid=None, enabled=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if enabled != None:
             self.enabled = enabled
         else:
             self.enabled = 0
+        return
 
     def pack(self):
         packed = []
@@ -927,18 +919,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_enable_get_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -949,22 +938,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.enabled != other.enabled: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_enable_get_reply {")
         with q.group():
@@ -981,14 +958,20 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_enable_get_request(Message):
+bsn_header.subtypes[20] = bsn_bw_enable_get_reply
+
+class bsn_bw_enable_get_request(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 19
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -1003,18 +986,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_enable_get_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -1024,21 +1004,9 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_enable_get_request {")
         with q.group():
@@ -1052,14 +1020,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_enable_set_reply(Message):
+bsn_header.subtypes[19] = bsn_bw_enable_get_request
+
+class bsn_bw_enable_set_reply(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 23
 
     def __init__(self, xid=None, enable=None, status=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if enable != None:
             self.enable = enable
         else:
@@ -1068,6 +1041,7 @@
             self.status = status
         else:
             self.status = 0
+        return
 
     def pack(self):
         packed = []
@@ -1084,18 +1058,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_enable_set_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -1107,23 +1078,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.enable != other.enable: return False
         if self.status != other.status: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_enable_set_reply {")
         with q.group():
@@ -1143,18 +1102,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_enable_set_request(Message):
+bsn_header.subtypes[23] = bsn_bw_enable_set_reply
+
+class bsn_bw_enable_set_request(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 18
 
     def __init__(self, xid=None, enable=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if enable != None:
             self.enable = enable
         else:
             self.enable = 0
+        return
 
     def pack(self):
         packed = []
@@ -1170,18 +1135,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_enable_set_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -1192,22 +1154,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.enable != other.enable: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_enable_set_request {")
         with q.group():
@@ -1224,18 +1174,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_get_interfaces_reply(Message):
+bsn_header.subtypes[18] = bsn_bw_enable_set_request
+
+class bsn_get_interfaces_reply(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 10
 
     def __init__(self, xid=None, interfaces=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if interfaces != None:
             self.interfaces = interfaces
         else:
             self.interfaces = []
+        return
 
     def pack(self):
         packed = []
@@ -1245,24 +1201,21 @@
         packed.append(struct.pack("!L", self.xid))
         packed.append(struct.pack("!L", self.experimenter))
         packed.append(struct.pack("!L", self.subtype))
-        packed.append(util.pack_list(self.interfaces))
+        packed.append(loxi.generic_util.pack_list(self.interfaces))
         length = sum([len(x) for x in packed])
         packed[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_get_interfaces_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -1273,22 +1226,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.interfaces != other.interfaces: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_get_interfaces_reply {")
         with q.group():
@@ -1305,14 +1246,20 @@
             q.breakable()
         q.text('}')
 
-class bsn_get_interfaces_request(Message):
+bsn_header.subtypes[10] = bsn_get_interfaces_reply
+
+class bsn_get_interfaces_request(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 9
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -1327,18 +1274,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_get_interfaces_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -1348,21 +1292,9 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_get_interfaces_request {")
         with q.group():
@@ -1376,18 +1308,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_get_mirroring_reply(Message):
+bsn_header.subtypes[9] = bsn_get_interfaces_request
+
+class bsn_get_mirroring_reply(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 5
 
     def __init__(self, xid=None, report_mirror_ports=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if report_mirror_ports != None:
             self.report_mirror_ports = report_mirror_ports
         else:
             self.report_mirror_ports = 0
+        return
 
     def pack(self):
         packed = []
@@ -1404,18 +1342,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_get_mirroring_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -1427,22 +1362,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.report_mirror_ports != other.report_mirror_ports: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_get_mirroring_reply {")
         with q.group():
@@ -1459,18 +1382,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_get_mirroring_request(Message):
+bsn_header.subtypes[5] = bsn_get_mirroring_reply
+
+class bsn_get_mirroring_request(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 4
 
     def __init__(self, xid=None, report_mirror_ports=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if report_mirror_ports != None:
             self.report_mirror_ports = report_mirror_ports
         else:
             self.report_mirror_ports = 0
+        return
 
     def pack(self):
         packed = []
@@ -1487,18 +1416,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_get_mirroring_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -1510,22 +1436,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.report_mirror_ports != other.report_mirror_ports: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_get_mirroring_request {")
         with q.group():
@@ -1542,14 +1456,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_pdu_rx_reply(Message):
+bsn_header.subtypes[4] = bsn_get_mirroring_request
+
+class bsn_pdu_rx_reply(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 34
 
     def __init__(self, xid=None, status=None, port_no=None, slot_num=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
@@ -1562,6 +1481,7 @@
             self.slot_num = slot_num
         else:
             self.slot_num = 0
+        return
 
     def pack(self):
         packed = []
@@ -1579,18 +1499,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_pdu_rx_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -1603,24 +1520,12 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         if self.port_no != other.port_no: return False
         if self.slot_num != other.slot_num: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_pdu_rx_reply {")
         with q.group():
@@ -1643,14 +1548,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_pdu_rx_request(Message):
+bsn_header.subtypes[34] = bsn_pdu_rx_reply
+
+class bsn_pdu_rx_request(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 33
 
     def __init__(self, xid=None, timeout_ms=None, port_no=None, slot_num=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if timeout_ms != None:
             self.timeout_ms = timeout_ms
         else:
@@ -1667,6 +1577,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -1686,18 +1597,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_pdu_rx_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -1712,8 +1620,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.timeout_ms != other.timeout_ms: return False
         if self.port_no != other.port_no: return False
@@ -1721,16 +1627,6 @@
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_pdu_rx_request {")
         with q.group():
@@ -1756,14 +1652,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_pdu_rx_timeout(Message):
+bsn_header.subtypes[33] = bsn_pdu_rx_request
+
+class bsn_pdu_rx_timeout(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 35
 
     def __init__(self, xid=None, port_no=None, slot_num=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if port_no != None:
             self.port_no = port_no
         else:
@@ -1772,6 +1673,7 @@
             self.slot_num = slot_num
         else:
             self.slot_num = 0
+        return
 
     def pack(self):
         packed = []
@@ -1788,18 +1690,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_pdu_rx_timeout()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -1811,23 +1710,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.port_no != other.port_no: return False
         if self.slot_num != other.slot_num: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_pdu_rx_timeout {")
         with q.group():
@@ -1847,14 +1734,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_pdu_tx_reply(Message):
+bsn_header.subtypes[35] = bsn_pdu_rx_timeout
+
+class bsn_pdu_tx_reply(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 32
 
     def __init__(self, xid=None, status=None, port_no=None, slot_num=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
@@ -1867,6 +1759,7 @@
             self.slot_num = slot_num
         else:
             self.slot_num = 0
+        return
 
     def pack(self):
         packed = []
@@ -1884,18 +1777,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_pdu_tx_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -1908,24 +1798,12 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         if self.port_no != other.port_no: return False
         if self.slot_num != other.slot_num: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_pdu_tx_reply {")
         with q.group():
@@ -1948,14 +1826,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_pdu_tx_request(Message):
+bsn_header.subtypes[32] = bsn_pdu_tx_reply
+
+class bsn_pdu_tx_request(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 31
 
     def __init__(self, xid=None, tx_interval_ms=None, port_no=None, slot_num=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if tx_interval_ms != None:
             self.tx_interval_ms = tx_interval_ms
         else:
@@ -1972,6 +1855,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -1991,18 +1875,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_pdu_tx_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -2017,8 +1898,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.tx_interval_ms != other.tx_interval_ms: return False
         if self.port_no != other.port_no: return False
@@ -2026,16 +1905,6 @@
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_pdu_tx_request {")
         with q.group():
@@ -2061,18 +1930,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_set_mirroring(Message):
+bsn_header.subtypes[31] = bsn_pdu_tx_request
+
+class bsn_set_mirroring(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 3
 
     def __init__(self, xid=None, report_mirror_ports=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if report_mirror_ports != None:
             self.report_mirror_ports = report_mirror_ports
         else:
             self.report_mirror_ports = 0
+        return
 
     def pack(self):
         packed = []
@@ -2089,18 +1964,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_set_mirroring()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -2112,22 +1984,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.report_mirror_ports != other.report_mirror_ports: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_set_mirroring {")
         with q.group():
@@ -2144,18 +2004,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_set_pktin_suppression_reply(Message):
+bsn_header.subtypes[3] = bsn_set_mirroring
+
+class bsn_set_pktin_suppression_reply(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 25
 
     def __init__(self, xid=None, status=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
             self.status = 0
+        return
 
     def pack(self):
         packed = []
@@ -2171,18 +2037,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_set_pktin_suppression_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -2193,22 +2056,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_set_pktin_suppression_reply {")
         with q.group():
@@ -2225,14 +2076,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_set_pktin_suppression_request(Message):
+bsn_header.subtypes[25] = bsn_set_pktin_suppression_reply
+
+class bsn_set_pktin_suppression_request(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 11
 
     def __init__(self, xid=None, enabled=None, idle_timeout=None, hard_timeout=None, priority=None, cookie=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if enabled != None:
             self.enabled = enabled
         else:
@@ -2253,6 +2109,7 @@
             self.cookie = cookie
         else:
             self.cookie = 0
+        return
 
     def pack(self):
         packed = []
@@ -2273,18 +2130,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_set_pktin_suppression_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -2300,8 +2154,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.enabled != other.enabled: return False
         if self.idle_timeout != other.idle_timeout: return False
@@ -2310,16 +2162,6 @@
         if self.cookie != other.cookie: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_set_pktin_suppression_request {")
         with q.group():
@@ -2348,14 +2190,75 @@
             q.breakable()
         q.text('}')
 
-class bsn_virtual_port_create_reply(Message):
+bsn_header.subtypes[11] = bsn_set_pktin_suppression_request
+
+class experimenter_stats_reply(stats_reply):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 16)
+        try:
+            subclass = experimenter_stats_reply.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter_stats_reply stats_reply message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+stats_reply.subtypes[65535] = experimenter_stats_reply
+
+class bsn_stats_reply(experimenter_stats_reply):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 20)
+        try:
+            subclass = bsn_stats_reply.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown bsn_stats_reply experimenter_stats_reply stats_reply message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter_stats_reply.subtypes[6035143] = bsn_stats_reply
+
+class experimenter_stats_request(stats_request):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 16)
+        try:
+            subclass = experimenter_stats_request.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter_stats_request stats_request message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+stats_request.subtypes[65535] = experimenter_stats_request
+
+class bsn_stats_request(experimenter_stats_request):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 20)
+        try:
+            subclass = bsn_stats_request.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown bsn_stats_request experimenter_stats_request stats_request message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter_stats_request.subtypes[6035143] = bsn_stats_request
+
+class bsn_virtual_port_create_reply(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 16
 
     def __init__(self, xid=None, status=None, vport_no=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
@@ -2364,6 +2267,7 @@
             self.vport_no = vport_no
         else:
             self.vport_no = 0
+        return
 
     def pack(self):
         packed = []
@@ -2380,18 +2284,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_virtual_port_create_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -2403,23 +2304,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         if self.vport_no != other.vport_no: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_virtual_port_create_reply {")
         with q.group():
@@ -2439,18 +2328,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_virtual_port_create_request(Message):
+bsn_header.subtypes[16] = bsn_virtual_port_create_reply
+
+class bsn_virtual_port_create_request(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 15
 
     def __init__(self, xid=None, vport=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if vport != None:
             self.vport = vport
         else:
             self.vport = common.bsn_vport_q_in_q()
+        return
 
     def pack(self):
         packed = []
@@ -2466,18 +2361,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_virtual_port_create_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -2488,22 +2380,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.vport != other.vport: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_virtual_port_create_request {")
         with q.group():
@@ -2520,18 +2400,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_virtual_port_remove_reply(Message):
+bsn_header.subtypes[15] = bsn_virtual_port_create_request
+
+class bsn_virtual_port_remove_reply(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 26
 
     def __init__(self, xid=None, status=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
             self.status = 0
+        return
 
     def pack(self):
         packed = []
@@ -2547,18 +2433,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_virtual_port_remove_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -2569,22 +2452,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_virtual_port_remove_reply {")
         with q.group():
@@ -2601,18 +2472,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_virtual_port_remove_request(Message):
+bsn_header.subtypes[26] = bsn_virtual_port_remove_reply
+
+class bsn_virtual_port_remove_request(bsn_header):
     version = 2
     type = 4
     experimenter = 6035143
     subtype = 17
 
     def __init__(self, xid=None, vport_no=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if vport_no != None:
             self.vport_no = vport_no
         else:
             self.vport_no = 0
+        return
 
     def pack(self):
         packed = []
@@ -2628,18 +2505,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_virtual_port_remove_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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)
@@ -2650,22 +2524,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.vport_no != other.vport_no: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_virtual_port_remove_request {")
         with q.group():
@@ -2682,13 +2544,18 @@
             q.breakable()
         q.text('}')
 
-class desc_stats_reply(Message):
+bsn_header.subtypes[17] = bsn_virtual_port_remove_request
+
+class desc_stats_reply(stats_reply):
     version = 2
     type = 19
     stats_type = 0
 
     def __init__(self, xid=None, flags=None, mfr_desc=None, hw_desc=None, sw_desc=None, serial_num=None, dp_desc=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -2713,6 +2580,7 @@
             self.dp_desc = dp_desc
         else:
             self.dp_desc = ""
+        return
 
     def pack(self):
         packed = []
@@ -2733,18 +2601,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = desc_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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 == 0)
@@ -2759,8 +2624,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.mfr_desc != other.mfr_desc: return False
@@ -2770,16 +2633,6 @@
         if self.dp_desc != other.dp_desc: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("desc_stats_reply {")
         with q.group():
@@ -2811,17 +2664,23 @@
             q.breakable()
         q.text('}')
 
-class desc_stats_request(Message):
+stats_reply.subtypes[0] = desc_stats_reply
+
+class desc_stats_request(stats_request):
     version = 2
     type = 18
     stats_type = 0
 
     def __init__(self, xid=None, flags=None):
-        self.xid = xid
+        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 = []
@@ -2837,18 +2696,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = desc_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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 == 0)
@@ -2858,22 +2714,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("desc_stats_request {")
         with q.group():
@@ -2890,16 +2734,22 @@
             q.breakable()
         q.text('}')
 
-class echo_reply(Message):
+stats_request.subtypes[0] = desc_stats_request
+
+class echo_reply(message):
     version = 2
     type = 3
 
     def __init__(self, xid=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if data != None:
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -2913,40 +2763,25 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = echo_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 3)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.data = str(reader.read_all())
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("echo_reply {")
         with q.group():
@@ -2963,16 +2798,22 @@
             q.breakable()
         q.text('}')
 
-class echo_request(Message):
+message.subtypes[3] = echo_reply
+
+class echo_request(message):
     version = 2
     type = 2
 
     def __init__(self, xid=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if data != None:
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -2986,40 +2827,25 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = echo_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 2)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.data = str(reader.read_all())
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("echo_request {")
         with q.group():
@@ -3036,12 +2862,17 @@
             q.breakable()
         q.text('}')
 
-class features_reply(Message):
+message.subtypes[2] = echo_request
+
+class features_reply(message):
     version = 2
     type = 6
 
     def __init__(self, xid=None, datapath_id=None, n_buffers=None, n_tables=None, capabilities=None, reserved=None, ports=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if datapath_id != None:
             self.datapath_id = datapath_id
         else:
@@ -3066,6 +2897,7 @@
             self.ports = ports
         else:
             self.ports = []
+        return
 
     def pack(self):
         packed = []
@@ -3079,24 +2911,21 @@
         packed.append('\x00' * 3)
         packed.append(struct.pack("!L", self.capabilities))
         packed.append(struct.pack("!L", self.reserved))
-        packed.append(util.pack_list(self.ports))
+        packed.append(loxi.generic_util.pack_list(self.ports))
         length = sum([len(x) for x in packed])
         packed[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = features_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 6)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.datapath_id = reader.read("!Q")[0]
         obj.n_buffers = reader.read("!L")[0]
@@ -3109,8 +2938,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.datapath_id != other.datapath_id: return False
         if self.n_buffers != other.n_buffers: return False
@@ -3120,16 +2947,6 @@
         if self.ports != other.ports: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("features_reply {")
         with q.group():
@@ -3161,12 +2978,18 @@
             q.breakable()
         q.text('}')
 
-class features_request(Message):
+message.subtypes[6] = features_reply
+
+class features_request(message):
     version = 2
     type = 5
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -3179,38 +3002,23 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = features_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 5)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("features_request {")
         with q.group():
@@ -3224,13 +3032,32 @@
             q.breakable()
         q.text('}')
 
-class flow_add(Message):
+message.subtypes[5] = features_request
+
+class flow_mod(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('B', 25)
+        try:
+            subclass = flow_mod.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown flow_mod message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[14] = flow_mod
+
+class flow_add(flow_mod):
     version = 2
     type = 14
     _command = 0
 
     def __init__(self, xid=None, cookie=None, cookie_mask=None, table_id=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, out_group=None, flags=None, match=None, instructions=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if cookie != None:
             self.cookie = cookie
         else:
@@ -3279,6 +3106,7 @@
             self.instructions = instructions
         else:
             self.instructions = []
+        return
 
     def pack(self):
         packed = []
@@ -3299,24 +3127,21 @@
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 2)
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_add()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 14)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.cookie = reader.read("!Q")[0]
         obj.cookie_mask = reader.read("!Q")[0]
@@ -3332,13 +3157,11 @@
         obj.flags = reader.read("!H")[0]
         reader.skip(2)
         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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.cookie != other.cookie: return False
         if self.cookie_mask != other.cookie_mask: return False
@@ -3354,16 +3177,6 @@
         if self.instructions != other.instructions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_add {")
         with q.group():
@@ -3413,13 +3226,18 @@
             q.breakable()
         q.text('}')
 
-class flow_delete(Message):
+flow_mod.subtypes[0] = flow_add
+
+class flow_delete(flow_mod):
     version = 2
     type = 14
     _command = 3
 
     def __init__(self, xid=None, cookie=None, cookie_mask=None, table_id=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, out_group=None, flags=None, match=None, instructions=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if cookie != None:
             self.cookie = cookie
         else:
@@ -3468,6 +3286,7 @@
             self.instructions = instructions
         else:
             self.instructions = []
+        return
 
     def pack(self):
         packed = []
@@ -3488,24 +3307,21 @@
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 2)
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_delete()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 14)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.cookie = reader.read("!Q")[0]
         obj.cookie_mask = reader.read("!Q")[0]
@@ -3521,13 +3337,11 @@
         obj.flags = reader.read("!H")[0]
         reader.skip(2)
         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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.cookie != other.cookie: return False
         if self.cookie_mask != other.cookie_mask: return False
@@ -3543,16 +3357,6 @@
         if self.instructions != other.instructions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_delete {")
         with q.group():
@@ -3602,13 +3406,18 @@
             q.breakable()
         q.text('}')
 
-class flow_delete_strict(Message):
+flow_mod.subtypes[3] = flow_delete
+
+class flow_delete_strict(flow_mod):
     version = 2
     type = 14
     _command = 4
 
     def __init__(self, xid=None, cookie=None, cookie_mask=None, table_id=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, out_group=None, flags=None, match=None, instructions=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if cookie != None:
             self.cookie = cookie
         else:
@@ -3657,6 +3466,7 @@
             self.instructions = instructions
         else:
             self.instructions = []
+        return
 
     def pack(self):
         packed = []
@@ -3677,24 +3487,21 @@
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 2)
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_delete_strict()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 14)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.cookie = reader.read("!Q")[0]
         obj.cookie_mask = reader.read("!Q")[0]
@@ -3710,13 +3517,11 @@
         obj.flags = reader.read("!H")[0]
         reader.skip(2)
         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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.cookie != other.cookie: return False
         if self.cookie_mask != other.cookie_mask: return False
@@ -3732,16 +3537,6 @@
         if self.instructions != other.instructions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_delete_strict {")
         with q.group():
@@ -3791,13 +3586,18 @@
             q.breakable()
         q.text('}')
 
-class flow_mod_failed_error_msg(Message):
+flow_mod.subtypes[4] = flow_delete_strict
+
+class flow_mod_failed_error_msg(error_msg):
     version = 2
     type = 1
     err_type = 5
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -3806,6 +3606,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -3821,18 +3622,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_mod_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 5)
@@ -3842,23 +3640,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_mod_failed_error_msg {")
         with q.group():
@@ -3878,13 +3664,18 @@
             q.breakable()
         q.text('}')
 
-class flow_modify(Message):
+error_msg.subtypes[5] = flow_mod_failed_error_msg
+
+class flow_modify(flow_mod):
     version = 2
     type = 14
     _command = 1
 
     def __init__(self, xid=None, cookie=None, cookie_mask=None, table_id=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, out_group=None, flags=None, match=None, instructions=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if cookie != None:
             self.cookie = cookie
         else:
@@ -3933,6 +3724,7 @@
             self.instructions = instructions
         else:
             self.instructions = []
+        return
 
     def pack(self):
         packed = []
@@ -3953,24 +3745,21 @@
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 2)
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_modify()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 14)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.cookie = reader.read("!Q")[0]
         obj.cookie_mask = reader.read("!Q")[0]
@@ -3986,13 +3775,11 @@
         obj.flags = reader.read("!H")[0]
         reader.skip(2)
         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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.cookie != other.cookie: return False
         if self.cookie_mask != other.cookie_mask: return False
@@ -4008,16 +3795,6 @@
         if self.instructions != other.instructions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_modify {")
         with q.group():
@@ -4067,13 +3844,18 @@
             q.breakable()
         q.text('}')
 
-class flow_modify_strict(Message):
+flow_mod.subtypes[1] = flow_modify
+
+class flow_modify_strict(flow_mod):
     version = 2
     type = 14
     _command = 2
 
     def __init__(self, xid=None, cookie=None, cookie_mask=None, table_id=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, out_group=None, flags=None, match=None, instructions=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if cookie != None:
             self.cookie = cookie
         else:
@@ -4122,6 +3904,7 @@
             self.instructions = instructions
         else:
             self.instructions = []
+        return
 
     def pack(self):
         packed = []
@@ -4142,24 +3925,21 @@
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 2)
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_modify_strict()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 14)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.cookie = reader.read("!Q")[0]
         obj.cookie_mask = reader.read("!Q")[0]
@@ -4175,13 +3955,11 @@
         obj.flags = reader.read("!H")[0]
         reader.skip(2)
         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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.cookie != other.cookie: return False
         if self.cookie_mask != other.cookie_mask: return False
@@ -4197,16 +3975,6 @@
         if self.instructions != other.instructions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_modify_strict {")
         with q.group():
@@ -4256,12 +4024,17 @@
             q.breakable()
         q.text('}')
 
-class flow_removed(Message):
+flow_mod.subtypes[2] = flow_modify_strict
+
+class flow_removed(message):
     version = 2
     type = 11
 
     def __init__(self, xid=None, cookie=None, priority=None, reason=None, table_id=None, duration_sec=None, duration_nsec=None, idle_timeout=None, packet_count=None, byte_count=None, match=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if cookie != None:
             self.cookie = cookie
         else:
@@ -4302,6 +4075,7 @@
             self.match = match
         else:
             self.match = common.match()
+        return
 
     def pack(self):
         packed = []
@@ -4325,18 +4099,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_removed()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 11)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.cookie = reader.read("!Q")[0]
         obj.priority = reader.read("!H")[0]
@@ -4353,8 +4124,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.cookie != other.cookie: return False
         if self.priority != other.priority: return False
@@ -4368,16 +4137,6 @@
         if self.match != other.match: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_removed {")
         with q.group():
@@ -4421,13 +4180,18 @@
             q.breakable()
         q.text('}')
 
-class flow_stats_reply(Message):
+message.subtypes[11] = flow_removed
+
+class flow_stats_reply(stats_reply):
     version = 2
     type = 19
     stats_type = 1
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -4436,6 +4200,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -4446,51 +4211,36 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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 == 1)
         obj.flags = reader.read("!H")[0]
         reader.skip(4)
-        obj.entries = common.unpack_list_flow_stats_entry(reader)
+        obj.entries = loxi.generic_util.unpack_list(reader, common.flow_stats_entry.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_stats_reply {")
         with q.group():
@@ -4510,13 +4260,18 @@
             q.breakable()
         q.text('}')
 
-class flow_stats_request(Message):
+stats_reply.subtypes[1] = flow_stats_reply
+
+class flow_stats_request(stats_request):
     version = 2
     type = 18
     stats_type = 1
 
     def __init__(self, xid=None, flags=None, table_id=None, out_port=None, out_group=None, cookie=None, cookie_mask=None, match=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -4545,6 +4300,7 @@
             self.match = match
         else:
             self.match = common.match()
+        return
 
     def pack(self):
         packed = []
@@ -4568,18 +4324,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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 == 1)
@@ -4597,8 +4350,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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
@@ -4609,16 +4360,6 @@
         if self.match != other.match: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_stats_request {")
         with q.group():
@@ -4653,12 +4394,17 @@
             q.breakable()
         q.text('}')
 
-class get_config_reply(Message):
+stats_request.subtypes[1] = flow_stats_request
+
+class get_config_reply(message):
     version = 2
     type = 8
 
     def __init__(self, xid=None, flags=None, miss_send_len=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -4667,6 +4413,7 @@
             self.miss_send_len = miss_send_len
         else:
             self.miss_send_len = 0
+        return
 
     def pack(self):
         packed = []
@@ -4681,18 +4428,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = get_config_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 8)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.flags = reader.read("!H")[0]
         obj.miss_send_len = reader.read("!H")[0]
@@ -4700,23 +4444,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.miss_send_len != other.miss_send_len: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("get_config_reply {")
         with q.group():
@@ -4736,12 +4468,18 @@
             q.breakable()
         q.text('}')
 
-class get_config_request(Message):
+message.subtypes[8] = get_config_reply
+
+class get_config_request(message):
     version = 2
     type = 7
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -4754,38 +4492,23 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = get_config_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 7)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("get_config_request {")
         with q.group():
@@ -4799,13 +4522,32 @@
             q.breakable()
         q.text('}')
 
-class group_add(Message):
+message.subtypes[7] = get_config_request
+
+class group_mod(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 8)
+        try:
+            subclass = group_mod.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown group_mod message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[15] = group_mod
+
+class group_add(group_mod):
     version = 2
     type = 15
     command = 0
 
     def __init__(self, xid=None, group_type=None, group_id=None, buckets=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if group_type != None:
             self.group_type = group_type
         else:
@@ -4818,6 +4560,7 @@
             self.buckets = buckets
         else:
             self.buckets = []
+        return
 
     def pack(self):
         packed = []
@@ -4829,53 +4572,38 @@
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_add()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 15)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _command = reader.read("!H")[0]
         assert(_command == 0)
         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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.group_type != other.group_type: return False
         if self.group_id != other.group_id: return False
         if self.buckets != other.buckets: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_add {")
         with q.group():
@@ -4898,13 +4626,18 @@
             q.breakable()
         q.text('}')
 
-class group_delete(Message):
+group_mod.subtypes[0] = group_add
+
+class group_delete(group_mod):
     version = 2
     type = 15
     command = 2
 
     def __init__(self, xid=None, group_type=None, group_id=None, buckets=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if group_type != None:
             self.group_type = group_type
         else:
@@ -4917,6 +4650,7 @@
             self.buckets = buckets
         else:
             self.buckets = []
+        return
 
     def pack(self):
         packed = []
@@ -4928,53 +4662,38 @@
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_delete()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 15)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _command = reader.read("!H")[0]
         assert(_command == 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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.group_type != other.group_type: return False
         if self.group_id != other.group_id: return False
         if self.buckets != other.buckets: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_delete {")
         with q.group():
@@ -4997,13 +4716,18 @@
             q.breakable()
         q.text('}')
 
-class group_desc_stats_reply(Message):
+group_mod.subtypes[2] = group_delete
+
+class group_desc_stats_reply(stats_reply):
     version = 2
     type = 19
     stats_type = 7
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -5012,6 +4736,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -5022,51 +4747,36 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_desc_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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 == 7)
         obj.flags = reader.read("!H")[0]
         reader.skip(4)
-        obj.entries = common.unpack_list_group_desc_stats_entry(reader)
+        obj.entries = loxi.generic_util.unpack_list(reader, common.group_desc_stats_entry.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_desc_stats_reply {")
         with q.group():
@@ -5086,17 +4796,23 @@
             q.breakable()
         q.text('}')
 
-class group_desc_stats_request(Message):
+stats_reply.subtypes[7] = group_desc_stats_reply
+
+class group_desc_stats_request(stats_request):
     version = 2
     type = 18
     stats_type = 7
 
     def __init__(self, xid=None, flags=None):
-        self.xid = xid
+        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 = []
@@ -5112,18 +4828,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_desc_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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 == 7)
@@ -5133,22 +4846,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_desc_stats_request {")
         with q.group():
@@ -5165,13 +4866,18 @@
             q.breakable()
         q.text('}')
 
-class group_mod_failed_error_msg(Message):
+stats_request.subtypes[7] = group_desc_stats_request
+
+class group_mod_failed_error_msg(error_msg):
     version = 2
     type = 1
     err_type = 6
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -5180,6 +4886,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -5195,18 +4902,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_mod_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 6)
@@ -5216,23 +4920,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_mod_failed_error_msg {")
         with q.group():
@@ -5252,13 +4944,18 @@
             q.breakable()
         q.text('}')
 
-class group_modify(Message):
+error_msg.subtypes[6] = group_mod_failed_error_msg
+
+class group_modify(group_mod):
     version = 2
     type = 15
     command = 1
 
     def __init__(self, xid=None, group_type=None, group_id=None, buckets=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if group_type != None:
             self.group_type = group_type
         else:
@@ -5271,6 +4968,7 @@
             self.buckets = buckets
         else:
             self.buckets = []
+        return
 
     def pack(self):
         packed = []
@@ -5282,53 +4980,38 @@
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_modify()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 15)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _command = reader.read("!H")[0]
         assert(_command == 1)
         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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.group_type != other.group_type: return False
         if self.group_id != other.group_id: return False
         if self.buckets != other.buckets: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_modify {")
         with q.group():
@@ -5351,13 +5034,18 @@
             q.breakable()
         q.text('}')
 
-class group_stats_reply(Message):
+group_mod.subtypes[1] = group_modify
+
+class group_stats_reply(stats_reply):
     version = 2
     type = 19
     stats_type = 6
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -5366,6 +5054,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -5376,51 +5065,36 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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 == 6)
         obj.flags = reader.read("!H")[0]
         reader.skip(4)
-        obj.entries = common.unpack_list_group_stats_entry(reader)
+        obj.entries = loxi.generic_util.unpack_list(reader, common.group_stats_entry.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_stats_reply {")
         with q.group():
@@ -5440,13 +5114,18 @@
             q.breakable()
         q.text('}')
 
-class group_stats_request(Message):
+stats_reply.subtypes[6] = group_stats_reply
+
+class group_stats_request(stats_request):
     version = 2
     type = 18
     stats_type = 6
 
     def __init__(self, xid=None, flags=None, group_id=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -5455,6 +5134,7 @@
             self.group_id = group_id
         else:
             self.group_id = 0
+        return
 
     def pack(self):
         packed = []
@@ -5472,18 +5152,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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 == 6)
@@ -5495,23 +5172,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.group_id != other.group_id: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_stats_request {")
         with q.group():
@@ -5531,12 +5196,18 @@
             q.breakable()
         q.text('}')
 
-class hello(Message):
+stats_request.subtypes[6] = group_stats_request
+
+class hello(message):
     version = 2
     type = 0
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -5549,38 +5220,23 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = hello()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 0)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("hello {")
         with q.group():
@@ -5594,13 +5250,18 @@
             q.breakable()
         q.text('}')
 
-class hello_failed_error_msg(Message):
+message.subtypes[0] = hello
+
+class hello_failed_error_msg(error_msg):
     version = 2
     type = 1
     err_type = 0
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -5609,6 +5270,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -5624,18 +5286,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = hello_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 0)
@@ -5645,23 +5304,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("hello_failed_error_msg {")
         with q.group():
@@ -5681,12 +5328,31 @@
             q.breakable()
         q.text('}')
 
-class packet_in(Message):
+error_msg.subtypes[0] = hello_failed_error_msg
+
+class nicira_header(experimenter):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 12)
+        try:
+            subclass = nicira_header.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown nicira_header experimenter message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter.subtypes[8992] = nicira_header
+
+class packet_in(message):
     version = 2
     type = 10
 
     def __init__(self, xid=None, buffer_id=None, in_port=None, in_phy_port=None, total_len=None, reason=None, table_id=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if buffer_id != None:
             self.buffer_id = buffer_id
         else:
@@ -5715,6 +5381,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -5734,18 +5401,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = packet_in()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 10)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.buffer_id = reader.read("!L")[0]
         obj.in_port = util.unpack_port_no(reader)
@@ -5758,8 +5422,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.buffer_id != other.buffer_id: return False
         if self.in_port != other.in_port: return False
@@ -5770,16 +5432,6 @@
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("packet_in {")
         with q.group():
@@ -5814,12 +5466,17 @@
             q.breakable()
         q.text('}')
 
-class packet_out(Message):
+message.subtypes[10] = packet_in
+
+class packet_out(message):
     version = 2
     type = 13
 
     def __init__(self, xid=None, buffer_id=None, in_port=None, actions=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if buffer_id != None:
             self.buffer_id = buffer_id
         else:
@@ -5836,6 +5493,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -5847,7 +5505,7 @@
         packed.append(util.pack_port_no(self.in_port))
         packed.append(struct.pack("!H", 0)) # placeholder for actions_len at index 6
         packed.append('\x00' * 6)
-        packed.append(util.pack_list(self.actions))
+        packed.append(loxi.generic_util.pack_list(self.actions))
         packed[6] = struct.pack("!H", len(packed[-1]))
         packed.append(self.data)
         length = sum([len(x) for x in packed])
@@ -5855,31 +5513,26 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = packet_out()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 13)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.buffer_id = reader.read("!L")[0]
         obj.in_port = util.unpack_port_no(reader)
         _actions_len = reader.read("!H")[0]
         reader.skip(6)
-        obj.actions = action.unpack_list(reader.slice(_actions_len))
+        obj.actions = loxi.generic_util.unpack_list(reader.slice(_actions_len), action.action.unpack)
         obj.data = str(reader.read_all())
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.buffer_id != other.buffer_id: return False
         if self.in_port != other.in_port: return False
@@ -5887,16 +5540,6 @@
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("packet_out {")
         with q.group():
@@ -5922,12 +5565,17 @@
             q.breakable()
         q.text('}')
 
-class port_mod(Message):
+message.subtypes[13] = packet_out
+
+class port_mod(message):
     version = 2
     type = 16
 
     def __init__(self, xid=None, port_no=None, hw_addr=None, config=None, mask=None, advertise=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if port_no != None:
             self.port_no = port_no
         else:
@@ -5948,6 +5596,7 @@
             self.advertise = advertise
         else:
             self.advertise = 0
+        return
 
     def pack(self):
         packed = []
@@ -5968,18 +5617,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_mod()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 16)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.port_no = util.unpack_port_no(reader)
         reader.skip(4)
@@ -5993,8 +5639,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.port_no != other.port_no: return False
         if self.hw_addr != other.hw_addr: return False
@@ -6003,16 +5647,6 @@
         if self.advertise != other.advertise: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_mod {")
         with q.group():
@@ -6041,13 +5675,18 @@
             q.breakable()
         q.text('}')
 
-class port_mod_failed_error_msg(Message):
+message.subtypes[16] = port_mod
+
+class port_mod_failed_error_msg(error_msg):
     version = 2
     type = 1
     err_type = 7
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -6056,6 +5695,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -6071,18 +5711,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_mod_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 7)
@@ -6092,23 +5729,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_mod_failed_error_msg {")
         with q.group():
@@ -6128,13 +5753,18 @@
             q.breakable()
         q.text('}')
 
-class port_stats_reply(Message):
+error_msg.subtypes[7] = port_mod_failed_error_msg
+
+class port_stats_reply(stats_reply):
     version = 2
     type = 19
     stats_type = 4
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -6143,6 +5773,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -6153,24 +5784,21 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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 == 4)
@@ -6181,23 +5809,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_stats_reply {")
         with q.group():
@@ -6217,13 +5833,18 @@
             q.breakable()
         q.text('}')
 
-class port_stats_request(Message):
+stats_reply.subtypes[4] = port_stats_reply
+
+class port_stats_request(stats_request):
     version = 2
     type = 18
     stats_type = 4
 
     def __init__(self, xid=None, flags=None, port_no=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -6232,6 +5853,7 @@
             self.port_no = port_no
         else:
             self.port_no = 0
+        return
 
     def pack(self):
         packed = []
@@ -6249,18 +5871,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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 == 4)
@@ -6272,23 +5891,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.port_no != other.port_no: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_stats_request {")
         with q.group():
@@ -6308,12 +5915,17 @@
             q.breakable()
         q.text('}')
 
-class port_status(Message):
+stats_request.subtypes[4] = port_stats_request
+
+class port_status(message):
     version = 2
     type = 12
 
     def __init__(self, xid=None, reason=None, desc=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if reason != None:
             self.reason = reason
         else:
@@ -6322,6 +5934,7 @@
             self.desc = desc
         else:
             self.desc = common.port_desc()
+        return
 
     def pack(self):
         packed = []
@@ -6337,18 +5950,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_status()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 12)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.reason = reader.read("!B")[0]
         reader.skip(7)
@@ -6357,23 +5967,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.reason != other.reason: return False
         if self.desc != other.desc: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_status {")
         with q.group():
@@ -6393,12 +5991,17 @@
             q.breakable()
         q.text('}')
 
-class queue_get_config_reply(Message):
+message.subtypes[12] = port_status
+
+class queue_get_config_reply(message):
     version = 2
     type = 23
 
     def __init__(self, xid=None, port=None, queues=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if port != None:
             self.port = port
         else:
@@ -6407,6 +6010,7 @@
             self.queues = queues
         else:
             self.queues = []
+        return
 
     def pack(self):
         packed = []
@@ -6416,49 +6020,34 @@
         packed.append(struct.pack("!L", self.xid))
         packed.append(util.pack_port_no(self.port))
         packed.append('\x00' * 4)
-        packed.append(util.pack_list(self.queues))
+        packed.append(loxi.generic_util.pack_list(self.queues))
         length = sum([len(x) for x in packed])
         packed[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = queue_get_config_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 23)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.port = util.unpack_port_no(reader)
         reader.skip(4)
-        obj.queues = common.unpack_list_packet_queue(reader)
+        obj.queues = loxi.generic_util.unpack_list(reader, common.packet_queue.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.port != other.port: return False
         if self.queues != other.queues: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_get_config_reply {")
         with q.group():
@@ -6478,16 +6067,22 @@
             q.breakable()
         q.text('}')
 
-class queue_get_config_request(Message):
+message.subtypes[23] = queue_get_config_reply
+
+class queue_get_config_request(message):
     version = 2
     type = 22
 
     def __init__(self, xid=None, port=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if port != None:
             self.port = port
         else:
             self.port = 0
+        return
 
     def pack(self):
         packed = []
@@ -6502,18 +6097,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = queue_get_config_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 22)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.port = util.unpack_port_no(reader)
         reader.skip(4)
@@ -6521,22 +6113,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.port != other.port: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_get_config_request {")
         with q.group():
@@ -6553,13 +6133,18 @@
             q.breakable()
         q.text('}')
 
-class queue_op_failed_error_msg(Message):
+message.subtypes[22] = queue_get_config_request
+
+class queue_op_failed_error_msg(error_msg):
     version = 2
     type = 1
     err_type = 9
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -6568,6 +6153,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -6583,18 +6169,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = queue_op_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 9)
@@ -6604,23 +6187,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_op_failed_error_msg {")
         with q.group():
@@ -6640,13 +6211,18 @@
             q.breakable()
         q.text('}')
 
-class queue_stats_reply(Message):
+error_msg.subtypes[9] = queue_op_failed_error_msg
+
+class queue_stats_reply(stats_reply):
     version = 2
     type = 19
     stats_type = 5
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -6655,6 +6231,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -6665,24 +6242,21 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = queue_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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 == 5)
@@ -6693,23 +6267,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_stats_reply {")
         with q.group():
@@ -6729,13 +6291,18 @@
             q.breakable()
         q.text('}')
 
-class queue_stats_request(Message):
+stats_reply.subtypes[5] = queue_stats_reply
+
+class queue_stats_request(stats_request):
     version = 2
     type = 18
     stats_type = 5
 
     def __init__(self, xid=None, flags=None, port_no=None, queue_id=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -6748,6 +6315,7 @@
             self.queue_id = queue_id
         else:
             self.queue_id = 0
+        return
 
     def pack(self):
         packed = []
@@ -6765,18 +6333,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = queue_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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 == 5)
@@ -6788,24 +6353,12 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.port_no != other.port_no: return False
         if self.queue_id != other.queue_id: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_stats_request {")
         with q.group():
@@ -6828,12 +6381,17 @@
             q.breakable()
         q.text('}')
 
-class set_config(Message):
+stats_request.subtypes[5] = queue_stats_request
+
+class set_config(message):
     version = 2
     type = 9
 
     def __init__(self, xid=None, flags=None, miss_send_len=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -6842,6 +6400,7 @@
             self.miss_send_len = miss_send_len
         else:
             self.miss_send_len = 0
+        return
 
     def pack(self):
         packed = []
@@ -6856,18 +6415,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = set_config()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 9)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.flags = reader.read("!H")[0]
         obj.miss_send_len = reader.read("!H")[0]
@@ -6875,23 +6431,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.miss_send_len != other.miss_send_len: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("set_config {")
         with q.group():
@@ -6911,13 +6455,18 @@
             q.breakable()
         q.text('}')
 
-class switch_config_failed_error_msg(Message):
+message.subtypes[9] = set_config
+
+class switch_config_failed_error_msg(error_msg):
     version = 2
     type = 1
     err_type = 10
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -6926,6 +6475,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -6941,18 +6491,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = switch_config_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 10)
@@ -6962,23 +6509,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("switch_config_failed_error_msg {")
         with q.group():
@@ -6998,12 +6533,17 @@
             q.breakable()
         q.text('}')
 
-class table_mod(Message):
+error_msg.subtypes[10] = switch_config_failed_error_msg
+
+class table_mod(message):
     version = 2
     type = 17
 
     def __init__(self, xid=None, table_id=None, config=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if table_id != None:
             self.table_id = table_id
         else:
@@ -7012,6 +6552,7 @@
             self.config = config
         else:
             self.config = 0
+        return
 
     def pack(self):
         packed = []
@@ -7027,18 +6568,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = table_mod()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 17)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.table_id = reader.read("!B")[0]
         reader.skip(3)
@@ -7047,23 +6585,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.table_id != other.table_id: return False
         if self.config != other.config: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_mod {")
         with q.group():
@@ -7083,13 +6609,18 @@
             q.breakable()
         q.text('}')
 
-class table_mod_failed_error_msg(Message):
+message.subtypes[17] = table_mod
+
+class table_mod_failed_error_msg(error_msg):
     version = 2
     type = 1
     err_type = 8
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -7098,6 +6629,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -7113,18 +6645,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = table_mod_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 8)
@@ -7134,23 +6663,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_mod_failed_error_msg {")
         with q.group():
@@ -7170,13 +6687,18 @@
             q.breakable()
         q.text('}')
 
-class table_stats_reply(Message):
+error_msg.subtypes[8] = table_mod_failed_error_msg
+
+class table_stats_reply(stats_reply):
     version = 2
     type = 19
     stats_type = 3
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -7185,6 +6707,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -7195,24 +6718,21 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = table_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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 == 3)
@@ -7223,23 +6743,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_stats_reply {")
         with q.group():
@@ -7259,17 +6767,23 @@
             q.breakable()
         q.text('}')
 
-class table_stats_request(Message):
+stats_reply.subtypes[3] = table_stats_reply
+
+class table_stats_request(stats_request):
     version = 2
     type = 18
     stats_type = 3
 
     def __init__(self, xid=None, flags=None):
-        self.xid = xid
+        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 = []
@@ -7285,18 +6799,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = table_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 2)
         _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 == 3)
@@ -7306,22 +6817,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_stats_request {")
         with q.group():
@@ -7338,6 +6837,8 @@
             q.breakable()
         q.text('}')
 
+stats_request.subtypes[3] = table_stats_request
+
 
 def parse_header(buf):
     if len(buf) < 8:
@@ -7350,210 +6851,4 @@
         raise loxi.ProtocolError("wrong OpenFlow version (expected %d, got %d)" % (const.OFP_VERSION, msg_ver))
     if len(buf) != msg_len:
         raise loxi.ProtocolError("incorrect message size")
-    if msg_type in parsers:
-        return parsers[msg_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected message type")
-
-def parse_error(buf):
-    if len(buf) < 8 + 2:
-        raise loxi.ProtocolError("message too short")
-    err_type, = struct.unpack_from("!H", buf, 8)
-    if err_type in error_msg_parsers:
-        return error_msg_parsers[err_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected error type %u" % err_type)
-
-def parse_flow_mod(buf):
-    if len(buf) < 25 + 1:
-        raise loxi.ProtocolError("message too short")
-    # Technically uint16_t for OF 1.0
-    cmd, = struct.unpack_from("!B", buf, 25)
-    if cmd in flow_mod_parsers:
-        return flow_mod_parsers[cmd](buf)
-    else:
-        raise loxi.ProtocolError("unexpected flow mod cmd %u" % cmd)
-
-def parse_group_mod(buf):
-    if len(buf) < 8 + 2:
-        raise loxi.ProtocolError("message too short")
-    cmd, = struct.unpack_from("!H", buf, 8)
-    if cmd in flow_mod_parsers:
-        return group_mod_parsers[cmd](buf)
-    else:
-        raise loxi.ProtocolError("unexpected group mod cmd %u" % cmd)
-
-def parse_stats_reply(buf):
-    if len(buf) < 8 + 2:
-        raise loxi.ProtocolError("message too short")
-    stats_type, = struct.unpack_from("!H", buf, 8)
-    if stats_type in stats_reply_parsers:
-        return stats_reply_parsers[stats_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected stats type %u" % stats_type)
-
-def parse_stats_request(buf):
-    if len(buf) < 8 + 2:
-        raise loxi.ProtocolError("message too short")
-    stats_type, = struct.unpack_from("!H", buf, 8)
-    if stats_type in stats_request_parsers:
-        return stats_request_parsers[stats_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected stats type %u" % stats_type)
-
-def parse_experimenter_stats_request(buf):
-    if len(buf) < 24:
-        raise loxi.ProtocolError("experimenter stats request message too short")
-
-    experimenter, exp_type = struct.unpack_from("!LL", buf, 16)
-
-    if experimenter in experimenter_stats_request_parsers and \
-            exp_type in experimenter_stats_request_parsers[experimenter]:
-        return experimenter_stats_request_parsers[experimenter][exp_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected stats request experimenter %#x exp_type %#x" % (experimenter, exp_type))
-
-def parse_experimenter_stats_reply(buf):
-    if len(buf) < 24:
-        raise loxi.ProtocolError("experimenter stats reply message too short")
-
-    experimenter, exp_type = struct.unpack_from("!LL", buf, 16)
-
-    if experimenter in experimenter_stats_reply_parsers and \
-            exp_type in experimenter_stats_reply_parsers[experimenter]:
-        return experimenter_stats_reply_parsers[experimenter][exp_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected stats reply experimenter %#x exp_type %#x" % (experimenter, exp_type))
-
-def parse_experimenter(buf):
-    if len(buf) < 16:
-        raise loxi.ProtocolError("experimenter message too short")
-
-    experimenter, = struct.unpack_from("!L", buf, 8)
-    if experimenter == 0x005c16c7: # Big Switch Networks
-        subtype, = struct.unpack_from("!L", buf, 12)
-    elif experimenter == 0x00002320: # Nicira
-        subtype, = struct.unpack_from("!L", buf, 12)
-    else:
-        raise loxi.ProtocolError("unexpected experimenter id %#x" % experimenter)
-
-    if subtype in experimenter_parsers[experimenter]:
-        return experimenter_parsers[experimenter][subtype](buf)
-    else:
-        raise loxi.ProtocolError("unexpected experimenter %#x subtype %#x" % (experimenter, subtype))
-
-parsers = {
-    const.OFPT_HELLO : hello.unpack,
-    const.OFPT_ERROR : parse_error,
-    const.OFPT_ECHO_REQUEST : echo_request.unpack,
-    const.OFPT_ECHO_REPLY : echo_reply.unpack,
-    const.OFPT_EXPERIMENTER : parse_experimenter,
-    const.OFPT_FEATURES_REQUEST : features_request.unpack,
-    const.OFPT_FEATURES_REPLY : features_reply.unpack,
-    const.OFPT_GET_CONFIG_REQUEST : get_config_request.unpack,
-    const.OFPT_GET_CONFIG_REPLY : get_config_reply.unpack,
-    const.OFPT_SET_CONFIG : set_config.unpack,
-    const.OFPT_PACKET_IN : packet_in.unpack,
-    const.OFPT_FLOW_REMOVED : flow_removed.unpack,
-    const.OFPT_PORT_STATUS : port_status.unpack,
-    const.OFPT_PACKET_OUT : packet_out.unpack,
-    const.OFPT_FLOW_MOD : parse_flow_mod,
-    const.OFPT_GROUP_MOD : parse_group_mod,
-    const.OFPT_PORT_MOD : port_mod.unpack,
-    const.OFPT_TABLE_MOD : table_mod.unpack,
-    const.OFPT_STATS_REQUEST : parse_stats_request,
-    const.OFPT_STATS_REPLY : parse_stats_reply,
-    const.OFPT_BARRIER_REQUEST : barrier_request.unpack,
-    const.OFPT_BARRIER_REPLY : barrier_reply.unpack,
-    const.OFPT_QUEUE_GET_CONFIG_REQUEST : queue_get_config_request.unpack,
-    const.OFPT_QUEUE_GET_CONFIG_REPLY : queue_get_config_reply.unpack,
-}
-
-error_msg_parsers = {
-    const.OFPET_HELLO_FAILED : hello_failed_error_msg.unpack,
-    const.OFPET_BAD_REQUEST : bad_request_error_msg.unpack,
-    const.OFPET_BAD_ACTION : bad_action_error_msg.unpack,
-    const.OFPET_FLOW_MOD_FAILED : flow_mod_failed_error_msg.unpack,
-    const.OFPET_PORT_MOD_FAILED : port_mod_failed_error_msg.unpack,
-    const.OFPET_QUEUE_OP_FAILED : queue_op_failed_error_msg.unpack,
-    const.OFPET_BAD_INSTRUCTION : bad_instruction_error_msg.unpack,
-    const.OFPET_BAD_MATCH : bad_match_error_msg.unpack,
-    const.OFPET_GROUP_MOD_FAILED : group_mod_failed_error_msg.unpack,
-    const.OFPET_TABLE_MOD_FAILED : table_mod_failed_error_msg.unpack,
-    const.OFPET_SWITCH_CONFIG_FAILED : switch_config_failed_error_msg.unpack,
-}
-
-flow_mod_parsers = {
-    const.OFPFC_ADD : flow_add.unpack,
-    const.OFPFC_MODIFY : flow_modify.unpack,
-    const.OFPFC_MODIFY_STRICT : flow_modify_strict.unpack,
-    const.OFPFC_DELETE : flow_delete.unpack,
-    const.OFPFC_DELETE_STRICT : flow_delete_strict.unpack,
-}
-
-group_mod_parsers = {
-    const.OFPGC_ADD : group_add.unpack,
-    const.OFPGC_MODIFY : group_modify.unpack,
-    const.OFPGC_DELETE : group_delete.unpack,
-}
-
-stats_reply_parsers = {
-    const.OFPST_DESC : desc_stats_reply.unpack,
-    const.OFPST_FLOW : flow_stats_reply.unpack,
-    const.OFPST_AGGREGATE : aggregate_stats_reply.unpack,
-    const.OFPST_TABLE : table_stats_reply.unpack,
-    const.OFPST_PORT : port_stats_reply.unpack,
-    const.OFPST_QUEUE : queue_stats_reply.unpack,
-    const.OFPST_EXPERIMENTER : parse_experimenter_stats_reply,
-    const.OFPST_GROUP : group_stats_reply.unpack,
-    const.OFPST_GROUP_DESC : group_desc_stats_reply.unpack,
-}
-
-stats_request_parsers = {
-    const.OFPST_DESC : desc_stats_request.unpack,
-    const.OFPST_FLOW : flow_stats_request.unpack,
-    const.OFPST_AGGREGATE : aggregate_stats_request.unpack,
-    const.OFPST_TABLE : table_stats_request.unpack,
-    const.OFPST_PORT : port_stats_request.unpack,
-    const.OFPST_QUEUE : queue_stats_request.unpack,
-    const.OFPST_EXPERIMENTER : parse_experimenter_stats_request,
-    const.OFPST_GROUP : group_stats_request.unpack,
-    const.OFPST_GROUP_DESC : group_desc_stats_request.unpack,
-}
-
-experimenter_parsers = {
-    6035143 : {
-        22: bsn_bw_clear_data_reply.unpack,
-        21: bsn_bw_clear_data_request.unpack,
-        20: bsn_bw_enable_get_reply.unpack,
-        19: bsn_bw_enable_get_request.unpack,
-        23: bsn_bw_enable_set_reply.unpack,
-        18: bsn_bw_enable_set_request.unpack,
-        10: bsn_get_interfaces_reply.unpack,
-        9: bsn_get_interfaces_request.unpack,
-        5: bsn_get_mirroring_reply.unpack,
-        4: bsn_get_mirroring_request.unpack,
-        34: bsn_pdu_rx_reply.unpack,
-        33: bsn_pdu_rx_request.unpack,
-        35: bsn_pdu_rx_timeout.unpack,
-        32: bsn_pdu_tx_reply.unpack,
-        31: bsn_pdu_tx_request.unpack,
-        3: bsn_set_mirroring.unpack,
-        25: bsn_set_pktin_suppression_reply.unpack,
-        11: bsn_set_pktin_suppression_request.unpack,
-        16: bsn_virtual_port_create_reply.unpack,
-        15: bsn_virtual_port_create_request.unpack,
-        26: bsn_virtual_port_remove_reply.unpack,
-        17: bsn_virtual_port_remove_request.unpack,
-    },
-}
-
-experimenter_stats_request_parsers = {
-    0x005c16c7: {
-    },
-}
-
-experimenter_stats_reply_parsers = {
-    0x005c16c7: {
-    },
-}
+    return message.unpack(loxi.generic_util.OFReader(buf))
diff --git a/src/python/loxi/of11/util.py b/src/python/loxi/of11/util.py
index a29545c..74a8ad2 100644
--- a/src/python/loxi/of11/util.py
+++ b/src/python/loxi/of11/util.py
@@ -5,9 +5,12 @@
 # Automatically generated by LOXI from template util.py
 # Do not modify
 
+import struct
 import loxi
 import const
-import struct
+import common
+import action
+import instruction
 
 def pretty_mac(mac):
     return ':'.join(["%02x" % x for x in mac])
@@ -74,9 +77,6 @@
 def unpack_match_bmap(reader):
     return reader.read("!L")[0]
 
-def pack_list(values):
-    return "".join([x.pack() for x in values])
-
 MASK64 = (1 << 64) - 1
 
 def pack_bitmap_128(value):
@@ -96,3 +96,13 @@
         i += 1
         x >>= 1
     return value
+
+def unpack_list_hello_elem(reader):
+    def deserializer(reader):
+        typ, length, = reader.peek('!HH')
+        reader = reader.slice(length)
+        try:
+            return common.hello_elem.unpack(reader)
+        except loxi.ProtocolError:
+            return None
+    return [x for x in loxi.generic_util.unpack_list(reader, deserializer) if x != None]
diff --git a/src/python/loxi/of12/action.py b/src/python/loxi/of12/action.py
index 141d118..7a93a43 100644
--- a/src/python/loxi/of12/action.py
+++ b/src/python/loxi/of12/action.py
@@ -3,28 +3,61 @@
 # 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 action.py
+# Automatically generated by LOXI from template module.py
 # Do not modify
 
 import struct
+import loxi
 import const
+import common
+import action
+import instruction
+import oxm
 import util
 import loxi.generic_util
-import loxi
-import oxm # for unpack
 
-def unpack_list(reader):
-    def deserializer(reader, typ):
-        parser = parsers.get(typ)
-        if not parser: raise loxi.ProtocolError("unknown action type %d" % typ)
-        return parser(reader)
-    return loxi.generic_util.unpack_list_tlv16(reader, deserializer)
+class action(loxi.OFObject):
+    subtypes = {}
 
-class Action(object):
-    type = None # override in subclass
-    pass
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 0)
+        try:
+            subclass = action.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown action subtype %#x" % subtype)
+        return subclass.unpack(reader)
 
-class bsn_mirror(Action):
+
+class experimenter(action):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 4)
+        try:
+            subclass = experimenter.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter action subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+action.subtypes[65535] = experimenter
+
+class bsn(experimenter):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 8)
+        try:
+            subclass = bsn.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown bsn experimenter action subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter.subtypes[6035143] = bsn
+
+class bsn_mirror(bsn):
     type = 65535
     experimenter = 6035143
     subtype = 1
@@ -59,15 +92,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_mirror()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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]
@@ -85,13 +116,6 @@
         if self.copy_stage != other.copy_stage: 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_mirror {")
         with q.group():
@@ -108,7 +132,9 @@
             q.breakable()
         q.text('}')
 
-class bsn_set_tunnel_dst(Action):
+bsn.subtypes[1] = bsn_mirror
+
+class bsn_set_tunnel_dst(bsn):
     type = 65535
     experimenter = 6035143
     subtype = 2
@@ -132,15 +158,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_set_tunnel_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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]
@@ -153,13 +177,6 @@
         if self.dst != other.dst: 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_set_tunnel_dst {")
         with q.group():
@@ -170,7 +187,9 @@
             q.breakable()
         q.text('}')
 
-class copy_ttl_in(Action):
+bsn.subtypes[2] = bsn_set_tunnel_dst
+
+class copy_ttl_in(action):
     type = 12
 
     def __init__(self):
@@ -186,15 +205,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = copy_ttl_in()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 12)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         return obj
 
@@ -202,13 +219,6 @@
         if type(self) != type(other): 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("copy_ttl_in {")
         with q.group():
@@ -217,7 +227,9 @@
             q.breakable()
         q.text('}')
 
-class copy_ttl_out(Action):
+action.subtypes[12] = copy_ttl_in
+
+class copy_ttl_out(action):
     type = 11
 
     def __init__(self):
@@ -233,15 +245,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = copy_ttl_out()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 11)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         return obj
 
@@ -249,13 +259,6 @@
         if type(self) != type(other): 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("copy_ttl_out {")
         with q.group():
@@ -264,7 +267,9 @@
             q.breakable()
         q.text('}')
 
-class dec_mpls_ttl(Action):
+action.subtypes[11] = copy_ttl_out
+
+class dec_mpls_ttl(action):
     type = 16
 
     def __init__(self):
@@ -280,15 +285,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = dec_mpls_ttl()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 16)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         return obj
 
@@ -296,13 +299,6 @@
         if type(self) != type(other): 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("dec_mpls_ttl {")
         with q.group():
@@ -311,7 +307,9 @@
             q.breakable()
         q.text('}')
 
-class dec_nw_ttl(Action):
+action.subtypes[16] = dec_mpls_ttl
+
+class dec_nw_ttl(action):
     type = 24
 
     def __init__(self):
@@ -327,15 +325,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = dec_nw_ttl()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 24)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         return obj
 
@@ -343,13 +339,6 @@
         if type(self) != type(other): 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("dec_nw_ttl {")
         with q.group():
@@ -358,7 +347,9 @@
             q.breakable()
         q.text('}')
 
-class group(Action):
+action.subtypes[24] = dec_nw_ttl
+
+class group(action):
     type = 22
 
     def __init__(self, group_id=None):
@@ -378,15 +369,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = group()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 22)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.group_id = reader.read("!L")[0]
         return obj
 
@@ -395,13 +384,6 @@
         if self.group_id != other.group_id: 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 {")
         with q.group():
@@ -412,7 +394,23 @@
             q.breakable()
         q.text('}')
 
-class nicira_dec_ttl(Action):
+action.subtypes[22] = group
+
+class nicira(experimenter):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 8)
+        try:
+            subclass = nicira.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown nicira experimenter action subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter.subtypes[8992] = nicira
+
+class nicira_dec_ttl(nicira):
     type = 65535
     experimenter = 8992
     subtype = 18
@@ -433,15 +431,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = nicira_dec_ttl()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 8992)
         _subtype = reader.read("!H")[0]
@@ -454,13 +450,6 @@
         if type(self) != type(other): 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("nicira_dec_ttl {")
         with q.group():
@@ -469,7 +458,9 @@
             q.breakable()
         q.text('}')
 
-class output(Action):
+nicira.subtypes[18] = nicira_dec_ttl
+
+class output(action):
     type = 0
 
     def __init__(self, port=None, max_len=None):
@@ -495,15 +486,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = output()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 0)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.port = util.unpack_port_no(reader)
         obj.max_len = reader.read("!H")[0]
         reader.skip(6)
@@ -515,13 +504,6 @@
         if self.max_len != other.max_len: 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("output {")
         with q.group():
@@ -535,7 +517,9 @@
             q.breakable()
         q.text('}')
 
-class pop_mpls(Action):
+action.subtypes[0] = output
+
+class pop_mpls(action):
     type = 20
 
     def __init__(self, ethertype=None):
@@ -556,15 +540,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = pop_mpls()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 20)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.ethertype = reader.read("!H")[0]
         reader.skip(2)
         return obj
@@ -574,13 +556,6 @@
         if self.ethertype != other.ethertype: 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("pop_mpls {")
         with q.group():
@@ -591,7 +566,9 @@
             q.breakable()
         q.text('}')
 
-class pop_vlan(Action):
+action.subtypes[20] = pop_mpls
+
+class pop_vlan(action):
     type = 18
 
     def __init__(self):
@@ -607,15 +584,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = pop_vlan()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 18)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         return obj
 
@@ -623,13 +598,6 @@
         if type(self) != type(other): 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("pop_vlan {")
         with q.group():
@@ -638,7 +606,9 @@
             q.breakable()
         q.text('}')
 
-class push_mpls(Action):
+action.subtypes[18] = pop_vlan
+
+class push_mpls(action):
     type = 19
 
     def __init__(self, ethertype=None):
@@ -659,15 +629,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = push_mpls()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 19)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.ethertype = reader.read("!H")[0]
         reader.skip(2)
         return obj
@@ -677,13 +645,6 @@
         if self.ethertype != other.ethertype: 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("push_mpls {")
         with q.group():
@@ -694,7 +655,9 @@
             q.breakable()
         q.text('}')
 
-class push_vlan(Action):
+action.subtypes[19] = push_mpls
+
+class push_vlan(action):
     type = 17
 
     def __init__(self, ethertype=None):
@@ -715,15 +678,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = push_vlan()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 17)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.ethertype = reader.read("!H")[0]
         reader.skip(2)
         return obj
@@ -733,13 +694,6 @@
         if self.ethertype != other.ethertype: 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("push_vlan {")
         with q.group():
@@ -750,7 +704,9 @@
             q.breakable()
         q.text('}')
 
-class set_field(Action):
+action.subtypes[17] = push_vlan
+
+class set_field(action):
     type = 25
 
     def __init__(self, field=None):
@@ -772,17 +728,14 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_field()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 25)
         _len = reader.read("!H")[0]
-        obj.field = oxm.unpack(reader)
-        reader.skip_align()
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        obj.field = oxm.oxm.unpack(reader)
         return obj
 
     def __eq__(self, other):
@@ -790,13 +743,6 @@
         if self.field != other.field: 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("set_field {")
         with q.group():
@@ -807,7 +753,9 @@
             q.breakable()
         q.text('}')
 
-class set_mpls_ttl(Action):
+action.subtypes[25] = set_field
+
+class set_mpls_ttl(action):
     type = 15
 
     def __init__(self, mpls_ttl=None):
@@ -828,15 +776,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_mpls_ttl()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 15)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.mpls_ttl = reader.read("!B")[0]
         reader.skip(3)
         return obj
@@ -846,13 +792,6 @@
         if self.mpls_ttl != other.mpls_ttl: 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("set_mpls_ttl {")
         with q.group():
@@ -863,7 +802,9 @@
             q.breakable()
         q.text('}')
 
-class set_nw_ttl(Action):
+action.subtypes[15] = set_mpls_ttl
+
+class set_nw_ttl(action):
     type = 23
 
     def __init__(self, nw_ttl=None):
@@ -884,15 +825,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_nw_ttl()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 23)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.nw_ttl = reader.read("!B")[0]
         reader.skip(3)
         return obj
@@ -902,13 +841,6 @@
         if self.nw_ttl != other.nw_ttl: 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("set_nw_ttl {")
         with q.group():
@@ -919,7 +851,9 @@
             q.breakable()
         q.text('}')
 
-class set_queue(Action):
+action.subtypes[23] = set_nw_ttl
+
+class set_queue(action):
     type = 21
 
     def __init__(self, queue_id=None):
@@ -939,15 +873,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_queue()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 21)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.queue_id = reader.read("!L")[0]
         return obj
 
@@ -956,13 +888,6 @@
         if self.queue_id != other.queue_id: 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("set_queue {")
         with q.group():
@@ -973,45 +898,6 @@
             q.breakable()
         q.text('}')
 
+action.subtypes[21] = set_queue
 
-def parse_experimenter(reader):
-    experimenter, = reader.peek("!4xL")
-    if experimenter == 0x005c16c7: # Big Switch Networks
-        subtype, = reader.peek("!8xL")
-    elif experimenter == 0x00002320: # Nicira
-        subtype, = reader.peek("!8xH")
-    else:
-        raise loxi.ProtocolError("unexpected experimenter id %#x" % experimenter)
 
-    if subtype in experimenter_parsers[experimenter]:
-        return experimenter_parsers[experimenter][subtype](reader)
-    else:
-        raise loxi.ProtocolError("unexpected BSN experimenter subtype %#x" % subtype)
-
-parsers = {
-    const.OFPAT_OUTPUT : output.unpack,
-    const.OFPAT_COPY_TTL_OUT : copy_ttl_out.unpack,
-    const.OFPAT_COPY_TTL_IN : copy_ttl_in.unpack,
-    const.OFPAT_SET_MPLS_TTL : set_mpls_ttl.unpack,
-    const.OFPAT_DEC_MPLS_TTL : dec_mpls_ttl.unpack,
-    const.OFPAT_PUSH_VLAN : push_vlan.unpack,
-    const.OFPAT_POP_VLAN : pop_vlan.unpack,
-    const.OFPAT_PUSH_MPLS : push_mpls.unpack,
-    const.OFPAT_POP_MPLS : pop_mpls.unpack,
-    const.OFPAT_SET_QUEUE : set_queue.unpack,
-    const.OFPAT_GROUP : group.unpack,
-    const.OFPAT_SET_NW_TTL : set_nw_ttl.unpack,
-    const.OFPAT_DEC_NW_TTL : dec_nw_ttl.unpack,
-    const.OFPAT_SET_FIELD : set_field.unpack,
-    const.OFPAT_EXPERIMENTER : parse_experimenter,
-}
-
-experimenter_parsers = {
-    8992 : {
-        18: nicira_dec_ttl.unpack,
-    },
-    6035143 : {
-        1: bsn_mirror.unpack,
-        2: bsn_set_tunnel_dst.unpack,
-    },
-}
diff --git a/src/python/loxi/of12/common.py b/src/python/loxi/of12/common.py
index 3956aec..0b64bd6 100644
--- a/src/python/loxi/of12/common.py
+++ b/src/python/loxi/of12/common.py
@@ -2,63 +2,21 @@
 # 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 loxi
 import const
+import common
+import action
+import instruction
+import oxm
 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 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:
@@ -89,12 +47,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")
@@ -110,13 +64,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():
@@ -136,7 +83,21 @@
             q.breakable()
         q.text('}')
 
-class bsn_vport_q_in_q(object):
+
+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):
@@ -181,15 +142,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]
@@ -208,13 +167,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():
@@ -240,7 +192,9 @@
             q.breakable()
         q.text('}')
 
-class bucket(object):
+bsn_vport.subtypes[0] = bsn_vport_q_in_q
+
+class bucket(loxi.OFObject):
 
     def __init__(self, weight=None, watch_port=None, watch_group=None, actions=None):
         if weight != None:
@@ -268,24 +222,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):
@@ -296,13 +248,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():
@@ -322,7 +267,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:
@@ -342,12 +288,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
@@ -358,13 +300,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():
@@ -378,7 +313,8 @@
             q.breakable()
         q.text('}')
 
-class flow_stats_entry(object):
+
+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, cookie=None, packet_count=None, byte_count=None, match=None, instructions=None):
         if table_id != None:
@@ -442,19 +378,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]
@@ -467,7 +401,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):
@@ -485,13 +419,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():
@@ -532,7 +459,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:
@@ -555,23 +483,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):
@@ -581,13 +507,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():
@@ -604,7 +523,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, bucket_stats=None):
         if group_id != None:
@@ -638,19 +558,17 @@
         packed.append('\x00' * 4)
         packed.append(struct.pack("!Q", self.packet_count))
         packed.append(struct.pack("!Q", self.byte_count))
-        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]
@@ -669,13 +587,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():
@@ -698,7 +609,8 @@
             q.breakable()
         q.text('}')
 
-class match_v3(object):
+
+class match_v3(loxi.OFObject):
     type = 1
 
     def __init__(self, oxm_list=None):
@@ -712,24 +624,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):
@@ -737,13 +647,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():
@@ -754,7 +657,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:
@@ -777,23 +681,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):
@@ -803,13 +705,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():
@@ -826,7 +721,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:
@@ -893,12 +789,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'))
@@ -929,13 +821,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():
@@ -976,7 +861,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):
         if port_no != None:
@@ -1052,12 +938,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]
@@ -1091,13 +973,6 @@
         if self.collisions != other.collisions: 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():
@@ -1144,7 +1019,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):
@@ -1166,15 +1069,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)
@@ -1185,13 +1086,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():
@@ -1202,7 +1096,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):
@@ -1224,15 +1120,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)
@@ -1243,13 +1137,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():
@@ -1260,7 +1147,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):
         if port_no != None:
@@ -1295,12 +1184,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]
@@ -1317,13 +1202,6 @@
         if self.tx_errors != other.tx_errors: 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():
@@ -1346,7 +1224,8 @@
             q.breakable()
         q.text('}')
 
-class table_stats_entry(object):
+
+class table_stats_entry(loxi.OFObject):
 
     def __init__(self, table_id=None, name=None, match=None, wildcards=None, write_actions=None, apply_actions=None, write_setfields=None, apply_setfields=None, metadata_match=None, metadata_write=None, instructions=None, config=None, max_entries=None, active_count=None, lookup_count=None, matched_count=None):
         if table_id != None:
@@ -1437,12 +1316,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(7)
         obj.name = reader.read("!32s")[0].rstrip("\x00")
@@ -1482,13 +1357,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():
@@ -1545,4 +1413,5 @@
         q.text('}')
 
 
+
 match = match_v3
diff --git a/src/python/loxi/of12/instruction.py b/src/python/loxi/of12/instruction.py
index 38bcdb6..e4472cd 100644
--- a/src/python/loxi/of12/instruction.py
+++ b/src/python/loxi/of12/instruction.py
@@ -3,28 +3,33 @@
 # 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 instruction.py
+# Automatically generated by LOXI from template module.py
 # Do not modify
 
 import struct
-import action
+import loxi
 import const
+import common
+import action
+import instruction
+import oxm
 import util
 import loxi.generic_util
-import loxi
 
-def unpack_list(reader):
-    def deserializer(reader, typ):
-        parser = parsers.get(typ)
-        if not parser: raise loxi.ProtocolError("unknown instruction type %d" % typ)
-        return parser(reader)
-    return loxi.generic_util.unpack_list_tlv16(reader, deserializer)
+class instruction(loxi.OFObject):
+    subtypes = {}
 
-class Instruction(object):
-    type = None # override in subclass
-    pass
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 0)
+        try:
+            subclass = instruction.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown instruction subtype %#x" % subtype)
+        return subclass.unpack(reader)
 
-class apply_actions(Instruction):
+
+class apply_actions(instruction):
     type = 4
 
     def __init__(self, actions=None):
@@ -39,23 +44,21 @@
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
         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[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = 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 == 4)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         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):
@@ -63,13 +66,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("apply_actions {")
         with q.group():
@@ -80,7 +76,9 @@
             q.breakable()
         q.text('}')
 
-class clear_actions(Instruction):
+instruction.subtypes[4] = apply_actions
+
+class clear_actions(instruction):
     type = 5
 
     def __init__(self):
@@ -96,15 +94,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = clear_actions()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 5)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         return obj
 
@@ -112,13 +108,6 @@
         if type(self) != type(other): 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("clear_actions {")
         with q.group():
@@ -127,7 +116,23 @@
             q.breakable()
         q.text('}')
 
-class goto_table(Instruction):
+instruction.subtypes[5] = clear_actions
+
+class experimenter(instruction):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 4)
+        try:
+            subclass = experimenter.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter instruction subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+instruction.subtypes[65535] = experimenter
+
+class goto_table(instruction):
     type = 1
 
     def __init__(self, table_id=None):
@@ -148,15 +153,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = goto_table()
-        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))
         obj.table_id = reader.read("!B")[0]
         reader.skip(3)
         return obj
@@ -166,13 +169,6 @@
         if self.table_id != other.table_id: 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("goto_table {")
         with q.group():
@@ -183,7 +179,9 @@
             q.breakable()
         q.text('}')
 
-class write_actions(Instruction):
+instruction.subtypes[1] = goto_table
+
+class write_actions(instruction):
     type = 3
 
     def __init__(self, actions=None):
@@ -198,23 +196,21 @@
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
         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[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = 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 == 3)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         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):
@@ -222,13 +218,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("write_actions {")
         with q.group():
@@ -239,7 +228,9 @@
             q.breakable()
         q.text('}')
 
-class write_metadata(Instruction):
+instruction.subtypes[3] = write_actions
+
+class write_metadata(instruction):
     type = 2
 
     def __init__(self, metadata=None, metadata_mask=None):
@@ -265,15 +256,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = write_metadata()
-        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.metadata = reader.read("!Q")[0]
         obj.metadata_mask = reader.read("!Q")[0]
@@ -285,13 +274,6 @@
         if self.metadata_mask != other.metadata_mask: 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("write_metadata {")
         with q.group():
@@ -305,26 +287,6 @@
             q.breakable()
         q.text('}')
 
+instruction.subtypes[2] = write_metadata
 
-def parse_experimenter(reader):
-    experimenter, = reader.peek("!4xL")
-    if experimenter == 0x005c16c7: # Big Switch Networks
-        subtype, = reader.peek("!8xL")
-    else:
-        raise loxi.ProtocolError("unexpected experimenter id %#x" % experimenter)
 
-    if subtype in experimenter_parsers[experimenter]:
-        return experimenter_parsers[experimenter][subtype](reader)
-    else:
-        raise loxi.ProtocolError("unexpected experimenter id %#x subtype %#x" % (experimenter, subtype))
-
-parsers = {
-    const.OFPIT_GOTO_TABLE : goto_table.unpack,
-    const.OFPIT_WRITE_METADATA : write_metadata.unpack,
-    const.OFPIT_WRITE_ACTIONS : write_actions.unpack,
-    const.OFPIT_APPLY_ACTIONS : apply_actions.unpack,
-    const.OFPIT_CLEAR_ACTIONS : clear_actions.unpack,
-}
-
-experimenter_parsers = {
-}
diff --git a/src/python/loxi/of12/message.py b/src/python/loxi/of12/message.py
index a5956bc..72dad2a 100644
--- a/src/python/loxi/of12/message.py
+++ b/src/python/loxi/of12/message.py
@@ -3,30 +3,56 @@
 # 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 message.py
+# Automatically generated by LOXI from template module.py
 # Do not modify
 
 import struct
 import loxi
 import const
 import common
-import action # for unpack_list
-import instruction # for unpack_list
+import action
+import instruction
+import oxm
 import util
 import loxi.generic_util
 
-class Message(object):
-    version = const.OFP_VERSION
-    type = None # override in subclass
-    xid = None
+class message(loxi.OFObject):
+    subtypes = {}
 
-class aggregate_stats_reply(Message):
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('B', 1)
+        try:
+            subclass = message.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+
+class stats_reply(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 8)
+        try:
+            subclass = stats_reply.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown stats_reply message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[19] = stats_reply
+
+class aggregate_stats_reply(stats_reply):
     version = 3
     type = 19
     stats_type = 2
 
     def __init__(self, xid=None, flags=None, packet_count=None, byte_count=None, flow_count=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -43,6 +69,7 @@
             self.flow_count = flow_count
         else:
             self.flow_count = 0
+        return
 
     def pack(self):
         packed = []
@@ -62,18 +89,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = aggregate_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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 == 2)
@@ -87,8 +111,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.packet_count != other.packet_count: return False
@@ -96,16 +118,6 @@
         if self.flow_count != other.flow_count: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("aggregate_stats_reply {")
         with q.group():
@@ -131,13 +143,32 @@
             q.breakable()
         q.text('}')
 
-class aggregate_stats_request(Message):
+stats_reply.subtypes[2] = aggregate_stats_reply
+
+class stats_request(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 8)
+        try:
+            subclass = stats_request.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown stats_request message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[18] = stats_request
+
+class aggregate_stats_request(stats_request):
     version = 3
     type = 18
     stats_type = 2
 
     def __init__(self, xid=None, flags=None, table_id=None, out_port=None, out_group=None, cookie=None, cookie_mask=None, match=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -166,6 +197,7 @@
             self.match = match
         else:
             self.match = common.match()
+        return
 
     def pack(self):
         packed = []
@@ -189,18 +221,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = aggregate_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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 == 2)
@@ -218,8 +247,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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
@@ -230,16 +257,6 @@
         if self.match != other.match: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("aggregate_stats_request {")
         with q.group():
@@ -274,13 +291,32 @@
             q.breakable()
         q.text('}')
 
-class bad_action_error_msg(Message):
+stats_request.subtypes[2] = aggregate_stats_request
+
+class error_msg(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 8)
+        try:
+            subclass = error_msg.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown error_msg message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[1] = error_msg
+
+class bad_action_error_msg(error_msg):
     version = 3
     type = 1
     err_type = 2
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -289,6 +325,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -304,18 +341,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bad_action_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 2)
@@ -325,23 +359,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bad_action_error_msg {")
         with q.group():
@@ -361,13 +383,18 @@
             q.breakable()
         q.text('}')
 
-class bad_instruction_error_msg(Message):
+error_msg.subtypes[2] = bad_action_error_msg
+
+class bad_instruction_error_msg(error_msg):
     version = 3
     type = 1
     err_type = 3
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -376,6 +403,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -391,18 +419,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bad_instruction_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 3)
@@ -412,23 +437,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bad_instruction_error_msg {")
         with q.group():
@@ -448,13 +461,18 @@
             q.breakable()
         q.text('}')
 
-class bad_match_error_msg(Message):
+error_msg.subtypes[3] = bad_instruction_error_msg
+
+class bad_match_error_msg(error_msg):
     version = 3
     type = 1
     err_type = 4
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -463,6 +481,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -478,18 +497,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bad_match_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 4)
@@ -499,23 +515,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bad_match_error_msg {")
         with q.group():
@@ -535,13 +539,18 @@
             q.breakable()
         q.text('}')
 
-class bad_request_error_msg(Message):
+error_msg.subtypes[4] = bad_match_error_msg
+
+class bad_request_error_msg(error_msg):
     version = 3
     type = 1
     err_type = 1
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -550,6 +559,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -565,18 +575,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bad_request_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 1)
@@ -586,23 +593,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bad_request_error_msg {")
         with q.group():
@@ -622,12 +617,18 @@
             q.breakable()
         q.text('}')
 
-class barrier_reply(Message):
+error_msg.subtypes[1] = bad_request_error_msg
+
+class barrier_reply(message):
     version = 3
     type = 21
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -640,38 +641,23 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = barrier_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 21)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("barrier_reply {")
         with q.group():
@@ -685,12 +671,18 @@
             q.breakable()
         q.text('}')
 
-class barrier_request(Message):
+message.subtypes[21] = barrier_reply
+
+class barrier_request(message):
     version = 3
     type = 20
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -703,38 +695,23 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = barrier_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 20)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("barrier_request {")
         with q.group():
@@ -748,18 +725,52 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_clear_data_reply(Message):
+message.subtypes[20] = barrier_request
+
+class experimenter(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 8)
+        try:
+            subclass = experimenter.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[4] = experimenter
+
+class bsn_header(experimenter):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 12)
+        try:
+            subclass = bsn_header.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown bsn_header experimenter message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter.subtypes[6035143] = bsn_header
+
+class bsn_bw_clear_data_reply(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 22
 
     def __init__(self, xid=None, status=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
             self.status = 0
+        return
 
     def pack(self):
         packed = []
@@ -775,18 +786,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_clear_data_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -797,22 +805,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_clear_data_reply {")
         with q.group():
@@ -829,14 +825,20 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_clear_data_request(Message):
+bsn_header.subtypes[22] = bsn_bw_clear_data_reply
+
+class bsn_bw_clear_data_request(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 21
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -851,18 +853,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_clear_data_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -872,21 +871,9 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_clear_data_request {")
         with q.group():
@@ -900,18 +887,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_enable_get_reply(Message):
+bsn_header.subtypes[21] = bsn_bw_clear_data_request
+
+class bsn_bw_enable_get_reply(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 20
 
     def __init__(self, xid=None, enabled=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if enabled != None:
             self.enabled = enabled
         else:
             self.enabled = 0
+        return
 
     def pack(self):
         packed = []
@@ -927,18 +920,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_enable_get_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -949,22 +939,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.enabled != other.enabled: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_enable_get_reply {")
         with q.group():
@@ -981,14 +959,20 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_enable_get_request(Message):
+bsn_header.subtypes[20] = bsn_bw_enable_get_reply
+
+class bsn_bw_enable_get_request(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 19
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -1003,18 +987,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_enable_get_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -1024,21 +1005,9 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_enable_get_request {")
         with q.group():
@@ -1052,14 +1021,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_enable_set_reply(Message):
+bsn_header.subtypes[19] = bsn_bw_enable_get_request
+
+class bsn_bw_enable_set_reply(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 23
 
     def __init__(self, xid=None, enable=None, status=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if enable != None:
             self.enable = enable
         else:
@@ -1068,6 +1042,7 @@
             self.status = status
         else:
             self.status = 0
+        return
 
     def pack(self):
         packed = []
@@ -1084,18 +1059,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_enable_set_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -1107,23 +1079,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.enable != other.enable: return False
         if self.status != other.status: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_enable_set_reply {")
         with q.group():
@@ -1143,18 +1103,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_enable_set_request(Message):
+bsn_header.subtypes[23] = bsn_bw_enable_set_reply
+
+class bsn_bw_enable_set_request(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 18
 
     def __init__(self, xid=None, enable=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if enable != None:
             self.enable = enable
         else:
             self.enable = 0
+        return
 
     def pack(self):
         packed = []
@@ -1170,18 +1136,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_enable_set_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -1192,22 +1155,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.enable != other.enable: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_enable_set_request {")
         with q.group():
@@ -1224,18 +1175,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_get_interfaces_reply(Message):
+bsn_header.subtypes[18] = bsn_bw_enable_set_request
+
+class bsn_get_interfaces_reply(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 10
 
     def __init__(self, xid=None, interfaces=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if interfaces != None:
             self.interfaces = interfaces
         else:
             self.interfaces = []
+        return
 
     def pack(self):
         packed = []
@@ -1245,24 +1202,21 @@
         packed.append(struct.pack("!L", self.xid))
         packed.append(struct.pack("!L", self.experimenter))
         packed.append(struct.pack("!L", self.subtype))
-        packed.append(util.pack_list(self.interfaces))
+        packed.append(loxi.generic_util.pack_list(self.interfaces))
         length = sum([len(x) for x in packed])
         packed[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_get_interfaces_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -1273,22 +1227,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.interfaces != other.interfaces: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_get_interfaces_reply {")
         with q.group():
@@ -1305,14 +1247,20 @@
             q.breakable()
         q.text('}')
 
-class bsn_get_interfaces_request(Message):
+bsn_header.subtypes[10] = bsn_get_interfaces_reply
+
+class bsn_get_interfaces_request(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 9
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -1327,18 +1275,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_get_interfaces_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -1348,21 +1293,9 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_get_interfaces_request {")
         with q.group():
@@ -1376,18 +1309,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_get_mirroring_reply(Message):
+bsn_header.subtypes[9] = bsn_get_interfaces_request
+
+class bsn_get_mirroring_reply(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 5
 
     def __init__(self, xid=None, report_mirror_ports=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if report_mirror_ports != None:
             self.report_mirror_ports = report_mirror_ports
         else:
             self.report_mirror_ports = 0
+        return
 
     def pack(self):
         packed = []
@@ -1404,18 +1343,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_get_mirroring_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -1427,22 +1363,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.report_mirror_ports != other.report_mirror_ports: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_get_mirroring_reply {")
         with q.group():
@@ -1459,18 +1383,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_get_mirroring_request(Message):
+bsn_header.subtypes[5] = bsn_get_mirroring_reply
+
+class bsn_get_mirroring_request(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 4
 
     def __init__(self, xid=None, report_mirror_ports=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if report_mirror_ports != None:
             self.report_mirror_ports = report_mirror_ports
         else:
             self.report_mirror_ports = 0
+        return
 
     def pack(self):
         packed = []
@@ -1487,18 +1417,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_get_mirroring_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -1510,22 +1437,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.report_mirror_ports != other.report_mirror_ports: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_get_mirroring_request {")
         with q.group():
@@ -1542,14 +1457,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_pdu_rx_reply(Message):
+bsn_header.subtypes[4] = bsn_get_mirroring_request
+
+class bsn_pdu_rx_reply(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 34
 
     def __init__(self, xid=None, status=None, port_no=None, slot_num=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
@@ -1562,6 +1482,7 @@
             self.slot_num = slot_num
         else:
             self.slot_num = 0
+        return
 
     def pack(self):
         packed = []
@@ -1579,18 +1500,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_pdu_rx_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -1603,24 +1521,12 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         if self.port_no != other.port_no: return False
         if self.slot_num != other.slot_num: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_pdu_rx_reply {")
         with q.group():
@@ -1643,14 +1549,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_pdu_rx_request(Message):
+bsn_header.subtypes[34] = bsn_pdu_rx_reply
+
+class bsn_pdu_rx_request(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 33
 
     def __init__(self, xid=None, timeout_ms=None, port_no=None, slot_num=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if timeout_ms != None:
             self.timeout_ms = timeout_ms
         else:
@@ -1667,6 +1578,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -1686,18 +1598,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_pdu_rx_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -1712,8 +1621,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.timeout_ms != other.timeout_ms: return False
         if self.port_no != other.port_no: return False
@@ -1721,16 +1628,6 @@
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_pdu_rx_request {")
         with q.group():
@@ -1756,14 +1653,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_pdu_rx_timeout(Message):
+bsn_header.subtypes[33] = bsn_pdu_rx_request
+
+class bsn_pdu_rx_timeout(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 35
 
     def __init__(self, xid=None, port_no=None, slot_num=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if port_no != None:
             self.port_no = port_no
         else:
@@ -1772,6 +1674,7 @@
             self.slot_num = slot_num
         else:
             self.slot_num = 0
+        return
 
     def pack(self):
         packed = []
@@ -1788,18 +1691,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_pdu_rx_timeout()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -1811,23 +1711,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.port_no != other.port_no: return False
         if self.slot_num != other.slot_num: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_pdu_rx_timeout {")
         with q.group():
@@ -1847,14 +1735,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_pdu_tx_reply(Message):
+bsn_header.subtypes[35] = bsn_pdu_rx_timeout
+
+class bsn_pdu_tx_reply(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 32
 
     def __init__(self, xid=None, status=None, port_no=None, slot_num=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
@@ -1867,6 +1760,7 @@
             self.slot_num = slot_num
         else:
             self.slot_num = 0
+        return
 
     def pack(self):
         packed = []
@@ -1884,18 +1778,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_pdu_tx_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -1908,24 +1799,12 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         if self.port_no != other.port_no: return False
         if self.slot_num != other.slot_num: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_pdu_tx_reply {")
         with q.group():
@@ -1948,14 +1827,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_pdu_tx_request(Message):
+bsn_header.subtypes[32] = bsn_pdu_tx_reply
+
+class bsn_pdu_tx_request(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 31
 
     def __init__(self, xid=None, tx_interval_ms=None, port_no=None, slot_num=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if tx_interval_ms != None:
             self.tx_interval_ms = tx_interval_ms
         else:
@@ -1972,6 +1856,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -1991,18 +1876,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_pdu_tx_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -2017,8 +1899,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.tx_interval_ms != other.tx_interval_ms: return False
         if self.port_no != other.port_no: return False
@@ -2026,16 +1906,6 @@
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_pdu_tx_request {")
         with q.group():
@@ -2061,18 +1931,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_set_mirroring(Message):
+bsn_header.subtypes[31] = bsn_pdu_tx_request
+
+class bsn_set_mirroring(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 3
 
     def __init__(self, xid=None, report_mirror_ports=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if report_mirror_ports != None:
             self.report_mirror_ports = report_mirror_ports
         else:
             self.report_mirror_ports = 0
+        return
 
     def pack(self):
         packed = []
@@ -2089,18 +1965,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_set_mirroring()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -2112,22 +1985,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.report_mirror_ports != other.report_mirror_ports: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_set_mirroring {")
         with q.group():
@@ -2144,18 +2005,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_set_pktin_suppression_reply(Message):
+bsn_header.subtypes[3] = bsn_set_mirroring
+
+class bsn_set_pktin_suppression_reply(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 25
 
     def __init__(self, xid=None, status=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
             self.status = 0
+        return
 
     def pack(self):
         packed = []
@@ -2171,18 +2038,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_set_pktin_suppression_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -2193,22 +2057,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_set_pktin_suppression_reply {")
         with q.group():
@@ -2225,14 +2077,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_set_pktin_suppression_request(Message):
+bsn_header.subtypes[25] = bsn_set_pktin_suppression_reply
+
+class bsn_set_pktin_suppression_request(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 11
 
     def __init__(self, xid=None, enabled=None, idle_timeout=None, hard_timeout=None, priority=None, cookie=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if enabled != None:
             self.enabled = enabled
         else:
@@ -2253,6 +2110,7 @@
             self.cookie = cookie
         else:
             self.cookie = 0
+        return
 
     def pack(self):
         packed = []
@@ -2273,18 +2131,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_set_pktin_suppression_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -2300,8 +2155,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.enabled != other.enabled: return False
         if self.idle_timeout != other.idle_timeout: return False
@@ -2310,16 +2163,6 @@
         if self.cookie != other.cookie: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_set_pktin_suppression_request {")
         with q.group():
@@ -2348,14 +2191,75 @@
             q.breakable()
         q.text('}')
 
-class bsn_virtual_port_create_reply(Message):
+bsn_header.subtypes[11] = bsn_set_pktin_suppression_request
+
+class experimenter_stats_reply(stats_reply):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 16)
+        try:
+            subclass = experimenter_stats_reply.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter_stats_reply stats_reply message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+stats_reply.subtypes[65535] = experimenter_stats_reply
+
+class bsn_stats_reply(experimenter_stats_reply):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 20)
+        try:
+            subclass = bsn_stats_reply.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown bsn_stats_reply experimenter_stats_reply stats_reply message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter_stats_reply.subtypes[6035143] = bsn_stats_reply
+
+class experimenter_stats_request(stats_request):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 16)
+        try:
+            subclass = experimenter_stats_request.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter_stats_request stats_request message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+stats_request.subtypes[65535] = experimenter_stats_request
+
+class bsn_stats_request(experimenter_stats_request):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 20)
+        try:
+            subclass = bsn_stats_request.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown bsn_stats_request experimenter_stats_request stats_request message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter_stats_request.subtypes[6035143] = bsn_stats_request
+
+class bsn_virtual_port_create_reply(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 16
 
     def __init__(self, xid=None, status=None, vport_no=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
@@ -2364,6 +2268,7 @@
             self.vport_no = vport_no
         else:
             self.vport_no = 0
+        return
 
     def pack(self):
         packed = []
@@ -2380,18 +2285,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_virtual_port_create_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -2403,23 +2305,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         if self.vport_no != other.vport_no: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_virtual_port_create_reply {")
         with q.group():
@@ -2439,18 +2329,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_virtual_port_create_request(Message):
+bsn_header.subtypes[16] = bsn_virtual_port_create_reply
+
+class bsn_virtual_port_create_request(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 15
 
     def __init__(self, xid=None, vport=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if vport != None:
             self.vport = vport
         else:
             self.vport = common.bsn_vport_q_in_q()
+        return
 
     def pack(self):
         packed = []
@@ -2466,18 +2362,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_virtual_port_create_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -2488,22 +2381,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.vport != other.vport: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_virtual_port_create_request {")
         with q.group():
@@ -2520,18 +2401,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_virtual_port_remove_reply(Message):
+bsn_header.subtypes[15] = bsn_virtual_port_create_request
+
+class bsn_virtual_port_remove_reply(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 26
 
     def __init__(self, xid=None, status=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
             self.status = 0
+        return
 
     def pack(self):
         packed = []
@@ -2547,18 +2434,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_virtual_port_remove_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -2569,22 +2453,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_virtual_port_remove_reply {")
         with q.group():
@@ -2601,18 +2473,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_virtual_port_remove_request(Message):
+bsn_header.subtypes[26] = bsn_virtual_port_remove_reply
+
+class bsn_virtual_port_remove_request(bsn_header):
     version = 3
     type = 4
     experimenter = 6035143
     subtype = 17
 
     def __init__(self, xid=None, vport_no=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if vport_no != None:
             self.vport_no = vport_no
         else:
             self.vport_no = 0
+        return
 
     def pack(self):
         packed = []
@@ -2628,18 +2506,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_virtual_port_remove_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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)
@@ -2650,22 +2525,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.vport_no != other.vport_no: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_virtual_port_remove_request {")
         with q.group():
@@ -2682,13 +2545,18 @@
             q.breakable()
         q.text('}')
 
-class desc_stats_reply(Message):
+bsn_header.subtypes[17] = bsn_virtual_port_remove_request
+
+class desc_stats_reply(stats_reply):
     version = 3
     type = 19
     stats_type = 0
 
     def __init__(self, xid=None, flags=None, mfr_desc=None, hw_desc=None, sw_desc=None, serial_num=None, dp_desc=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -2713,6 +2581,7 @@
             self.dp_desc = dp_desc
         else:
             self.dp_desc = ""
+        return
 
     def pack(self):
         packed = []
@@ -2733,18 +2602,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = desc_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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 == 0)
@@ -2759,8 +2625,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.mfr_desc != other.mfr_desc: return False
@@ -2770,16 +2634,6 @@
         if self.dp_desc != other.dp_desc: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("desc_stats_reply {")
         with q.group():
@@ -2811,17 +2665,23 @@
             q.breakable()
         q.text('}')
 
-class desc_stats_request(Message):
+stats_reply.subtypes[0] = desc_stats_reply
+
+class desc_stats_request(stats_request):
     version = 3
     type = 18
     stats_type = 0
 
     def __init__(self, xid=None, flags=None):
-        self.xid = xid
+        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 = []
@@ -2837,18 +2697,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = desc_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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 == 0)
@@ -2858,22 +2715,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("desc_stats_request {")
         with q.group():
@@ -2890,16 +2735,22 @@
             q.breakable()
         q.text('}')
 
-class echo_reply(Message):
+stats_request.subtypes[0] = desc_stats_request
+
+class echo_reply(message):
     version = 3
     type = 3
 
     def __init__(self, xid=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if data != None:
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -2913,40 +2764,25 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = echo_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 3)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.data = str(reader.read_all())
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("echo_reply {")
         with q.group():
@@ -2963,16 +2799,22 @@
             q.breakable()
         q.text('}')
 
-class echo_request(Message):
+message.subtypes[3] = echo_reply
+
+class echo_request(message):
     version = 3
     type = 2
 
     def __init__(self, xid=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if data != None:
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -2986,40 +2828,25 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = echo_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 2)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.data = str(reader.read_all())
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("echo_request {")
         with q.group():
@@ -3036,13 +2863,18 @@
             q.breakable()
         q.text('}')
 
-class experimenter_error_msg(Message):
+message.subtypes[2] = echo_request
+
+class experimenter_error_msg(error_msg):
     version = 3
     type = 1
     err_type = 65535
 
     def __init__(self, xid=None, subtype=None, experimenter=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if subtype != None:
             self.subtype = subtype
         else:
@@ -3055,6 +2887,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -3071,18 +2904,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = experimenter_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 65535)
@@ -3093,24 +2923,12 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.subtype != other.subtype: return False
         if self.experimenter != other.experimenter: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("experimenter_error_msg {")
         with q.group():
@@ -3133,12 +2951,17 @@
             q.breakable()
         q.text('}')
 
-class features_reply(Message):
+error_msg.subtypes[65535] = experimenter_error_msg
+
+class features_reply(message):
     version = 3
     type = 6
 
     def __init__(self, xid=None, datapath_id=None, n_buffers=None, n_tables=None, capabilities=None, reserved=None, ports=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if datapath_id != None:
             self.datapath_id = datapath_id
         else:
@@ -3163,6 +2986,7 @@
             self.ports = ports
         else:
             self.ports = []
+        return
 
     def pack(self):
         packed = []
@@ -3176,24 +3000,21 @@
         packed.append('\x00' * 3)
         packed.append(struct.pack("!L", self.capabilities))
         packed.append(struct.pack("!L", self.reserved))
-        packed.append(util.pack_list(self.ports))
+        packed.append(loxi.generic_util.pack_list(self.ports))
         length = sum([len(x) for x in packed])
         packed[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = features_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 6)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.datapath_id = reader.read("!Q")[0]
         obj.n_buffers = reader.read("!L")[0]
@@ -3206,8 +3027,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.datapath_id != other.datapath_id: return False
         if self.n_buffers != other.n_buffers: return False
@@ -3217,16 +3036,6 @@
         if self.ports != other.ports: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("features_reply {")
         with q.group():
@@ -3258,12 +3067,18 @@
             q.breakable()
         q.text('}')
 
-class features_request(Message):
+message.subtypes[6] = features_reply
+
+class features_request(message):
     version = 3
     type = 5
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -3276,38 +3091,23 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = features_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 5)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("features_request {")
         with q.group():
@@ -3321,13 +3121,32 @@
             q.breakable()
         q.text('}')
 
-class flow_add(Message):
+message.subtypes[5] = features_request
+
+class flow_mod(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('B', 25)
+        try:
+            subclass = flow_mod.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown flow_mod message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[14] = flow_mod
+
+class flow_add(flow_mod):
     version = 3
     type = 14
     _command = 0
 
     def __init__(self, xid=None, cookie=None, cookie_mask=None, table_id=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, out_group=None, flags=None, match=None, instructions=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if cookie != None:
             self.cookie = cookie
         else:
@@ -3376,6 +3195,7 @@
             self.instructions = instructions
         else:
             self.instructions = []
+        return
 
     def pack(self):
         packed = []
@@ -3396,24 +3216,21 @@
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 2)
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_add()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 14)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.cookie = reader.read("!Q")[0]
         obj.cookie_mask = reader.read("!Q")[0]
@@ -3429,13 +3246,11 @@
         obj.flags = reader.read("!H")[0]
         reader.skip(2)
         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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.cookie != other.cookie: return False
         if self.cookie_mask != other.cookie_mask: return False
@@ -3451,16 +3266,6 @@
         if self.instructions != other.instructions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_add {")
         with q.group():
@@ -3510,13 +3315,18 @@
             q.breakable()
         q.text('}')
 
-class flow_delete(Message):
+flow_mod.subtypes[0] = flow_add
+
+class flow_delete(flow_mod):
     version = 3
     type = 14
     _command = 3
 
     def __init__(self, xid=None, cookie=None, cookie_mask=None, table_id=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, out_group=None, flags=None, match=None, instructions=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if cookie != None:
             self.cookie = cookie
         else:
@@ -3565,6 +3375,7 @@
             self.instructions = instructions
         else:
             self.instructions = []
+        return
 
     def pack(self):
         packed = []
@@ -3585,24 +3396,21 @@
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 2)
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_delete()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 14)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.cookie = reader.read("!Q")[0]
         obj.cookie_mask = reader.read("!Q")[0]
@@ -3618,13 +3426,11 @@
         obj.flags = reader.read("!H")[0]
         reader.skip(2)
         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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.cookie != other.cookie: return False
         if self.cookie_mask != other.cookie_mask: return False
@@ -3640,16 +3446,6 @@
         if self.instructions != other.instructions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_delete {")
         with q.group():
@@ -3699,13 +3495,18 @@
             q.breakable()
         q.text('}')
 
-class flow_delete_strict(Message):
+flow_mod.subtypes[3] = flow_delete
+
+class flow_delete_strict(flow_mod):
     version = 3
     type = 14
     _command = 4
 
     def __init__(self, xid=None, cookie=None, cookie_mask=None, table_id=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, out_group=None, flags=None, match=None, instructions=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if cookie != None:
             self.cookie = cookie
         else:
@@ -3754,6 +3555,7 @@
             self.instructions = instructions
         else:
             self.instructions = []
+        return
 
     def pack(self):
         packed = []
@@ -3774,24 +3576,21 @@
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 2)
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_delete_strict()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 14)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.cookie = reader.read("!Q")[0]
         obj.cookie_mask = reader.read("!Q")[0]
@@ -3807,13 +3606,11 @@
         obj.flags = reader.read("!H")[0]
         reader.skip(2)
         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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.cookie != other.cookie: return False
         if self.cookie_mask != other.cookie_mask: return False
@@ -3829,16 +3626,6 @@
         if self.instructions != other.instructions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_delete_strict {")
         with q.group():
@@ -3888,13 +3675,18 @@
             q.breakable()
         q.text('}')
 
-class flow_mod_failed_error_msg(Message):
+flow_mod.subtypes[4] = flow_delete_strict
+
+class flow_mod_failed_error_msg(error_msg):
     version = 3
     type = 1
     err_type = 5
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -3903,6 +3695,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -3918,18 +3711,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_mod_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 5)
@@ -3939,23 +3729,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_mod_failed_error_msg {")
         with q.group():
@@ -3975,13 +3753,18 @@
             q.breakable()
         q.text('}')
 
-class flow_modify(Message):
+error_msg.subtypes[5] = flow_mod_failed_error_msg
+
+class flow_modify(flow_mod):
     version = 3
     type = 14
     _command = 1
 
     def __init__(self, xid=None, cookie=None, cookie_mask=None, table_id=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, out_group=None, flags=None, match=None, instructions=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if cookie != None:
             self.cookie = cookie
         else:
@@ -4030,6 +3813,7 @@
             self.instructions = instructions
         else:
             self.instructions = []
+        return
 
     def pack(self):
         packed = []
@@ -4050,24 +3834,21 @@
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 2)
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_modify()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 14)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.cookie = reader.read("!Q")[0]
         obj.cookie_mask = reader.read("!Q")[0]
@@ -4083,13 +3864,11 @@
         obj.flags = reader.read("!H")[0]
         reader.skip(2)
         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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.cookie != other.cookie: return False
         if self.cookie_mask != other.cookie_mask: return False
@@ -4105,16 +3884,6 @@
         if self.instructions != other.instructions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_modify {")
         with q.group():
@@ -4164,13 +3933,18 @@
             q.breakable()
         q.text('}')
 
-class flow_modify_strict(Message):
+flow_mod.subtypes[1] = flow_modify
+
+class flow_modify_strict(flow_mod):
     version = 3
     type = 14
     _command = 2
 
     def __init__(self, xid=None, cookie=None, cookie_mask=None, table_id=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, out_group=None, flags=None, match=None, instructions=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if cookie != None:
             self.cookie = cookie
         else:
@@ -4219,6 +3993,7 @@
             self.instructions = instructions
         else:
             self.instructions = []
+        return
 
     def pack(self):
         packed = []
@@ -4239,24 +4014,21 @@
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 2)
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_modify_strict()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 14)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.cookie = reader.read("!Q")[0]
         obj.cookie_mask = reader.read("!Q")[0]
@@ -4272,13 +4044,11 @@
         obj.flags = reader.read("!H")[0]
         reader.skip(2)
         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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.cookie != other.cookie: return False
         if self.cookie_mask != other.cookie_mask: return False
@@ -4294,16 +4064,6 @@
         if self.instructions != other.instructions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_modify_strict {")
         with q.group():
@@ -4353,12 +4113,17 @@
             q.breakable()
         q.text('}')
 
-class flow_removed(Message):
+flow_mod.subtypes[2] = flow_modify_strict
+
+class flow_removed(message):
     version = 3
     type = 11
 
     def __init__(self, xid=None, cookie=None, priority=None, reason=None, table_id=None, duration_sec=None, duration_nsec=None, idle_timeout=None, hard_timeout=None, packet_count=None, byte_count=None, match=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if cookie != None:
             self.cookie = cookie
         else:
@@ -4403,6 +4168,7 @@
             self.match = match
         else:
             self.match = common.match()
+        return
 
     def pack(self):
         packed = []
@@ -4426,18 +4192,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_removed()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 11)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.cookie = reader.read("!Q")[0]
         obj.priority = reader.read("!H")[0]
@@ -4454,8 +4217,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.cookie != other.cookie: return False
         if self.priority != other.priority: return False
@@ -4470,16 +4231,6 @@
         if self.match != other.match: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_removed {")
         with q.group():
@@ -4526,13 +4277,18 @@
             q.breakable()
         q.text('}')
 
-class flow_stats_reply(Message):
+message.subtypes[11] = flow_removed
+
+class flow_stats_reply(stats_reply):
     version = 3
     type = 19
     stats_type = 1
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -4541,6 +4297,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -4551,51 +4308,36 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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 == 1)
         obj.flags = reader.read("!H")[0]
         reader.skip(4)
-        obj.entries = common.unpack_list_flow_stats_entry(reader)
+        obj.entries = loxi.generic_util.unpack_list(reader, common.flow_stats_entry.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_stats_reply {")
         with q.group():
@@ -4615,13 +4357,18 @@
             q.breakable()
         q.text('}')
 
-class flow_stats_request(Message):
+stats_reply.subtypes[1] = flow_stats_reply
+
+class flow_stats_request(stats_request):
     version = 3
     type = 18
     stats_type = 1
 
     def __init__(self, xid=None, flags=None, table_id=None, out_port=None, out_group=None, cookie=None, cookie_mask=None, match=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -4650,6 +4397,7 @@
             self.match = match
         else:
             self.match = common.match()
+        return
 
     def pack(self):
         packed = []
@@ -4673,18 +4421,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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 == 1)
@@ -4702,8 +4447,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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
@@ -4714,16 +4457,6 @@
         if self.match != other.match: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_stats_request {")
         with q.group():
@@ -4758,12 +4491,17 @@
             q.breakable()
         q.text('}')
 
-class get_config_reply(Message):
+stats_request.subtypes[1] = flow_stats_request
+
+class get_config_reply(message):
     version = 3
     type = 8
 
     def __init__(self, xid=None, flags=None, miss_send_len=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -4772,6 +4510,7 @@
             self.miss_send_len = miss_send_len
         else:
             self.miss_send_len = 0
+        return
 
     def pack(self):
         packed = []
@@ -4786,18 +4525,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = get_config_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 8)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.flags = reader.read("!H")[0]
         obj.miss_send_len = reader.read("!H")[0]
@@ -4805,23 +4541,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.miss_send_len != other.miss_send_len: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("get_config_reply {")
         with q.group():
@@ -4841,12 +4565,18 @@
             q.breakable()
         q.text('}')
 
-class get_config_request(Message):
+message.subtypes[8] = get_config_reply
+
+class get_config_request(message):
     version = 3
     type = 7
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -4859,38 +4589,23 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = get_config_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 7)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("get_config_request {")
         with q.group():
@@ -4904,13 +4619,32 @@
             q.breakable()
         q.text('}')
 
-class group_add(Message):
+message.subtypes[7] = get_config_request
+
+class group_mod(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 8)
+        try:
+            subclass = group_mod.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown group_mod message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[15] = group_mod
+
+class group_add(group_mod):
     version = 3
     type = 15
     command = 0
 
     def __init__(self, xid=None, group_type=None, group_id=None, buckets=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if group_type != None:
             self.group_type = group_type
         else:
@@ -4923,6 +4657,7 @@
             self.buckets = buckets
         else:
             self.buckets = []
+        return
 
     def pack(self):
         packed = []
@@ -4934,53 +4669,38 @@
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_add()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 15)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _command = reader.read("!H")[0]
         assert(_command == 0)
         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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.group_type != other.group_type: return False
         if self.group_id != other.group_id: return False
         if self.buckets != other.buckets: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_add {")
         with q.group():
@@ -5003,13 +4723,18 @@
             q.breakable()
         q.text('}')
 
-class group_delete(Message):
+group_mod.subtypes[0] = group_add
+
+class group_delete(group_mod):
     version = 3
     type = 15
     command = 2
 
     def __init__(self, xid=None, group_type=None, group_id=None, buckets=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if group_type != None:
             self.group_type = group_type
         else:
@@ -5022,6 +4747,7 @@
             self.buckets = buckets
         else:
             self.buckets = []
+        return
 
     def pack(self):
         packed = []
@@ -5033,53 +4759,38 @@
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_delete()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 15)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _command = reader.read("!H")[0]
         assert(_command == 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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.group_type != other.group_type: return False
         if self.group_id != other.group_id: return False
         if self.buckets != other.buckets: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_delete {")
         with q.group():
@@ -5102,13 +4813,18 @@
             q.breakable()
         q.text('}')
 
-class group_desc_stats_reply(Message):
+group_mod.subtypes[2] = group_delete
+
+class group_desc_stats_reply(stats_reply):
     version = 3
     type = 19
     stats_type = 7
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -5117,6 +4833,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -5127,51 +4844,36 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_desc_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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 == 7)
         obj.flags = reader.read("!H")[0]
         reader.skip(4)
-        obj.entries = common.unpack_list_group_desc_stats_entry(reader)
+        obj.entries = loxi.generic_util.unpack_list(reader, common.group_desc_stats_entry.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_desc_stats_reply {")
         with q.group():
@@ -5191,17 +4893,23 @@
             q.breakable()
         q.text('}')
 
-class group_desc_stats_request(Message):
+stats_reply.subtypes[7] = group_desc_stats_reply
+
+class group_desc_stats_request(stats_request):
     version = 3
     type = 18
     stats_type = 7
 
     def __init__(self, xid=None, flags=None):
-        self.xid = xid
+        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 = []
@@ -5217,18 +4925,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_desc_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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 == 7)
@@ -5238,22 +4943,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_desc_stats_request {")
         with q.group():
@@ -5270,13 +4963,18 @@
             q.breakable()
         q.text('}')
 
-class group_features_stats_reply(Message):
+stats_request.subtypes[7] = group_desc_stats_request
+
+class group_features_stats_reply(stats_reply):
     version = 3
     type = 19
     stats_type = 8
 
     def __init__(self, xid=None, flags=None, types=None, capabilities=None, max_groups_all=None, max_groups_select=None, max_groups_indirect=None, max_groups_ff=None, actions_all=None, actions_select=None, actions_indirect=None, actions_ff=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -5321,6 +5019,7 @@
             self.actions_ff = actions_ff
         else:
             self.actions_ff = 0
+        return
 
     def pack(self):
         packed = []
@@ -5346,18 +5045,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_features_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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 == 8)
@@ -5377,8 +5073,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.types != other.types: return False
@@ -5393,16 +5087,6 @@
         if self.actions_ff != other.actions_ff: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_features_stats_reply {")
         with q.group():
@@ -5449,17 +5133,23 @@
             q.breakable()
         q.text('}')
 
-class group_features_stats_request(Message):
+stats_reply.subtypes[8] = group_features_stats_reply
+
+class group_features_stats_request(stats_request):
     version = 3
     type = 18
     stats_type = 8
 
     def __init__(self, xid=None, flags=None):
-        self.xid = xid
+        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 = []
@@ -5475,18 +5165,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_features_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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 == 8)
@@ -5496,22 +5183,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_features_stats_request {")
         with q.group():
@@ -5528,13 +5203,18 @@
             q.breakable()
         q.text('}')
 
-class group_mod_failed_error_msg(Message):
+stats_request.subtypes[8] = group_features_stats_request
+
+class group_mod_failed_error_msg(error_msg):
     version = 3
     type = 1
     err_type = 6
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -5543,6 +5223,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -5558,18 +5239,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_mod_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 6)
@@ -5579,23 +5257,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_mod_failed_error_msg {")
         with q.group():
@@ -5615,13 +5281,18 @@
             q.breakable()
         q.text('}')
 
-class group_modify(Message):
+error_msg.subtypes[6] = group_mod_failed_error_msg
+
+class group_modify(group_mod):
     version = 3
     type = 15
     command = 1
 
     def __init__(self, xid=None, group_type=None, group_id=None, buckets=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if group_type != None:
             self.group_type = group_type
         else:
@@ -5634,6 +5305,7 @@
             self.buckets = buckets
         else:
             self.buckets = []
+        return
 
     def pack(self):
         packed = []
@@ -5645,53 +5317,38 @@
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_modify()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 15)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _command = reader.read("!H")[0]
         assert(_command == 1)
         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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.group_type != other.group_type: return False
         if self.group_id != other.group_id: return False
         if self.buckets != other.buckets: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_modify {")
         with q.group():
@@ -5714,13 +5371,18 @@
             q.breakable()
         q.text('}')
 
-class group_stats_reply(Message):
+group_mod.subtypes[1] = group_modify
+
+class group_stats_reply(stats_reply):
     version = 3
     type = 19
     stats_type = 6
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -5729,6 +5391,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -5739,51 +5402,36 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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 == 6)
         obj.flags = reader.read("!H")[0]
         reader.skip(4)
-        obj.entries = common.unpack_list_group_stats_entry(reader)
+        obj.entries = loxi.generic_util.unpack_list(reader, common.group_stats_entry.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_stats_reply {")
         with q.group():
@@ -5803,13 +5451,18 @@
             q.breakable()
         q.text('}')
 
-class group_stats_request(Message):
+stats_reply.subtypes[6] = group_stats_reply
+
+class group_stats_request(stats_request):
     version = 3
     type = 18
     stats_type = 6
 
     def __init__(self, xid=None, flags=None, group_id=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -5818,6 +5471,7 @@
             self.group_id = group_id
         else:
             self.group_id = 0
+        return
 
     def pack(self):
         packed = []
@@ -5835,18 +5489,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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 == 6)
@@ -5858,23 +5509,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.group_id != other.group_id: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_stats_request {")
         with q.group():
@@ -5894,12 +5533,18 @@
             q.breakable()
         q.text('}')
 
-class hello(Message):
+stats_request.subtypes[6] = group_stats_request
+
+class hello(message):
     version = 3
     type = 0
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -5912,38 +5557,23 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = hello()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 0)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("hello {")
         with q.group():
@@ -5957,13 +5587,18 @@
             q.breakable()
         q.text('}')
 
-class hello_failed_error_msg(Message):
+message.subtypes[0] = hello
+
+class hello_failed_error_msg(error_msg):
     version = 3
     type = 1
     err_type = 0
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -5972,6 +5607,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -5987,18 +5623,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = hello_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 0)
@@ -6008,23 +5641,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("hello_failed_error_msg {")
         with q.group():
@@ -6044,12 +5665,31 @@
             q.breakable()
         q.text('}')
 
-class packet_in(Message):
+error_msg.subtypes[0] = hello_failed_error_msg
+
+class nicira_header(experimenter):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 12)
+        try:
+            subclass = nicira_header.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown nicira_header experimenter message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter.subtypes[8992] = nicira_header
+
+class packet_in(message):
     version = 3
     type = 10
 
     def __init__(self, xid=None, buffer_id=None, total_len=None, reason=None, table_id=None, match=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if buffer_id != None:
             self.buffer_id = buffer_id
         else:
@@ -6074,6 +5714,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -6093,18 +5734,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = packet_in()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 10)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.buffer_id = reader.read("!L")[0]
         obj.total_len = reader.read("!H")[0]
@@ -6117,8 +5755,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.buffer_id != other.buffer_id: return False
         if self.total_len != other.total_len: return False
@@ -6128,16 +5764,6 @@
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("packet_in {")
         with q.group():
@@ -6169,12 +5795,17 @@
             q.breakable()
         q.text('}')
 
-class packet_out(Message):
+message.subtypes[10] = packet_in
+
+class packet_out(message):
     version = 3
     type = 13
 
     def __init__(self, xid=None, buffer_id=None, in_port=None, actions=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if buffer_id != None:
             self.buffer_id = buffer_id
         else:
@@ -6191,6 +5822,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -6202,7 +5834,7 @@
         packed.append(util.pack_port_no(self.in_port))
         packed.append(struct.pack("!H", 0)) # placeholder for actions_len at index 6
         packed.append('\x00' * 6)
-        packed.append(util.pack_list(self.actions))
+        packed.append(loxi.generic_util.pack_list(self.actions))
         packed[6] = struct.pack("!H", len(packed[-1]))
         packed.append(self.data)
         length = sum([len(x) for x in packed])
@@ -6210,31 +5842,26 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = packet_out()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 13)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.buffer_id = reader.read("!L")[0]
         obj.in_port = util.unpack_port_no(reader)
         _actions_len = reader.read("!H")[0]
         reader.skip(6)
-        obj.actions = action.unpack_list(reader.slice(_actions_len))
+        obj.actions = loxi.generic_util.unpack_list(reader.slice(_actions_len), action.action.unpack)
         obj.data = str(reader.read_all())
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.buffer_id != other.buffer_id: return False
         if self.in_port != other.in_port: return False
@@ -6242,16 +5869,6 @@
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("packet_out {")
         with q.group():
@@ -6277,12 +5894,17 @@
             q.breakable()
         q.text('}')
 
-class port_mod(Message):
+message.subtypes[13] = packet_out
+
+class port_mod(message):
     version = 3
     type = 16
 
     def __init__(self, xid=None, port_no=None, hw_addr=None, config=None, mask=None, advertise=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if port_no != None:
             self.port_no = port_no
         else:
@@ -6303,6 +5925,7 @@
             self.advertise = advertise
         else:
             self.advertise = 0
+        return
 
     def pack(self):
         packed = []
@@ -6323,18 +5946,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_mod()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 16)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.port_no = util.unpack_port_no(reader)
         reader.skip(4)
@@ -6348,8 +5968,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.port_no != other.port_no: return False
         if self.hw_addr != other.hw_addr: return False
@@ -6358,16 +5976,6 @@
         if self.advertise != other.advertise: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_mod {")
         with q.group():
@@ -6396,13 +6004,18 @@
             q.breakable()
         q.text('}')
 
-class port_mod_failed_error_msg(Message):
+message.subtypes[16] = port_mod
+
+class port_mod_failed_error_msg(error_msg):
     version = 3
     type = 1
     err_type = 7
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -6411,6 +6024,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -6426,18 +6040,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_mod_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 7)
@@ -6447,23 +6058,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_mod_failed_error_msg {")
         with q.group():
@@ -6483,13 +6082,18 @@
             q.breakable()
         q.text('}')
 
-class port_stats_reply(Message):
+error_msg.subtypes[7] = port_mod_failed_error_msg
+
+class port_stats_reply(stats_reply):
     version = 3
     type = 19
     stats_type = 4
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -6498,6 +6102,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -6508,24 +6113,21 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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 == 4)
@@ -6536,23 +6138,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_stats_reply {")
         with q.group():
@@ -6572,13 +6162,18 @@
             q.breakable()
         q.text('}')
 
-class port_stats_request(Message):
+stats_reply.subtypes[4] = port_stats_reply
+
+class port_stats_request(stats_request):
     version = 3
     type = 18
     stats_type = 4
 
     def __init__(self, xid=None, flags=None, port_no=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -6587,6 +6182,7 @@
             self.port_no = port_no
         else:
             self.port_no = 0
+        return
 
     def pack(self):
         packed = []
@@ -6604,18 +6200,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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 == 4)
@@ -6627,23 +6220,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.port_no != other.port_no: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_stats_request {")
         with q.group():
@@ -6663,12 +6244,17 @@
             q.breakable()
         q.text('}')
 
-class port_status(Message):
+stats_request.subtypes[4] = port_stats_request
+
+class port_status(message):
     version = 3
     type = 12
 
     def __init__(self, xid=None, reason=None, desc=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if reason != None:
             self.reason = reason
         else:
@@ -6677,6 +6263,7 @@
             self.desc = desc
         else:
             self.desc = common.port_desc()
+        return
 
     def pack(self):
         packed = []
@@ -6692,18 +6279,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_status()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 12)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.reason = reader.read("!B")[0]
         reader.skip(7)
@@ -6712,23 +6296,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.reason != other.reason: return False
         if self.desc != other.desc: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_status {")
         with q.group():
@@ -6748,12 +6320,17 @@
             q.breakable()
         q.text('}')
 
-class queue_get_config_reply(Message):
+message.subtypes[12] = port_status
+
+class queue_get_config_reply(message):
     version = 3
     type = 23
 
     def __init__(self, xid=None, port=None, queues=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if port != None:
             self.port = port
         else:
@@ -6762,6 +6339,7 @@
             self.queues = queues
         else:
             self.queues = []
+        return
 
     def pack(self):
         packed = []
@@ -6771,49 +6349,34 @@
         packed.append(struct.pack("!L", self.xid))
         packed.append(util.pack_port_no(self.port))
         packed.append('\x00' * 4)
-        packed.append(util.pack_list(self.queues))
+        packed.append(loxi.generic_util.pack_list(self.queues))
         length = sum([len(x) for x in packed])
         packed[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = queue_get_config_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 23)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.port = util.unpack_port_no(reader)
         reader.skip(4)
-        obj.queues = common.unpack_list_packet_queue(reader)
+        obj.queues = loxi.generic_util.unpack_list(reader, common.packet_queue.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.port != other.port: return False
         if self.queues != other.queues: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_get_config_reply {")
         with q.group():
@@ -6833,16 +6396,22 @@
             q.breakable()
         q.text('}')
 
-class queue_get_config_request(Message):
+message.subtypes[23] = queue_get_config_reply
+
+class queue_get_config_request(message):
     version = 3
     type = 22
 
     def __init__(self, xid=None, port=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if port != None:
             self.port = port
         else:
             self.port = 0
+        return
 
     def pack(self):
         packed = []
@@ -6857,18 +6426,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = queue_get_config_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 22)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.port = util.unpack_port_no(reader)
         reader.skip(4)
@@ -6876,22 +6442,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.port != other.port: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_get_config_request {")
         with q.group():
@@ -6908,13 +6462,18 @@
             q.breakable()
         q.text('}')
 
-class queue_op_failed_error_msg(Message):
+message.subtypes[22] = queue_get_config_request
+
+class queue_op_failed_error_msg(error_msg):
     version = 3
     type = 1
     err_type = 9
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -6923,6 +6482,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -6938,18 +6498,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = queue_op_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 9)
@@ -6959,23 +6516,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_op_failed_error_msg {")
         with q.group():
@@ -6995,13 +6540,18 @@
             q.breakable()
         q.text('}')
 
-class queue_stats_reply(Message):
+error_msg.subtypes[9] = queue_op_failed_error_msg
+
+class queue_stats_reply(stats_reply):
     version = 3
     type = 19
     stats_type = 5
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -7010,6 +6560,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -7020,24 +6571,21 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = queue_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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 == 5)
@@ -7048,23 +6596,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_stats_reply {")
         with q.group():
@@ -7084,13 +6620,18 @@
             q.breakable()
         q.text('}')
 
-class queue_stats_request(Message):
+stats_reply.subtypes[5] = queue_stats_reply
+
+class queue_stats_request(stats_request):
     version = 3
     type = 18
     stats_type = 5
 
     def __init__(self, xid=None, flags=None, port_no=None, queue_id=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -7103,6 +6644,7 @@
             self.queue_id = queue_id
         else:
             self.queue_id = 0
+        return
 
     def pack(self):
         packed = []
@@ -7120,18 +6662,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = queue_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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 == 5)
@@ -7143,24 +6682,12 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.port_no != other.port_no: return False
         if self.queue_id != other.queue_id: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_stats_request {")
         with q.group():
@@ -7183,12 +6710,17 @@
             q.breakable()
         q.text('}')
 
-class role_reply(Message):
+stats_request.subtypes[5] = queue_stats_request
+
+class role_reply(message):
     version = 3
     type = 25
 
     def __init__(self, xid=None, role=None, generation_id=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if role != None:
             self.role = role
         else:
@@ -7197,6 +6729,7 @@
             self.generation_id = generation_id
         else:
             self.generation_id = 0
+        return
 
     def pack(self):
         packed = []
@@ -7212,18 +6745,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = role_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 25)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.role = reader.read("!L")[0]
         reader.skip(4)
@@ -7232,23 +6762,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.role != other.role: return False
         if self.generation_id != other.generation_id: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("role_reply {")
         with q.group():
@@ -7268,12 +6786,17 @@
             q.breakable()
         q.text('}')
 
-class role_request(Message):
+message.subtypes[25] = role_reply
+
+class role_request(message):
     version = 3
     type = 24
 
     def __init__(self, xid=None, role=None, generation_id=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if role != None:
             self.role = role
         else:
@@ -7282,6 +6805,7 @@
             self.generation_id = generation_id
         else:
             self.generation_id = 0
+        return
 
     def pack(self):
         packed = []
@@ -7297,18 +6821,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = role_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 24)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.role = reader.read("!L")[0]
         reader.skip(4)
@@ -7317,23 +6838,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.role != other.role: return False
         if self.generation_id != other.generation_id: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("role_request {")
         with q.group():
@@ -7353,13 +6862,18 @@
             q.breakable()
         q.text('}')
 
-class role_request_failed_error_msg(Message):
+message.subtypes[24] = role_request
+
+class role_request_failed_error_msg(error_msg):
     version = 3
     type = 1
     err_type = 11
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -7368,6 +6882,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -7383,18 +6898,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = role_request_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 11)
@@ -7404,23 +6916,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("role_request_failed_error_msg {")
         with q.group():
@@ -7440,12 +6940,17 @@
             q.breakable()
         q.text('}')
 
-class set_config(Message):
+error_msg.subtypes[11] = role_request_failed_error_msg
+
+class set_config(message):
     version = 3
     type = 9
 
     def __init__(self, xid=None, flags=None, miss_send_len=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -7454,6 +6959,7 @@
             self.miss_send_len = miss_send_len
         else:
             self.miss_send_len = 0
+        return
 
     def pack(self):
         packed = []
@@ -7468,18 +6974,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = set_config()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 9)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.flags = reader.read("!H")[0]
         obj.miss_send_len = reader.read("!H")[0]
@@ -7487,23 +6990,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.miss_send_len != other.miss_send_len: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("set_config {")
         with q.group():
@@ -7523,13 +7014,18 @@
             q.breakable()
         q.text('}')
 
-class switch_config_failed_error_msg(Message):
+message.subtypes[9] = set_config
+
+class switch_config_failed_error_msg(error_msg):
     version = 3
     type = 1
     err_type = 10
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -7538,6 +7034,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -7553,18 +7050,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = switch_config_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 10)
@@ -7574,23 +7068,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("switch_config_failed_error_msg {")
         with q.group():
@@ -7610,12 +7092,17 @@
             q.breakable()
         q.text('}')
 
-class table_mod(Message):
+error_msg.subtypes[10] = switch_config_failed_error_msg
+
+class table_mod(message):
     version = 3
     type = 17
 
     def __init__(self, xid=None, table_id=None, config=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if table_id != None:
             self.table_id = table_id
         else:
@@ -7624,6 +7111,7 @@
             self.config = config
         else:
             self.config = 0
+        return
 
     def pack(self):
         packed = []
@@ -7639,18 +7127,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = table_mod()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 17)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.table_id = reader.read("!B")[0]
         reader.skip(3)
@@ -7659,23 +7144,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.table_id != other.table_id: return False
         if self.config != other.config: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_mod {")
         with q.group():
@@ -7695,13 +7168,18 @@
             q.breakable()
         q.text('}')
 
-class table_mod_failed_error_msg(Message):
+message.subtypes[17] = table_mod
+
+class table_mod_failed_error_msg(error_msg):
     version = 3
     type = 1
     err_type = 8
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -7710,6 +7188,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -7725,18 +7204,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = table_mod_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 8)
@@ -7746,23 +7222,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_mod_failed_error_msg {")
         with q.group():
@@ -7782,13 +7246,18 @@
             q.breakable()
         q.text('}')
 
-class table_stats_reply(Message):
+error_msg.subtypes[8] = table_mod_failed_error_msg
+
+class table_stats_reply(stats_reply):
     version = 3
     type = 19
     stats_type = 3
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -7797,6 +7266,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -7807,24 +7277,21 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = table_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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 == 3)
@@ -7835,23 +7302,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_stats_reply {")
         with q.group():
@@ -7871,17 +7326,23 @@
             q.breakable()
         q.text('}')
 
-class table_stats_request(Message):
+stats_reply.subtypes[3] = table_stats_reply
+
+class table_stats_request(stats_request):
     version = 3
     type = 18
     stats_type = 3
 
     def __init__(self, xid=None, flags=None):
-        self.xid = xid
+        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 = []
@@ -7897,18 +7358,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = table_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 3)
         _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 == 3)
@@ -7918,22 +7376,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_stats_request {")
         with q.group():
@@ -7950,6 +7396,8 @@
             q.breakable()
         q.text('}')
 
+stats_request.subtypes[3] = table_stats_request
+
 
 def parse_header(buf):
     if len(buf) < 8:
@@ -7962,216 +7410,4 @@
         raise loxi.ProtocolError("wrong OpenFlow version (expected %d, got %d)" % (const.OFP_VERSION, msg_ver))
     if len(buf) != msg_len:
         raise loxi.ProtocolError("incorrect message size")
-    if msg_type in parsers:
-        return parsers[msg_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected message type")
-
-def parse_error(buf):
-    if len(buf) < 8 + 2:
-        raise loxi.ProtocolError("message too short")
-    err_type, = struct.unpack_from("!H", buf, 8)
-    if err_type in error_msg_parsers:
-        return error_msg_parsers[err_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected error type %u" % err_type)
-
-def parse_flow_mod(buf):
-    if len(buf) < 25 + 1:
-        raise loxi.ProtocolError("message too short")
-    # Technically uint16_t for OF 1.0
-    cmd, = struct.unpack_from("!B", buf, 25)
-    if cmd in flow_mod_parsers:
-        return flow_mod_parsers[cmd](buf)
-    else:
-        raise loxi.ProtocolError("unexpected flow mod cmd %u" % cmd)
-
-def parse_group_mod(buf):
-    if len(buf) < 8 + 2:
-        raise loxi.ProtocolError("message too short")
-    cmd, = struct.unpack_from("!H", buf, 8)
-    if cmd in flow_mod_parsers:
-        return group_mod_parsers[cmd](buf)
-    else:
-        raise loxi.ProtocolError("unexpected group mod cmd %u" % cmd)
-
-def parse_stats_reply(buf):
-    if len(buf) < 8 + 2:
-        raise loxi.ProtocolError("message too short")
-    stats_type, = struct.unpack_from("!H", buf, 8)
-    if stats_type in stats_reply_parsers:
-        return stats_reply_parsers[stats_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected stats type %u" % stats_type)
-
-def parse_stats_request(buf):
-    if len(buf) < 8 + 2:
-        raise loxi.ProtocolError("message too short")
-    stats_type, = struct.unpack_from("!H", buf, 8)
-    if stats_type in stats_request_parsers:
-        return stats_request_parsers[stats_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected stats type %u" % stats_type)
-
-def parse_experimenter_stats_request(buf):
-    if len(buf) < 24:
-        raise loxi.ProtocolError("experimenter stats request message too short")
-
-    experimenter, exp_type = struct.unpack_from("!LL", buf, 16)
-
-    if experimenter in experimenter_stats_request_parsers and \
-            exp_type in experimenter_stats_request_parsers[experimenter]:
-        return experimenter_stats_request_parsers[experimenter][exp_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected stats request experimenter %#x exp_type %#x" % (experimenter, exp_type))
-
-def parse_experimenter_stats_reply(buf):
-    if len(buf) < 24:
-        raise loxi.ProtocolError("experimenter stats reply message too short")
-
-    experimenter, exp_type = struct.unpack_from("!LL", buf, 16)
-
-    if experimenter in experimenter_stats_reply_parsers and \
-            exp_type in experimenter_stats_reply_parsers[experimenter]:
-        return experimenter_stats_reply_parsers[experimenter][exp_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected stats reply experimenter %#x exp_type %#x" % (experimenter, exp_type))
-
-def parse_experimenter(buf):
-    if len(buf) < 16:
-        raise loxi.ProtocolError("experimenter message too short")
-
-    experimenter, = struct.unpack_from("!L", buf, 8)
-    if experimenter == 0x005c16c7: # Big Switch Networks
-        subtype, = struct.unpack_from("!L", buf, 12)
-    elif experimenter == 0x00002320: # Nicira
-        subtype, = struct.unpack_from("!L", buf, 12)
-    else:
-        raise loxi.ProtocolError("unexpected experimenter id %#x" % experimenter)
-
-    if subtype in experimenter_parsers[experimenter]:
-        return experimenter_parsers[experimenter][subtype](buf)
-    else:
-        raise loxi.ProtocolError("unexpected experimenter %#x subtype %#x" % (experimenter, subtype))
-
-parsers = {
-    const.OFPT_HELLO : hello.unpack,
-    const.OFPT_ERROR : parse_error,
-    const.OFPT_ECHO_REQUEST : echo_request.unpack,
-    const.OFPT_ECHO_REPLY : echo_reply.unpack,
-    const.OFPT_EXPERIMENTER : parse_experimenter,
-    const.OFPT_FEATURES_REQUEST : features_request.unpack,
-    const.OFPT_FEATURES_REPLY : features_reply.unpack,
-    const.OFPT_GET_CONFIG_REQUEST : get_config_request.unpack,
-    const.OFPT_GET_CONFIG_REPLY : get_config_reply.unpack,
-    const.OFPT_SET_CONFIG : set_config.unpack,
-    const.OFPT_PACKET_IN : packet_in.unpack,
-    const.OFPT_FLOW_REMOVED : flow_removed.unpack,
-    const.OFPT_PORT_STATUS : port_status.unpack,
-    const.OFPT_PACKET_OUT : packet_out.unpack,
-    const.OFPT_FLOW_MOD : parse_flow_mod,
-    const.OFPT_GROUP_MOD : parse_group_mod,
-    const.OFPT_PORT_MOD : port_mod.unpack,
-    const.OFPT_TABLE_MOD : table_mod.unpack,
-    const.OFPT_STATS_REQUEST : parse_stats_request,
-    const.OFPT_STATS_REPLY : parse_stats_reply,
-    const.OFPT_BARRIER_REQUEST : barrier_request.unpack,
-    const.OFPT_BARRIER_REPLY : barrier_reply.unpack,
-    const.OFPT_QUEUE_GET_CONFIG_REQUEST : queue_get_config_request.unpack,
-    const.OFPT_QUEUE_GET_CONFIG_REPLY : queue_get_config_reply.unpack,
-    const.OFPT_ROLE_REQUEST : role_request.unpack,
-    const.OFPT_ROLE_REPLY : role_reply.unpack,
-}
-
-error_msg_parsers = {
-    const.OFPET_HELLO_FAILED : hello_failed_error_msg.unpack,
-    const.OFPET_BAD_REQUEST : bad_request_error_msg.unpack,
-    const.OFPET_BAD_ACTION : bad_action_error_msg.unpack,
-    const.OFPET_FLOW_MOD_FAILED : flow_mod_failed_error_msg.unpack,
-    const.OFPET_PORT_MOD_FAILED : port_mod_failed_error_msg.unpack,
-    const.OFPET_QUEUE_OP_FAILED : queue_op_failed_error_msg.unpack,
-    const.OFPET_BAD_INSTRUCTION : bad_instruction_error_msg.unpack,
-    const.OFPET_BAD_MATCH : bad_match_error_msg.unpack,
-    const.OFPET_GROUP_MOD_FAILED : group_mod_failed_error_msg.unpack,
-    const.OFPET_TABLE_MOD_FAILED : table_mod_failed_error_msg.unpack,
-    const.OFPET_SWITCH_CONFIG_FAILED : switch_config_failed_error_msg.unpack,
-    const.OFPET_ROLE_REQUEST_FAILED : role_request_failed_error_msg.unpack,
-    const.OFPET_EXPERIMENTER : experimenter_error_msg.unpack,
-}
-
-flow_mod_parsers = {
-    const.OFPFC_ADD : flow_add.unpack,
-    const.OFPFC_MODIFY : flow_modify.unpack,
-    const.OFPFC_MODIFY_STRICT : flow_modify_strict.unpack,
-    const.OFPFC_DELETE : flow_delete.unpack,
-    const.OFPFC_DELETE_STRICT : flow_delete_strict.unpack,
-}
-
-group_mod_parsers = {
-    const.OFPGC_ADD : group_add.unpack,
-    const.OFPGC_MODIFY : group_modify.unpack,
-    const.OFPGC_DELETE : group_delete.unpack,
-}
-
-stats_reply_parsers = {
-    const.OFPST_DESC : desc_stats_reply.unpack,
-    const.OFPST_FLOW : flow_stats_reply.unpack,
-    const.OFPST_AGGREGATE : aggregate_stats_reply.unpack,
-    const.OFPST_TABLE : table_stats_reply.unpack,
-    const.OFPST_PORT : port_stats_reply.unpack,
-    const.OFPST_QUEUE : queue_stats_reply.unpack,
-    const.OFPST_EXPERIMENTER : parse_experimenter_stats_reply,
-    const.OFPST_GROUP : group_stats_reply.unpack,
-    const.OFPST_GROUP_DESC : group_desc_stats_reply.unpack,
-    const.OFPST_GROUP_FEATURES : group_features_stats_reply.unpack,
-}
-
-stats_request_parsers = {
-    const.OFPST_DESC : desc_stats_request.unpack,
-    const.OFPST_FLOW : flow_stats_request.unpack,
-    const.OFPST_AGGREGATE : aggregate_stats_request.unpack,
-    const.OFPST_TABLE : table_stats_request.unpack,
-    const.OFPST_PORT : port_stats_request.unpack,
-    const.OFPST_QUEUE : queue_stats_request.unpack,
-    const.OFPST_EXPERIMENTER : parse_experimenter_stats_request,
-    const.OFPST_GROUP : group_stats_request.unpack,
-    const.OFPST_GROUP_DESC : group_desc_stats_request.unpack,
-    const.OFPST_GROUP_FEATURES : group_features_stats_request.unpack,
-}
-
-experimenter_parsers = {
-    6035143 : {
-        22: bsn_bw_clear_data_reply.unpack,
-        21: bsn_bw_clear_data_request.unpack,
-        20: bsn_bw_enable_get_reply.unpack,
-        19: bsn_bw_enable_get_request.unpack,
-        23: bsn_bw_enable_set_reply.unpack,
-        18: bsn_bw_enable_set_request.unpack,
-        10: bsn_get_interfaces_reply.unpack,
-        9: bsn_get_interfaces_request.unpack,
-        5: bsn_get_mirroring_reply.unpack,
-        4: bsn_get_mirroring_request.unpack,
-        34: bsn_pdu_rx_reply.unpack,
-        33: bsn_pdu_rx_request.unpack,
-        35: bsn_pdu_rx_timeout.unpack,
-        32: bsn_pdu_tx_reply.unpack,
-        31: bsn_pdu_tx_request.unpack,
-        3: bsn_set_mirroring.unpack,
-        25: bsn_set_pktin_suppression_reply.unpack,
-        11: bsn_set_pktin_suppression_request.unpack,
-        16: bsn_virtual_port_create_reply.unpack,
-        15: bsn_virtual_port_create_request.unpack,
-        26: bsn_virtual_port_remove_reply.unpack,
-        17: bsn_virtual_port_remove_request.unpack,
-    },
-}
-
-experimenter_stats_request_parsers = {
-    0x005c16c7: {
-    },
-}
-
-experimenter_stats_reply_parsers = {
-    0x005c16c7: {
-    },
-}
+    return message.unpack(loxi.generic_util.OFReader(buf))
diff --git a/src/python/loxi/of12/oxm.py b/src/python/loxi/of12/oxm.py
index de53112..56da4d0 100644
--- a/src/python/loxi/of12/oxm.py
+++ b/src/python/loxi/of12/oxm.py
@@ -3,31 +3,33 @@
 # 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 oxm.py
+# Automatically generated by LOXI from template module.py
 # Do not modify
 
 import struct
+import loxi
 import const
+import common
+import action
+import instruction
+import oxm
 import util
 import loxi.generic_util
-import loxi
 
-def unpack(reader):
-    type_len, = reader.peek('!L')
-    if type_len in parsers:
-        return parsers[type_len](reader)
-    else:
-        raise loxi.ProtocolError("unknown OXM cls=%#x type=%#x masked=%d len=%d (%#x)" % \
-            ((type_len >> 16) & 0xffff, (type_len >> 9) & 0x7f, (type_len >> 8) & 1, type_len & 0xff, type_len))
+class oxm(loxi.OFObject):
+    subtypes = {}
 
-def unpack_list(reader):
-    return loxi.generic_util.unpack_list(reader, unpack)
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 0)
+        try:
+            subclass = oxm.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown oxm subtype %#x" % subtype)
+        return subclass.unpack(reader)
 
-class OXM(object):
-    type_len = None # override in subclass
-    pass
 
-class arp_op(OXM):
+class arp_op(oxm):
     type_len = 2147494402
 
     def __init__(self, value=None):
@@ -35,6 +37,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -43,12 +46,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = arp_op()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147494402)
         obj.value = reader.read("!H")[0]
@@ -59,13 +58,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("arp_op {")
         with q.group():
@@ -76,7 +68,9 @@
             q.breakable()
         q.text('}')
 
-class arp_op_masked(OXM):
+oxm.subtypes[2147494402] = arp_op
+
+class arp_op_masked(oxm):
     type_len = 2147494660
 
     def __init__(self, value=None, value_mask=None):
@@ -88,6 +82,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -97,12 +92,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = arp_op_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147494660)
         obj.value = reader.read("!H")[0]
@@ -115,13 +106,6 @@
         if self.value_mask != other.value_mask: 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("arp_op_masked {")
         with q.group():
@@ -135,7 +119,9 @@
             q.breakable()
         q.text('}')
 
-class arp_sha(OXM):
+oxm.subtypes[2147494660] = arp_op_masked
+
+class arp_sha(oxm):
     type_len = 2147495942
 
     def __init__(self, value=None):
@@ -143,6 +129,7 @@
             self.value = value
         else:
             self.value = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -151,12 +138,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = arp_sha()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147495942)
         obj.value = list(reader.read('!6B'))
@@ -167,13 +150,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("arp_sha {")
         with q.group():
@@ -184,7 +160,9 @@
             q.breakable()
         q.text('}')
 
-class arp_sha_masked(OXM):
+oxm.subtypes[2147495942] = arp_sha
+
+class arp_sha_masked(oxm):
     type_len = 2147496204
 
     def __init__(self, value=None, value_mask=None):
@@ -196,6 +174,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -205,12 +184,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = arp_sha_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147496204)
         obj.value = list(reader.read('!6B'))
@@ -223,13 +198,6 @@
         if self.value_mask != other.value_mask: 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("arp_sha_masked {")
         with q.group():
@@ -243,7 +211,9 @@
             q.breakable()
         q.text('}')
 
-class arp_spa(OXM):
+oxm.subtypes[2147496204] = arp_sha_masked
+
+class arp_spa(oxm):
     type_len = 2147494916
 
     def __init__(self, value=None):
@@ -251,6 +221,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -259,12 +230,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = arp_spa()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147494916)
         obj.value = reader.read("!L")[0]
@@ -275,13 +242,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("arp_spa {")
         with q.group():
@@ -292,7 +252,9 @@
             q.breakable()
         q.text('}')
 
-class arp_spa_masked(OXM):
+oxm.subtypes[2147494916] = arp_spa
+
+class arp_spa_masked(oxm):
     type_len = 2147495176
 
     def __init__(self, value=None, value_mask=None):
@@ -304,6 +266,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -313,12 +276,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = arp_spa_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147495176)
         obj.value = reader.read("!L")[0]
@@ -331,13 +290,6 @@
         if self.value_mask != other.value_mask: 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("arp_spa_masked {")
         with q.group():
@@ -351,7 +303,9 @@
             q.breakable()
         q.text('}')
 
-class arp_tha(OXM):
+oxm.subtypes[2147495176] = arp_spa_masked
+
+class arp_tha(oxm):
     type_len = 2147496454
 
     def __init__(self, value=None):
@@ -359,6 +313,7 @@
             self.value = value
         else:
             self.value = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -367,12 +322,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = arp_tha()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147496454)
         obj.value = list(reader.read('!6B'))
@@ -383,13 +334,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("arp_tha {")
         with q.group():
@@ -400,7 +344,9 @@
             q.breakable()
         q.text('}')
 
-class arp_tha_masked(OXM):
+oxm.subtypes[2147496454] = arp_tha
+
+class arp_tha_masked(oxm):
     type_len = 2147496716
 
     def __init__(self, value=None, value_mask=None):
@@ -412,6 +358,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -421,12 +368,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = arp_tha_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147496716)
         obj.value = list(reader.read('!6B'))
@@ -439,13 +382,6 @@
         if self.value_mask != other.value_mask: 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("arp_tha_masked {")
         with q.group():
@@ -459,7 +395,9 @@
             q.breakable()
         q.text('}')
 
-class arp_tpa(OXM):
+oxm.subtypes[2147496716] = arp_tha_masked
+
+class arp_tpa(oxm):
     type_len = 2147495428
 
     def __init__(self, value=None):
@@ -467,6 +405,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -475,12 +414,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = arp_tpa()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147495428)
         obj.value = reader.read("!L")[0]
@@ -491,13 +426,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("arp_tpa {")
         with q.group():
@@ -508,7 +436,9 @@
             q.breakable()
         q.text('}')
 
-class arp_tpa_masked(OXM):
+oxm.subtypes[2147495428] = arp_tpa
+
+class arp_tpa_masked(oxm):
     type_len = 2147495688
 
     def __init__(self, value=None, value_mask=None):
@@ -520,6 +450,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -529,12 +460,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = arp_tpa_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147495688)
         obj.value = reader.read("!L")[0]
@@ -547,13 +474,6 @@
         if self.value_mask != other.value_mask: 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("arp_tpa_masked {")
         with q.group():
@@ -567,7 +487,9 @@
             q.breakable()
         q.text('}')
 
-class bsn_global_vrf_allowed(OXM):
+oxm.subtypes[2147495688] = arp_tpa_masked
+
+class bsn_global_vrf_allowed(oxm):
     type_len = 198145
 
     def __init__(self, value=None):
@@ -575,6 +497,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -583,12 +506,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_global_vrf_allowed()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 198145)
         obj.value = reader.read("!B")[0]
@@ -599,13 +518,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("bsn_global_vrf_allowed {")
         with q.group():
@@ -616,8 +528,10 @@
             q.breakable()
         q.text('}')
 
-class bsn_global_vrf_allowed_masked(OXM):
-    type_len = 198401
+oxm.subtypes[198145] = bsn_global_vrf_allowed
+
+class bsn_global_vrf_allowed_masked(oxm):
+    type_len = 198402
 
     def __init__(self, value=None, value_mask=None):
         if value != None:
@@ -628,6 +542,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -637,14 +552,10 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_global_vrf_allowed_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
-        assert(_type_len == 198401)
+        assert(_type_len == 198402)
         obj.value = reader.read("!B")[0]
         obj.value_mask = reader.read("!B")[0]
         return obj
@@ -655,13 +566,6 @@
         if self.value_mask != other.value_mask: 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_global_vrf_allowed_masked {")
         with q.group():
@@ -675,14 +579,17 @@
             q.breakable()
         q.text('}')
 
-class bsn_in_ports_128(OXM):
-    type_len = 196640
+oxm.subtypes[198402] = bsn_global_vrf_allowed_masked
+
+class bsn_in_ports_128(oxm):
+    type_len = 196624
 
     def __init__(self, value=None):
         if value != None:
             self.value = value
         else:
             self.value = set()
+        return
 
     def pack(self):
         packed = []
@@ -691,14 +598,10 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_in_ports_128()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
-        assert(_type_len == 196640)
+        assert(_type_len == 196624)
         obj.value = util.unpack_bitmap_128(reader)
         return obj
 
@@ -707,13 +610,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("bsn_in_ports_128 {")
         with q.group():
@@ -724,7 +620,9 @@
             q.breakable()
         q.text('}')
 
-class bsn_in_ports_128_masked(OXM):
+oxm.subtypes[196624] = bsn_in_ports_128
+
+class bsn_in_ports_128_masked(oxm):
     type_len = 196896
 
     def __init__(self, value=None, value_mask=None):
@@ -736,6 +634,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = set()
+        return
 
     def pack(self):
         packed = []
@@ -745,12 +644,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_in_ports_128_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 196896)
         obj.value = util.unpack_bitmap_128(reader)
@@ -763,13 +658,6 @@
         if self.value_mask != other.value_mask: 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_in_ports_128_masked {")
         with q.group():
@@ -783,7 +671,9 @@
             q.breakable()
         q.text('}')
 
-class bsn_l3_dst_class_id(OXM):
+oxm.subtypes[196896] = bsn_in_ports_128_masked
+
+class bsn_l3_dst_class_id(oxm):
     type_len = 199684
 
     def __init__(self, value=None):
@@ -791,6 +681,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -799,12 +690,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_l3_dst_class_id()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 199684)
         obj.value = reader.read("!L")[0]
@@ -815,13 +702,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("bsn_l3_dst_class_id {")
         with q.group():
@@ -832,8 +712,10 @@
             q.breakable()
         q.text('}')
 
-class bsn_l3_dst_class_id_masked(OXM):
-    type_len = 199940
+oxm.subtypes[199684] = bsn_l3_dst_class_id
+
+class bsn_l3_dst_class_id_masked(oxm):
+    type_len = 199944
 
     def __init__(self, value=None, value_mask=None):
         if value != None:
@@ -844,6 +726,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -853,14 +736,10 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_l3_dst_class_id_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
-        assert(_type_len == 199940)
+        assert(_type_len == 199944)
         obj.value = reader.read("!L")[0]
         obj.value_mask = reader.read("!L")[0]
         return obj
@@ -871,13 +750,6 @@
         if self.value_mask != other.value_mask: 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_l3_dst_class_id_masked {")
         with q.group():
@@ -891,7 +763,9 @@
             q.breakable()
         q.text('}')
 
-class bsn_l3_interface_class_id(OXM):
+oxm.subtypes[199944] = bsn_l3_dst_class_id_masked
+
+class bsn_l3_interface_class_id(oxm):
     type_len = 198660
 
     def __init__(self, value=None):
@@ -899,6 +773,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -907,12 +782,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_l3_interface_class_id()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 198660)
         obj.value = reader.read("!L")[0]
@@ -923,13 +794,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("bsn_l3_interface_class_id {")
         with q.group():
@@ -940,8 +804,10 @@
             q.breakable()
         q.text('}')
 
-class bsn_l3_interface_class_id_masked(OXM):
-    type_len = 198916
+oxm.subtypes[198660] = bsn_l3_interface_class_id
+
+class bsn_l3_interface_class_id_masked(oxm):
+    type_len = 198920
 
     def __init__(self, value=None, value_mask=None):
         if value != None:
@@ -952,6 +818,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -961,14 +828,10 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_l3_interface_class_id_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
-        assert(_type_len == 198916)
+        assert(_type_len == 198920)
         obj.value = reader.read("!L")[0]
         obj.value_mask = reader.read("!L")[0]
         return obj
@@ -979,13 +842,6 @@
         if self.value_mask != other.value_mask: 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_l3_interface_class_id_masked {")
         with q.group():
@@ -999,7 +855,9 @@
             q.breakable()
         q.text('}')
 
-class bsn_l3_src_class_id(OXM):
+oxm.subtypes[198920] = bsn_l3_interface_class_id_masked
+
+class bsn_l3_src_class_id(oxm):
     type_len = 199172
 
     def __init__(self, value=None):
@@ -1007,6 +865,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -1015,12 +874,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_l3_src_class_id()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 199172)
         obj.value = reader.read("!L")[0]
@@ -1031,13 +886,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("bsn_l3_src_class_id {")
         with q.group():
@@ -1048,8 +896,10 @@
             q.breakable()
         q.text('}')
 
-class bsn_l3_src_class_id_masked(OXM):
-    type_len = 199428
+oxm.subtypes[199172] = bsn_l3_src_class_id
+
+class bsn_l3_src_class_id_masked(oxm):
+    type_len = 199432
 
     def __init__(self, value=None, value_mask=None):
         if value != None:
@@ -1060,6 +910,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -1069,14 +920,10 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_l3_src_class_id_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
-        assert(_type_len == 199428)
+        assert(_type_len == 199432)
         obj.value = reader.read("!L")[0]
         obj.value_mask = reader.read("!L")[0]
         return obj
@@ -1087,13 +934,6 @@
         if self.value_mask != other.value_mask: 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_l3_src_class_id_masked {")
         with q.group():
@@ -1107,7 +947,9 @@
             q.breakable()
         q.text('}')
 
-class bsn_lag_id(OXM):
+oxm.subtypes[199432] = bsn_l3_src_class_id_masked
+
+class bsn_lag_id(oxm):
     type_len = 197124
 
     def __init__(self, value=None):
@@ -1115,6 +957,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -1123,12 +966,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_lag_id()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 197124)
         obj.value = reader.read("!L")[0]
@@ -1139,13 +978,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("bsn_lag_id {")
         with q.group():
@@ -1156,8 +988,10 @@
             q.breakable()
         q.text('}')
 
-class bsn_lag_id_masked(OXM):
-    type_len = 197380
+oxm.subtypes[197124] = bsn_lag_id
+
+class bsn_lag_id_masked(oxm):
+    type_len = 197384
 
     def __init__(self, value=None, value_mask=None):
         if value != None:
@@ -1168,6 +1002,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -1177,14 +1012,10 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_lag_id_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
-        assert(_type_len == 197380)
+        assert(_type_len == 197384)
         obj.value = reader.read("!L")[0]
         obj.value_mask = reader.read("!L")[0]
         return obj
@@ -1195,13 +1026,6 @@
         if self.value_mask != other.value_mask: 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_lag_id_masked {")
         with q.group():
@@ -1215,7 +1039,9 @@
             q.breakable()
         q.text('}')
 
-class bsn_vrf(OXM):
+oxm.subtypes[197384] = bsn_lag_id_masked
+
+class bsn_vrf(oxm):
     type_len = 197636
 
     def __init__(self, value=None):
@@ -1223,6 +1049,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -1231,12 +1058,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_vrf()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 197636)
         obj.value = reader.read("!L")[0]
@@ -1247,13 +1070,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("bsn_vrf {")
         with q.group():
@@ -1264,8 +1080,10 @@
             q.breakable()
         q.text('}')
 
-class bsn_vrf_masked(OXM):
-    type_len = 197892
+oxm.subtypes[197636] = bsn_vrf
+
+class bsn_vrf_masked(oxm):
+    type_len = 197896
 
     def __init__(self, value=None, value_mask=None):
         if value != None:
@@ -1276,6 +1094,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -1285,14 +1104,10 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_vrf_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
-        assert(_type_len == 197892)
+        assert(_type_len == 197896)
         obj.value = reader.read("!L")[0]
         obj.value_mask = reader.read("!L")[0]
         return obj
@@ -1303,13 +1118,6 @@
         if self.value_mask != other.value_mask: 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_vrf_masked {")
         with q.group():
@@ -1323,7 +1131,9 @@
             q.breakable()
         q.text('}')
 
-class eth_dst(OXM):
+oxm.subtypes[197896] = bsn_vrf_masked
+
+class eth_dst(oxm):
     type_len = 2147485190
 
     def __init__(self, value=None):
@@ -1331,6 +1141,7 @@
             self.value = value
         else:
             self.value = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -1339,12 +1150,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = eth_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147485190)
         obj.value = list(reader.read('!6B'))
@@ -1355,13 +1162,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("eth_dst {")
         with q.group():
@@ -1372,7 +1172,9 @@
             q.breakable()
         q.text('}')
 
-class eth_dst_masked(OXM):
+oxm.subtypes[2147485190] = eth_dst
+
+class eth_dst_masked(oxm):
     type_len = 2147485452
 
     def __init__(self, value=None, value_mask=None):
@@ -1384,6 +1186,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -1393,12 +1196,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = eth_dst_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147485452)
         obj.value = list(reader.read('!6B'))
@@ -1411,13 +1210,6 @@
         if self.value_mask != other.value_mask: 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("eth_dst_masked {")
         with q.group():
@@ -1431,7 +1223,9 @@
             q.breakable()
         q.text('}')
 
-class eth_src(OXM):
+oxm.subtypes[2147485452] = eth_dst_masked
+
+class eth_src(oxm):
     type_len = 2147485702
 
     def __init__(self, value=None):
@@ -1439,6 +1233,7 @@
             self.value = value
         else:
             self.value = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -1447,12 +1242,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = eth_src()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147485702)
         obj.value = list(reader.read('!6B'))
@@ -1463,13 +1254,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("eth_src {")
         with q.group():
@@ -1480,7 +1264,9 @@
             q.breakable()
         q.text('}')
 
-class eth_src_masked(OXM):
+oxm.subtypes[2147485702] = eth_src
+
+class eth_src_masked(oxm):
     type_len = 2147485964
 
     def __init__(self, value=None, value_mask=None):
@@ -1492,6 +1278,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -1501,12 +1288,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = eth_src_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147485964)
         obj.value = list(reader.read('!6B'))
@@ -1519,13 +1302,6 @@
         if self.value_mask != other.value_mask: 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("eth_src_masked {")
         with q.group():
@@ -1539,7 +1315,9 @@
             q.breakable()
         q.text('}')
 
-class eth_type(OXM):
+oxm.subtypes[2147485964] = eth_src_masked
+
+class eth_type(oxm):
     type_len = 2147486210
 
     def __init__(self, value=None):
@@ -1547,6 +1325,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -1555,12 +1334,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = eth_type()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147486210)
         obj.value = reader.read("!H")[0]
@@ -1571,13 +1346,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("eth_type {")
         with q.group():
@@ -1588,7 +1356,9 @@
             q.breakable()
         q.text('}')
 
-class eth_type_masked(OXM):
+oxm.subtypes[2147486210] = eth_type
+
+class eth_type_masked(oxm):
     type_len = 2147486468
 
     def __init__(self, value=None, value_mask=None):
@@ -1600,6 +1370,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -1609,12 +1380,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = eth_type_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147486468)
         obj.value = reader.read("!H")[0]
@@ -1627,13 +1394,6 @@
         if self.value_mask != other.value_mask: 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("eth_type_masked {")
         with q.group():
@@ -1647,7 +1407,9 @@
             q.breakable()
         q.text('}')
 
-class icmpv4_code(OXM):
+oxm.subtypes[2147486468] = eth_type_masked
+
+class icmpv4_code(oxm):
     type_len = 2147493889
 
     def __init__(self, value=None):
@@ -1655,6 +1417,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -1663,12 +1426,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = icmpv4_code()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147493889)
         obj.value = reader.read("!B")[0]
@@ -1679,13 +1438,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("icmpv4_code {")
         with q.group():
@@ -1696,7 +1448,9 @@
             q.breakable()
         q.text('}')
 
-class icmpv4_code_masked(OXM):
+oxm.subtypes[2147493889] = icmpv4_code
+
+class icmpv4_code_masked(oxm):
     type_len = 2147494146
 
     def __init__(self, value=None, value_mask=None):
@@ -1708,6 +1462,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -1717,12 +1472,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = icmpv4_code_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147494146)
         obj.value = reader.read("!B")[0]
@@ -1735,13 +1486,6 @@
         if self.value_mask != other.value_mask: 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("icmpv4_code_masked {")
         with q.group():
@@ -1755,7 +1499,9 @@
             q.breakable()
         q.text('}')
 
-class icmpv4_type(OXM):
+oxm.subtypes[2147494146] = icmpv4_code_masked
+
+class icmpv4_type(oxm):
     type_len = 2147493377
 
     def __init__(self, value=None):
@@ -1763,6 +1509,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -1771,12 +1518,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = icmpv4_type()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147493377)
         obj.value = reader.read("!B")[0]
@@ -1787,13 +1530,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("icmpv4_type {")
         with q.group():
@@ -1804,7 +1540,9 @@
             q.breakable()
         q.text('}')
 
-class icmpv4_type_masked(OXM):
+oxm.subtypes[2147493377] = icmpv4_type
+
+class icmpv4_type_masked(oxm):
     type_len = 2147493634
 
     def __init__(self, value=None, value_mask=None):
@@ -1816,6 +1554,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -1825,12 +1564,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = icmpv4_type_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147493634)
         obj.value = reader.read("!B")[0]
@@ -1843,13 +1578,6 @@
         if self.value_mask != other.value_mask: 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("icmpv4_type_masked {")
         with q.group():
@@ -1863,7 +1591,9 @@
             q.breakable()
         q.text('}')
 
-class icmpv6_code(OXM):
+oxm.subtypes[2147493634] = icmpv4_type_masked
+
+class icmpv6_code(oxm):
     type_len = 2147499009
 
     def __init__(self, value=None):
@@ -1871,6 +1601,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -1879,12 +1610,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = icmpv6_code()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147499009)
         obj.value = reader.read("!B")[0]
@@ -1895,13 +1622,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("icmpv6_code {")
         with q.group():
@@ -1912,7 +1632,9 @@
             q.breakable()
         q.text('}')
 
-class icmpv6_code_masked(OXM):
+oxm.subtypes[2147499009] = icmpv6_code
+
+class icmpv6_code_masked(oxm):
     type_len = 2147499266
 
     def __init__(self, value=None, value_mask=None):
@@ -1924,6 +1646,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -1933,12 +1656,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = icmpv6_code_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147499266)
         obj.value = reader.read("!B")[0]
@@ -1951,13 +1670,6 @@
         if self.value_mask != other.value_mask: 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("icmpv6_code_masked {")
         with q.group():
@@ -1971,7 +1683,9 @@
             q.breakable()
         q.text('}')
 
-class icmpv6_type(OXM):
+oxm.subtypes[2147499266] = icmpv6_code_masked
+
+class icmpv6_type(oxm):
     type_len = 2147498497
 
     def __init__(self, value=None):
@@ -1979,6 +1693,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -1987,12 +1702,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = icmpv6_type()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147498497)
         obj.value = reader.read("!B")[0]
@@ -2003,13 +1714,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("icmpv6_type {")
         with q.group():
@@ -2020,7 +1724,9 @@
             q.breakable()
         q.text('}')
 
-class icmpv6_type_masked(OXM):
+oxm.subtypes[2147498497] = icmpv6_type
+
+class icmpv6_type_masked(oxm):
     type_len = 2147498754
 
     def __init__(self, value=None, value_mask=None):
@@ -2032,6 +1738,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -2041,12 +1748,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = icmpv6_type_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147498754)
         obj.value = reader.read("!B")[0]
@@ -2059,13 +1762,6 @@
         if self.value_mask != other.value_mask: 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("icmpv6_type_masked {")
         with q.group():
@@ -2079,7 +1775,9 @@
             q.breakable()
         q.text('}')
 
-class in_phy_port(OXM):
+oxm.subtypes[2147498754] = icmpv6_type_masked
+
+class in_phy_port(oxm):
     type_len = 2147484164
 
     def __init__(self, value=None):
@@ -2087,6 +1785,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -2095,12 +1794,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = in_phy_port()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147484164)
         obj.value = util.unpack_port_no(reader)
@@ -2111,13 +1806,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("in_phy_port {")
         with q.group():
@@ -2128,7 +1816,9 @@
             q.breakable()
         q.text('}')
 
-class in_phy_port_masked(OXM):
+oxm.subtypes[2147484164] = in_phy_port
+
+class in_phy_port_masked(oxm):
     type_len = 2147484424
 
     def __init__(self, value=None, value_mask=None):
@@ -2140,6 +1830,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -2149,12 +1840,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = in_phy_port_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147484424)
         obj.value = util.unpack_port_no(reader)
@@ -2167,13 +1854,6 @@
         if self.value_mask != other.value_mask: 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("in_phy_port_masked {")
         with q.group():
@@ -2187,7 +1867,9 @@
             q.breakable()
         q.text('}')
 
-class in_port(OXM):
+oxm.subtypes[2147484424] = in_phy_port_masked
+
+class in_port(oxm):
     type_len = 2147483652
 
     def __init__(self, value=None):
@@ -2195,6 +1877,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -2203,12 +1886,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = in_port()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147483652)
         obj.value = util.unpack_port_no(reader)
@@ -2219,13 +1898,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("in_port {")
         with q.group():
@@ -2236,7 +1908,9 @@
             q.breakable()
         q.text('}')
 
-class in_port_masked(OXM):
+oxm.subtypes[2147483652] = in_port
+
+class in_port_masked(oxm):
     type_len = 2147483912
 
     def __init__(self, value=None, value_mask=None):
@@ -2248,6 +1922,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -2257,12 +1932,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = in_port_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147483912)
         obj.value = util.unpack_port_no(reader)
@@ -2275,13 +1946,6 @@
         if self.value_mask != other.value_mask: 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("in_port_masked {")
         with q.group():
@@ -2295,7 +1959,9 @@
             q.breakable()
         q.text('}')
 
-class ip_dscp(OXM):
+oxm.subtypes[2147483912] = in_port_masked
+
+class ip_dscp(oxm):
     type_len = 2147487745
 
     def __init__(self, value=None):
@@ -2303,6 +1969,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -2311,12 +1978,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ip_dscp()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147487745)
         obj.value = reader.read("!B")[0]
@@ -2327,13 +1990,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("ip_dscp {")
         with q.group():
@@ -2344,7 +2000,9 @@
             q.breakable()
         q.text('}')
 
-class ip_dscp_masked(OXM):
+oxm.subtypes[2147487745] = ip_dscp
+
+class ip_dscp_masked(oxm):
     type_len = 2147488002
 
     def __init__(self, value=None, value_mask=None):
@@ -2356,6 +2014,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -2365,12 +2024,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ip_dscp_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147488002)
         obj.value = reader.read("!B")[0]
@@ -2383,13 +2038,6 @@
         if self.value_mask != other.value_mask: 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("ip_dscp_masked {")
         with q.group():
@@ -2403,7 +2051,9 @@
             q.breakable()
         q.text('}')
 
-class ip_ecn(OXM):
+oxm.subtypes[2147488002] = ip_dscp_masked
+
+class ip_ecn(oxm):
     type_len = 2147488257
 
     def __init__(self, value=None):
@@ -2411,6 +2061,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -2419,12 +2070,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ip_ecn()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147488257)
         obj.value = reader.read("!B")[0]
@@ -2435,13 +2082,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("ip_ecn {")
         with q.group():
@@ -2452,7 +2092,9 @@
             q.breakable()
         q.text('}')
 
-class ip_ecn_masked(OXM):
+oxm.subtypes[2147488257] = ip_ecn
+
+class ip_ecn_masked(oxm):
     type_len = 2147488514
 
     def __init__(self, value=None, value_mask=None):
@@ -2464,6 +2106,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -2473,12 +2116,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ip_ecn_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147488514)
         obj.value = reader.read("!B")[0]
@@ -2491,13 +2130,6 @@
         if self.value_mask != other.value_mask: 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("ip_ecn_masked {")
         with q.group():
@@ -2511,7 +2143,9 @@
             q.breakable()
         q.text('}')
 
-class ip_proto(OXM):
+oxm.subtypes[2147488514] = ip_ecn_masked
+
+class ip_proto(oxm):
     type_len = 2147488769
 
     def __init__(self, value=None):
@@ -2519,6 +2153,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -2527,12 +2162,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ip_proto()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147488769)
         obj.value = reader.read("!B")[0]
@@ -2543,13 +2174,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("ip_proto {")
         with q.group():
@@ -2560,7 +2184,9 @@
             q.breakable()
         q.text('}')
 
-class ip_proto_masked(OXM):
+oxm.subtypes[2147488769] = ip_proto
+
+class ip_proto_masked(oxm):
     type_len = 2147489026
 
     def __init__(self, value=None, value_mask=None):
@@ -2572,6 +2198,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -2581,12 +2208,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ip_proto_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147489026)
         obj.value = reader.read("!B")[0]
@@ -2599,13 +2222,6 @@
         if self.value_mask != other.value_mask: 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("ip_proto_masked {")
         with q.group():
@@ -2619,7 +2235,9 @@
             q.breakable()
         q.text('}')
 
-class ipv4_dst(OXM):
+oxm.subtypes[2147489026] = ip_proto_masked
+
+class ipv4_dst(oxm):
     type_len = 2147489796
 
     def __init__(self, value=None):
@@ -2627,6 +2245,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -2635,12 +2254,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv4_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147489796)
         obj.value = reader.read("!L")[0]
@@ -2651,13 +2266,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("ipv4_dst {")
         with q.group():
@@ -2668,7 +2276,9 @@
             q.breakable()
         q.text('}')
 
-class ipv4_dst_masked(OXM):
+oxm.subtypes[2147489796] = ipv4_dst
+
+class ipv4_dst_masked(oxm):
     type_len = 2147490056
 
     def __init__(self, value=None, value_mask=None):
@@ -2680,6 +2290,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -2689,12 +2300,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv4_dst_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147490056)
         obj.value = reader.read("!L")[0]
@@ -2707,13 +2314,6 @@
         if self.value_mask != other.value_mask: 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("ipv4_dst_masked {")
         with q.group():
@@ -2727,7 +2327,9 @@
             q.breakable()
         q.text('}')
 
-class ipv4_src(OXM):
+oxm.subtypes[2147490056] = ipv4_dst_masked
+
+class ipv4_src(oxm):
     type_len = 2147489284
 
     def __init__(self, value=None):
@@ -2735,6 +2337,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -2743,12 +2346,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv4_src()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147489284)
         obj.value = reader.read("!L")[0]
@@ -2759,13 +2358,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("ipv4_src {")
         with q.group():
@@ -2776,7 +2368,9 @@
             q.breakable()
         q.text('}')
 
-class ipv4_src_masked(OXM):
+oxm.subtypes[2147489284] = ipv4_src
+
+class ipv4_src_masked(oxm):
     type_len = 2147489544
 
     def __init__(self, value=None, value_mask=None):
@@ -2788,6 +2382,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -2797,12 +2392,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv4_src_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147489544)
         obj.value = reader.read("!L")[0]
@@ -2815,13 +2406,6 @@
         if self.value_mask != other.value_mask: 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("ipv4_src_masked {")
         with q.group():
@@ -2835,7 +2419,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_dst(OXM):
+oxm.subtypes[2147489544] = ipv4_src_masked
+
+class ipv6_dst(oxm):
     type_len = 2147497488
 
     def __init__(self, value=None):
@@ -2843,6 +2429,7 @@
             self.value = value
         else:
             self.value = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+        return
 
     def pack(self):
         packed = []
@@ -2851,12 +2438,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147497488)
         obj.value = reader.read('!16s')[0]
@@ -2867,13 +2450,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("ipv6_dst {")
         with q.group():
@@ -2884,7 +2460,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_dst_masked(OXM):
+oxm.subtypes[2147497488] = ipv6_dst
+
+class ipv6_dst_masked(oxm):
     type_len = 2147497760
 
     def __init__(self, value=None, value_mask=None):
@@ -2896,6 +2474,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+        return
 
     def pack(self):
         packed = []
@@ -2905,12 +2484,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_dst_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147497760)
         obj.value = reader.read('!16s')[0]
@@ -2923,13 +2498,6 @@
         if self.value_mask != other.value_mask: 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("ipv6_dst_masked {")
         with q.group():
@@ -2943,7 +2511,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_flabel(OXM):
+oxm.subtypes[2147497760] = ipv6_dst_masked
+
+class ipv6_flabel(oxm):
     type_len = 2147497988
 
     def __init__(self, value=None):
@@ -2951,6 +2521,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -2959,12 +2530,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_flabel()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147497988)
         obj.value = reader.read("!L")[0]
@@ -2975,13 +2542,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("ipv6_flabel {")
         with q.group():
@@ -2992,7 +2552,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_flabel_masked(OXM):
+oxm.subtypes[2147497988] = ipv6_flabel
+
+class ipv6_flabel_masked(oxm):
     type_len = 2147498248
 
     def __init__(self, value=None, value_mask=None):
@@ -3004,6 +2566,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -3013,12 +2576,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_flabel_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147498248)
         obj.value = reader.read("!L")[0]
@@ -3031,13 +2590,6 @@
         if self.value_mask != other.value_mask: 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("ipv6_flabel_masked {")
         with q.group():
@@ -3051,7 +2603,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_nd_sll(OXM):
+oxm.subtypes[2147498248] = ipv6_flabel_masked
+
+class ipv6_nd_sll(oxm):
     type_len = 2147500038
 
     def __init__(self, value=None):
@@ -3059,6 +2613,7 @@
             self.value = value
         else:
             self.value = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -3067,12 +2622,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_nd_sll()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147500038)
         obj.value = list(reader.read('!6B'))
@@ -3083,13 +2634,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("ipv6_nd_sll {")
         with q.group():
@@ -3100,7 +2644,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_nd_sll_masked(OXM):
+oxm.subtypes[2147500038] = ipv6_nd_sll
+
+class ipv6_nd_sll_masked(oxm):
     type_len = 2147500300
 
     def __init__(self, value=None, value_mask=None):
@@ -3112,6 +2658,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -3121,12 +2668,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_nd_sll_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147500300)
         obj.value = list(reader.read('!6B'))
@@ -3139,13 +2682,6 @@
         if self.value_mask != other.value_mask: 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("ipv6_nd_sll_masked {")
         with q.group():
@@ -3159,7 +2695,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_nd_target(OXM):
+oxm.subtypes[2147500300] = ipv6_nd_sll_masked
+
+class ipv6_nd_target(oxm):
     type_len = 2147499536
 
     def __init__(self, value=None):
@@ -3167,6 +2705,7 @@
             self.value = value
         else:
             self.value = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+        return
 
     def pack(self):
         packed = []
@@ -3175,12 +2714,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_nd_target()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147499536)
         obj.value = reader.read('!16s')[0]
@@ -3191,13 +2726,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("ipv6_nd_target {")
         with q.group():
@@ -3208,7 +2736,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_nd_target_masked(OXM):
+oxm.subtypes[2147499536] = ipv6_nd_target
+
+class ipv6_nd_target_masked(oxm):
     type_len = 2147499808
 
     def __init__(self, value=None, value_mask=None):
@@ -3220,6 +2750,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+        return
 
     def pack(self):
         packed = []
@@ -3229,12 +2760,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_nd_target_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147499808)
         obj.value = reader.read('!16s')[0]
@@ -3247,13 +2774,6 @@
         if self.value_mask != other.value_mask: 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("ipv6_nd_target_masked {")
         with q.group():
@@ -3267,7 +2787,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_nd_tll(OXM):
+oxm.subtypes[2147499808] = ipv6_nd_target_masked
+
+class ipv6_nd_tll(oxm):
     type_len = 2147500550
 
     def __init__(self, value=None):
@@ -3275,6 +2797,7 @@
             self.value = value
         else:
             self.value = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -3283,12 +2806,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_nd_tll()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147500550)
         obj.value = list(reader.read('!6B'))
@@ -3299,13 +2818,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("ipv6_nd_tll {")
         with q.group():
@@ -3316,7 +2828,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_nd_tll_masked(OXM):
+oxm.subtypes[2147500550] = ipv6_nd_tll
+
+class ipv6_nd_tll_masked(oxm):
     type_len = 2147500812
 
     def __init__(self, value=None, value_mask=None):
@@ -3328,6 +2842,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -3337,12 +2852,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_nd_tll_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147500812)
         obj.value = list(reader.read('!6B'))
@@ -3355,13 +2866,6 @@
         if self.value_mask != other.value_mask: 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("ipv6_nd_tll_masked {")
         with q.group():
@@ -3375,7 +2879,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_src(OXM):
+oxm.subtypes[2147500812] = ipv6_nd_tll_masked
+
+class ipv6_src(oxm):
     type_len = 2147496976
 
     def __init__(self, value=None):
@@ -3383,6 +2889,7 @@
             self.value = value
         else:
             self.value = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+        return
 
     def pack(self):
         packed = []
@@ -3391,12 +2898,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_src()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147496976)
         obj.value = reader.read('!16s')[0]
@@ -3407,13 +2910,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("ipv6_src {")
         with q.group():
@@ -3424,7 +2920,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_src_masked(OXM):
+oxm.subtypes[2147496976] = ipv6_src
+
+class ipv6_src_masked(oxm):
     type_len = 2147497248
 
     def __init__(self, value=None, value_mask=None):
@@ -3436,6 +2934,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+        return
 
     def pack(self):
         packed = []
@@ -3445,12 +2944,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_src_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147497248)
         obj.value = reader.read('!16s')[0]
@@ -3463,13 +2958,6 @@
         if self.value_mask != other.value_mask: 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("ipv6_src_masked {")
         with q.group():
@@ -3483,7 +2971,9 @@
             q.breakable()
         q.text('}')
 
-class metadata(OXM):
+oxm.subtypes[2147497248] = ipv6_src_masked
+
+class metadata(oxm):
     type_len = 2147484680
 
     def __init__(self, value=None):
@@ -3491,6 +2981,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -3499,12 +2990,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = metadata()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147484680)
         obj.value = reader.read("!Q")[0]
@@ -3515,13 +3002,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("metadata {")
         with q.group():
@@ -3532,7 +3012,9 @@
             q.breakable()
         q.text('}')
 
-class metadata_masked(OXM):
+oxm.subtypes[2147484680] = metadata
+
+class metadata_masked(oxm):
     type_len = 2147484944
 
     def __init__(self, value=None, value_mask=None):
@@ -3544,6 +3026,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -3553,12 +3036,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = metadata_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147484944)
         obj.value = reader.read("!Q")[0]
@@ -3571,13 +3050,6 @@
         if self.value_mask != other.value_mask: 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("metadata_masked {")
         with q.group():
@@ -3591,7 +3063,9 @@
             q.breakable()
         q.text('}')
 
-class mpls_label(OXM):
+oxm.subtypes[2147484944] = metadata_masked
+
+class mpls_label(oxm):
     type_len = 2147501060
 
     def __init__(self, value=None):
@@ -3599,6 +3073,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -3607,12 +3082,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = mpls_label()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147501060)
         obj.value = reader.read("!L")[0]
@@ -3623,13 +3094,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("mpls_label {")
         with q.group():
@@ -3640,7 +3104,9 @@
             q.breakable()
         q.text('}')
 
-class mpls_label_masked(OXM):
+oxm.subtypes[2147501060] = mpls_label
+
+class mpls_label_masked(oxm):
     type_len = 2147501320
 
     def __init__(self, value=None, value_mask=None):
@@ -3652,6 +3118,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -3661,12 +3128,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = mpls_label_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147501320)
         obj.value = reader.read("!L")[0]
@@ -3679,13 +3142,6 @@
         if self.value_mask != other.value_mask: 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("mpls_label_masked {")
         with q.group():
@@ -3699,7 +3155,9 @@
             q.breakable()
         q.text('}')
 
-class mpls_tc(OXM):
+oxm.subtypes[2147501320] = mpls_label_masked
+
+class mpls_tc(oxm):
     type_len = 2147501569
 
     def __init__(self, value=None):
@@ -3707,6 +3165,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -3715,12 +3174,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = mpls_tc()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147501569)
         obj.value = reader.read("!B")[0]
@@ -3731,13 +3186,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("mpls_tc {")
         with q.group():
@@ -3748,7 +3196,9 @@
             q.breakable()
         q.text('}')
 
-class mpls_tc_masked(OXM):
+oxm.subtypes[2147501569] = mpls_tc
+
+class mpls_tc_masked(oxm):
     type_len = 2147501826
 
     def __init__(self, value=None, value_mask=None):
@@ -3760,6 +3210,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -3769,12 +3220,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = mpls_tc_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147501826)
         obj.value = reader.read("!B")[0]
@@ -3787,13 +3234,6 @@
         if self.value_mask != other.value_mask: 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("mpls_tc_masked {")
         with q.group():
@@ -3807,7 +3247,9 @@
             q.breakable()
         q.text('}')
 
-class sctp_dst(OXM):
+oxm.subtypes[2147501826] = mpls_tc_masked
+
+class sctp_dst(oxm):
     type_len = 2147492866
 
     def __init__(self, value=None):
@@ -3815,6 +3257,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -3823,12 +3266,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = sctp_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147492866)
         obj.value = reader.read("!H")[0]
@@ -3839,13 +3278,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("sctp_dst {")
         with q.group():
@@ -3856,7 +3288,9 @@
             q.breakable()
         q.text('}')
 
-class sctp_dst_masked(OXM):
+oxm.subtypes[2147492866] = sctp_dst
+
+class sctp_dst_masked(oxm):
     type_len = 2147493124
 
     def __init__(self, value=None, value_mask=None):
@@ -3868,6 +3302,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -3877,12 +3312,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = sctp_dst_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147493124)
         obj.value = reader.read("!H")[0]
@@ -3895,13 +3326,6 @@
         if self.value_mask != other.value_mask: 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("sctp_dst_masked {")
         with q.group():
@@ -3915,7 +3339,9 @@
             q.breakable()
         q.text('}')
 
-class sctp_src(OXM):
+oxm.subtypes[2147493124] = sctp_dst_masked
+
+class sctp_src(oxm):
     type_len = 2147492354
 
     def __init__(self, value=None):
@@ -3923,6 +3349,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -3931,12 +3358,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = sctp_src()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147492354)
         obj.value = reader.read("!H")[0]
@@ -3947,13 +3370,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("sctp_src {")
         with q.group():
@@ -3964,7 +3380,9 @@
             q.breakable()
         q.text('}')
 
-class sctp_src_masked(OXM):
+oxm.subtypes[2147492354] = sctp_src
+
+class sctp_src_masked(oxm):
     type_len = 2147492612
 
     def __init__(self, value=None, value_mask=None):
@@ -3976,6 +3394,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -3985,12 +3404,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = sctp_src_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147492612)
         obj.value = reader.read("!H")[0]
@@ -4003,13 +3418,6 @@
         if self.value_mask != other.value_mask: 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("sctp_src_masked {")
         with q.group():
@@ -4023,7 +3431,9 @@
             q.breakable()
         q.text('}')
 
-class tcp_dst(OXM):
+oxm.subtypes[2147492612] = sctp_src_masked
+
+class tcp_dst(oxm):
     type_len = 2147490818
 
     def __init__(self, value=None):
@@ -4031,6 +3441,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -4039,12 +3450,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = tcp_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147490818)
         obj.value = reader.read("!H")[0]
@@ -4055,13 +3462,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("tcp_dst {")
         with q.group():
@@ -4072,7 +3472,9 @@
             q.breakable()
         q.text('}')
 
-class tcp_dst_masked(OXM):
+oxm.subtypes[2147490818] = tcp_dst
+
+class tcp_dst_masked(oxm):
     type_len = 2147491076
 
     def __init__(self, value=None, value_mask=None):
@@ -4084,6 +3486,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -4093,12 +3496,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = tcp_dst_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147491076)
         obj.value = reader.read("!H")[0]
@@ -4111,13 +3510,6 @@
         if self.value_mask != other.value_mask: 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("tcp_dst_masked {")
         with q.group():
@@ -4131,7 +3523,9 @@
             q.breakable()
         q.text('}')
 
-class tcp_src(OXM):
+oxm.subtypes[2147491076] = tcp_dst_masked
+
+class tcp_src(oxm):
     type_len = 2147490306
 
     def __init__(self, value=None):
@@ -4139,6 +3533,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -4147,12 +3542,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = tcp_src()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147490306)
         obj.value = reader.read("!H")[0]
@@ -4163,13 +3554,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("tcp_src {")
         with q.group():
@@ -4180,7 +3564,9 @@
             q.breakable()
         q.text('}')
 
-class tcp_src_masked(OXM):
+oxm.subtypes[2147490306] = tcp_src
+
+class tcp_src_masked(oxm):
     type_len = 2147490564
 
     def __init__(self, value=None, value_mask=None):
@@ -4192,6 +3578,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -4201,12 +3588,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = tcp_src_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147490564)
         obj.value = reader.read("!H")[0]
@@ -4219,13 +3602,6 @@
         if self.value_mask != other.value_mask: 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("tcp_src_masked {")
         with q.group():
@@ -4239,7 +3615,9 @@
             q.breakable()
         q.text('}')
 
-class udp_dst(OXM):
+oxm.subtypes[2147490564] = tcp_src_masked
+
+class udp_dst(oxm):
     type_len = 2147491842
 
     def __init__(self, value=None):
@@ -4247,6 +3625,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -4255,12 +3634,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = udp_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147491842)
         obj.value = reader.read("!H")[0]
@@ -4271,13 +3646,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("udp_dst {")
         with q.group():
@@ -4288,7 +3656,9 @@
             q.breakable()
         q.text('}')
 
-class udp_dst_masked(OXM):
+oxm.subtypes[2147491842] = udp_dst
+
+class udp_dst_masked(oxm):
     type_len = 2147492100
 
     def __init__(self, value=None, value_mask=None):
@@ -4300,6 +3670,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -4309,12 +3680,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = udp_dst_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147492100)
         obj.value = reader.read("!H")[0]
@@ -4327,13 +3694,6 @@
         if self.value_mask != other.value_mask: 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("udp_dst_masked {")
         with q.group():
@@ -4347,7 +3707,9 @@
             q.breakable()
         q.text('}')
 
-class udp_src(OXM):
+oxm.subtypes[2147492100] = udp_dst_masked
+
+class udp_src(oxm):
     type_len = 2147491330
 
     def __init__(self, value=None):
@@ -4355,6 +3717,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -4363,12 +3726,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = udp_src()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147491330)
         obj.value = reader.read("!H")[0]
@@ -4379,13 +3738,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("udp_src {")
         with q.group():
@@ -4396,7 +3748,9 @@
             q.breakable()
         q.text('}')
 
-class udp_src_masked(OXM):
+oxm.subtypes[2147491330] = udp_src
+
+class udp_src_masked(oxm):
     type_len = 2147491588
 
     def __init__(self, value=None, value_mask=None):
@@ -4408,6 +3762,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -4417,12 +3772,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = udp_src_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147491588)
         obj.value = reader.read("!H")[0]
@@ -4435,13 +3786,6 @@
         if self.value_mask != other.value_mask: 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("udp_src_masked {")
         with q.group():
@@ -4455,7 +3799,9 @@
             q.breakable()
         q.text('}')
 
-class vlan_pcp(OXM):
+oxm.subtypes[2147491588] = udp_src_masked
+
+class vlan_pcp(oxm):
     type_len = 2147487233
 
     def __init__(self, value=None):
@@ -4463,6 +3809,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -4471,12 +3818,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = vlan_pcp()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147487233)
         obj.value = reader.read("!B")[0]
@@ -4487,13 +3830,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("vlan_pcp {")
         with q.group():
@@ -4504,7 +3840,9 @@
             q.breakable()
         q.text('}')
 
-class vlan_pcp_masked(OXM):
+oxm.subtypes[2147487233] = vlan_pcp
+
+class vlan_pcp_masked(oxm):
     type_len = 2147487490
 
     def __init__(self, value=None, value_mask=None):
@@ -4516,6 +3854,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -4525,12 +3864,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = vlan_pcp_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147487490)
         obj.value = reader.read("!B")[0]
@@ -4543,13 +3878,6 @@
         if self.value_mask != other.value_mask: 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("vlan_pcp_masked {")
         with q.group():
@@ -4563,7 +3891,9 @@
             q.breakable()
         q.text('}')
 
-class vlan_vid(OXM):
+oxm.subtypes[2147487490] = vlan_pcp_masked
+
+class vlan_vid(oxm):
     type_len = 2147486722
 
     def __init__(self, value=None):
@@ -4571,6 +3901,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -4579,12 +3910,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = vlan_vid()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147486722)
         obj.value = reader.read("!H")[0]
@@ -4595,13 +3922,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("vlan_vid {")
         with q.group():
@@ -4612,7 +3932,9 @@
             q.breakable()
         q.text('}')
 
-class vlan_vid_masked(OXM):
+oxm.subtypes[2147486722] = vlan_vid
+
+class vlan_vid_masked(oxm):
     type_len = 2147486980
 
     def __init__(self, value=None, value_mask=None):
@@ -4624,6 +3946,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -4633,12 +3956,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = vlan_vid_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147486980)
         obj.value = reader.read("!H")[0]
@@ -4651,13 +3970,6 @@
         if self.value_mask != other.value_mask: 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("vlan_vid_masked {")
         with q.group():
@@ -4671,92 +3983,6 @@
             q.breakable()
         q.text('}')
 
+oxm.subtypes[2147486980] = vlan_vid_masked
 
-parsers = {
-    196640 : bsn_in_ports_128.unpack,
-    196896 : bsn_in_ports_128_masked.unpack,
-    197124 : bsn_lag_id.unpack,
-    197380 : bsn_lag_id_masked.unpack,
-    197636 : bsn_vrf.unpack,
-    197892 : bsn_vrf_masked.unpack,
-    198145 : bsn_global_vrf_allowed.unpack,
-    198401 : bsn_global_vrf_allowed_masked.unpack,
-    198660 : bsn_l3_interface_class_id.unpack,
-    198916 : bsn_l3_interface_class_id_masked.unpack,
-    199172 : bsn_l3_src_class_id.unpack,
-    199428 : bsn_l3_src_class_id_masked.unpack,
-    199684 : bsn_l3_dst_class_id.unpack,
-    199940 : bsn_l3_dst_class_id_masked.unpack,
-    2147483652 : in_port.unpack,
-    2147483912 : in_port_masked.unpack,
-    2147484164 : in_phy_port.unpack,
-    2147484424 : in_phy_port_masked.unpack,
-    2147484680 : metadata.unpack,
-    2147484944 : metadata_masked.unpack,
-    2147485190 : eth_dst.unpack,
-    2147485452 : eth_dst_masked.unpack,
-    2147485702 : eth_src.unpack,
-    2147485964 : eth_src_masked.unpack,
-    2147486210 : eth_type.unpack,
-    2147486468 : eth_type_masked.unpack,
-    2147486722 : vlan_vid.unpack,
-    2147486980 : vlan_vid_masked.unpack,
-    2147487233 : vlan_pcp.unpack,
-    2147487490 : vlan_pcp_masked.unpack,
-    2147487745 : ip_dscp.unpack,
-    2147488002 : ip_dscp_masked.unpack,
-    2147488257 : ip_ecn.unpack,
-    2147488514 : ip_ecn_masked.unpack,
-    2147488769 : ip_proto.unpack,
-    2147489026 : ip_proto_masked.unpack,
-    2147489284 : ipv4_src.unpack,
-    2147489544 : ipv4_src_masked.unpack,
-    2147489796 : ipv4_dst.unpack,
-    2147490056 : ipv4_dst_masked.unpack,
-    2147490306 : tcp_src.unpack,
-    2147490564 : tcp_src_masked.unpack,
-    2147490818 : tcp_dst.unpack,
-    2147491076 : tcp_dst_masked.unpack,
-    2147491330 : udp_src.unpack,
-    2147491588 : udp_src_masked.unpack,
-    2147491842 : udp_dst.unpack,
-    2147492100 : udp_dst_masked.unpack,
-    2147492354 : sctp_src.unpack,
-    2147492612 : sctp_src_masked.unpack,
-    2147492866 : sctp_dst.unpack,
-    2147493124 : sctp_dst_masked.unpack,
-    2147493377 : icmpv4_type.unpack,
-    2147493634 : icmpv4_type_masked.unpack,
-    2147493889 : icmpv4_code.unpack,
-    2147494146 : icmpv4_code_masked.unpack,
-    2147494402 : arp_op.unpack,
-    2147494660 : arp_op_masked.unpack,
-    2147494916 : arp_spa.unpack,
-    2147495176 : arp_spa_masked.unpack,
-    2147495428 : arp_tpa.unpack,
-    2147495688 : arp_tpa_masked.unpack,
-    2147495942 : arp_sha.unpack,
-    2147496204 : arp_sha_masked.unpack,
-    2147496454 : arp_tha.unpack,
-    2147496716 : arp_tha_masked.unpack,
-    2147496976 : ipv6_src.unpack,
-    2147497248 : ipv6_src_masked.unpack,
-    2147497488 : ipv6_dst.unpack,
-    2147497760 : ipv6_dst_masked.unpack,
-    2147497988 : ipv6_flabel.unpack,
-    2147498248 : ipv6_flabel_masked.unpack,
-    2147498497 : icmpv6_type.unpack,
-    2147498754 : icmpv6_type_masked.unpack,
-    2147499009 : icmpv6_code.unpack,
-    2147499266 : icmpv6_code_masked.unpack,
-    2147499536 : ipv6_nd_target.unpack,
-    2147499808 : ipv6_nd_target_masked.unpack,
-    2147500038 : ipv6_nd_sll.unpack,
-    2147500300 : ipv6_nd_sll_masked.unpack,
-    2147500550 : ipv6_nd_tll.unpack,
-    2147500812 : ipv6_nd_tll_masked.unpack,
-    2147501060 : mpls_label.unpack,
-    2147501320 : mpls_label_masked.unpack,
-    2147501569 : mpls_tc.unpack,
-    2147501826 : mpls_tc_masked.unpack,
-}
+
diff --git a/src/python/loxi/of12/util.py b/src/python/loxi/of12/util.py
index b908451..59be12e 100644
--- a/src/python/loxi/of12/util.py
+++ b/src/python/loxi/of12/util.py
@@ -5,9 +5,13 @@
 # Automatically generated by LOXI from template util.py
 # Do not modify
 
+import struct
 import loxi
 import const
-import struct
+import common
+import action
+import instruction
+import oxm
 
 def pretty_mac(mac):
     return ':'.join(["%02x" % x for x in mac])
@@ -66,9 +70,6 @@
 def unpack_match_bmap(reader):
     return reader.read("!Q")[0]
 
-def pack_list(values):
-    return "".join([x.pack() for x in values])
-
 MASK64 = (1 << 64) - 1
 
 def pack_bitmap_128(value):
@@ -88,3 +89,13 @@
         i += 1
         x >>= 1
     return value
+
+def unpack_list_hello_elem(reader):
+    def deserializer(reader):
+        typ, length, = reader.peek('!HH')
+        reader = reader.slice(length)
+        try:
+            return common.hello_elem.unpack(reader)
+        except loxi.ProtocolError:
+            return None
+    return [x for x in loxi.generic_util.unpack_list(reader, deserializer) if x != None]
diff --git a/src/python/loxi/of13/action.py b/src/python/loxi/of13/action.py
index 819e724..1c1714c 100644
--- a/src/python/loxi/of13/action.py
+++ b/src/python/loxi/of13/action.py
@@ -3,28 +3,64 @@
 # 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 action.py
+# Automatically generated by LOXI from template module.py
 # Do not modify
 
 import struct
+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 loxi
-import oxm # for unpack
 
-def unpack_list(reader):
-    def deserializer(reader, typ):
-        parser = parsers.get(typ)
-        if not parser: raise loxi.ProtocolError("unknown action type %d" % typ)
-        return parser(reader)
-    return loxi.generic_util.unpack_list_tlv16(reader, deserializer)
+class action(loxi.OFObject):
+    subtypes = {}
 
-class Action(object):
-    type = None # override in subclass
-    pass
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 0)
+        try:
+            subclass = action.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown action subtype %#x" % subtype)
+        return subclass.unpack(reader)
 
-class bsn_mirror(Action):
+
+class experimenter(action):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 4)
+        try:
+            subclass = experimenter.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter action subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+action.subtypes[65535] = experimenter
+
+class bsn(experimenter):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 8)
+        try:
+            subclass = bsn.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown bsn experimenter action subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter.subtypes[6035143] = bsn
+
+class bsn_mirror(bsn):
     type = 65535
     experimenter = 6035143
     subtype = 1
@@ -59,15 +95,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_mirror()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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]
@@ -85,13 +119,6 @@
         if self.copy_stage != other.copy_stage: 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_mirror {")
         with q.group():
@@ -108,7 +135,9 @@
             q.breakable()
         q.text('}')
 
-class bsn_set_tunnel_dst(Action):
+bsn.subtypes[1] = bsn_mirror
+
+class bsn_set_tunnel_dst(bsn):
     type = 65535
     experimenter = 6035143
     subtype = 2
@@ -132,15 +161,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_set_tunnel_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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]
@@ -153,13 +180,6 @@
         if self.dst != other.dst: 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_set_tunnel_dst {")
         with q.group():
@@ -170,7 +190,9 @@
             q.breakable()
         q.text('}')
 
-class copy_ttl_in(Action):
+bsn.subtypes[2] = bsn_set_tunnel_dst
+
+class copy_ttl_in(action):
     type = 12
 
     def __init__(self):
@@ -186,15 +208,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = copy_ttl_in()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 12)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         return obj
 
@@ -202,13 +222,6 @@
         if type(self) != type(other): 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("copy_ttl_in {")
         with q.group():
@@ -217,7 +230,9 @@
             q.breakable()
         q.text('}')
 
-class copy_ttl_out(Action):
+action.subtypes[12] = copy_ttl_in
+
+class copy_ttl_out(action):
     type = 11
 
     def __init__(self):
@@ -233,15 +248,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = copy_ttl_out()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 11)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         return obj
 
@@ -249,13 +262,6 @@
         if type(self) != type(other): 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("copy_ttl_out {")
         with q.group():
@@ -264,7 +270,9 @@
             q.breakable()
         q.text('}')
 
-class dec_mpls_ttl(Action):
+action.subtypes[11] = copy_ttl_out
+
+class dec_mpls_ttl(action):
     type = 16
 
     def __init__(self):
@@ -280,15 +288,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = dec_mpls_ttl()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 16)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         return obj
 
@@ -296,13 +302,6 @@
         if type(self) != type(other): 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("dec_mpls_ttl {")
         with q.group():
@@ -311,7 +310,9 @@
             q.breakable()
         q.text('}')
 
-class dec_nw_ttl(Action):
+action.subtypes[16] = dec_mpls_ttl
+
+class dec_nw_ttl(action):
     type = 24
 
     def __init__(self):
@@ -327,15 +328,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = dec_nw_ttl()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 24)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         return obj
 
@@ -343,13 +342,6 @@
         if type(self) != type(other): 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("dec_nw_ttl {")
         with q.group():
@@ -358,7 +350,9 @@
             q.breakable()
         q.text('}')
 
-class group(Action):
+action.subtypes[24] = dec_nw_ttl
+
+class group(action):
     type = 22
 
     def __init__(self, group_id=None):
@@ -378,15 +372,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = group()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 22)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.group_id = reader.read("!L")[0]
         return obj
 
@@ -395,13 +387,6 @@
         if self.group_id != other.group_id: 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 {")
         with q.group():
@@ -412,7 +397,23 @@
             q.breakable()
         q.text('}')
 
-class nicira_dec_ttl(Action):
+action.subtypes[22] = group
+
+class nicira(experimenter):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 8)
+        try:
+            subclass = nicira.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown nicira experimenter action subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter.subtypes[8992] = nicira
+
+class nicira_dec_ttl(nicira):
     type = 65535
     experimenter = 8992
     subtype = 18
@@ -433,15 +434,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = nicira_dec_ttl()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 8992)
         _subtype = reader.read("!H")[0]
@@ -454,13 +453,6 @@
         if type(self) != type(other): 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("nicira_dec_ttl {")
         with q.group():
@@ -469,7 +461,9 @@
             q.breakable()
         q.text('}')
 
-class output(Action):
+nicira.subtypes[18] = nicira_dec_ttl
+
+class output(action):
     type = 0
 
     def __init__(self, port=None, max_len=None):
@@ -495,15 +489,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = output()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 0)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.port = util.unpack_port_no(reader)
         obj.max_len = reader.read("!H")[0]
         reader.skip(6)
@@ -515,13 +507,6 @@
         if self.max_len != other.max_len: 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("output {")
         with q.group():
@@ -535,7 +520,9 @@
             q.breakable()
         q.text('}')
 
-class pop_mpls(Action):
+action.subtypes[0] = output
+
+class pop_mpls(action):
     type = 20
 
     def __init__(self, ethertype=None):
@@ -556,15 +543,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = pop_mpls()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 20)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.ethertype = reader.read("!H")[0]
         reader.skip(2)
         return obj
@@ -574,13 +559,6 @@
         if self.ethertype != other.ethertype: 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("pop_mpls {")
         with q.group():
@@ -591,7 +569,9 @@
             q.breakable()
         q.text('}')
 
-class pop_pbb(Action):
+action.subtypes[20] = pop_mpls
+
+class pop_pbb(action):
     type = 27
 
     def __init__(self):
@@ -607,15 +587,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = pop_pbb()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 27)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         return obj
 
@@ -623,13 +601,6 @@
         if type(self) != type(other): 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("pop_pbb {")
         with q.group():
@@ -638,7 +609,9 @@
             q.breakable()
         q.text('}')
 
-class pop_vlan(Action):
+action.subtypes[27] = pop_pbb
+
+class pop_vlan(action):
     type = 18
 
     def __init__(self):
@@ -654,15 +627,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = pop_vlan()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 18)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         return obj
 
@@ -670,13 +641,6 @@
         if type(self) != type(other): 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("pop_vlan {")
         with q.group():
@@ -685,7 +649,9 @@
             q.breakable()
         q.text('}')
 
-class push_mpls(Action):
+action.subtypes[18] = pop_vlan
+
+class push_mpls(action):
     type = 19
 
     def __init__(self, ethertype=None):
@@ -706,15 +672,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = push_mpls()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 19)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.ethertype = reader.read("!H")[0]
         reader.skip(2)
         return obj
@@ -724,13 +688,6 @@
         if self.ethertype != other.ethertype: 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("push_mpls {")
         with q.group():
@@ -741,7 +698,9 @@
             q.breakable()
         q.text('}')
 
-class push_pbb(Action):
+action.subtypes[19] = push_mpls
+
+class push_pbb(action):
     type = 26
 
     def __init__(self, ethertype=None):
@@ -762,15 +721,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = push_pbb()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 26)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.ethertype = reader.read("!H")[0]
         reader.skip(2)
         return obj
@@ -780,13 +737,6 @@
         if self.ethertype != other.ethertype: 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("push_pbb {")
         with q.group():
@@ -797,7 +747,9 @@
             q.breakable()
         q.text('}')
 
-class push_vlan(Action):
+action.subtypes[26] = push_pbb
+
+class push_vlan(action):
     type = 17
 
     def __init__(self, ethertype=None):
@@ -818,15 +770,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = push_vlan()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 17)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.ethertype = reader.read("!H")[0]
         reader.skip(2)
         return obj
@@ -836,13 +786,6 @@
         if self.ethertype != other.ethertype: 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("push_vlan {")
         with q.group():
@@ -853,7 +796,9 @@
             q.breakable()
         q.text('}')
 
-class set_field(Action):
+action.subtypes[17] = push_vlan
+
+class set_field(action):
     type = 25
 
     def __init__(self, field=None):
@@ -875,17 +820,14 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_field()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 25)
         _len = reader.read("!H")[0]
-        obj.field = oxm.unpack(reader)
-        reader.skip_align()
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        obj.field = oxm.oxm.unpack(reader)
         return obj
 
     def __eq__(self, other):
@@ -893,13 +835,6 @@
         if self.field != other.field: 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("set_field {")
         with q.group():
@@ -910,7 +845,9 @@
             q.breakable()
         q.text('}')
 
-class set_mpls_ttl(Action):
+action.subtypes[25] = set_field
+
+class set_mpls_ttl(action):
     type = 15
 
     def __init__(self, mpls_ttl=None):
@@ -931,15 +868,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_mpls_ttl()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 15)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.mpls_ttl = reader.read("!B")[0]
         reader.skip(3)
         return obj
@@ -949,13 +884,6 @@
         if self.mpls_ttl != other.mpls_ttl: 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("set_mpls_ttl {")
         with q.group():
@@ -966,7 +894,9 @@
             q.breakable()
         q.text('}')
 
-class set_nw_ttl(Action):
+action.subtypes[15] = set_mpls_ttl
+
+class set_nw_ttl(action):
     type = 23
 
     def __init__(self, nw_ttl=None):
@@ -987,15 +917,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_nw_ttl()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 23)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.nw_ttl = reader.read("!B")[0]
         reader.skip(3)
         return obj
@@ -1005,13 +933,6 @@
         if self.nw_ttl != other.nw_ttl: 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("set_nw_ttl {")
         with q.group():
@@ -1022,7 +943,9 @@
             q.breakable()
         q.text('}')
 
-class set_queue(Action):
+action.subtypes[23] = set_nw_ttl
+
+class set_queue(action):
     type = 21
 
     def __init__(self, queue_id=None):
@@ -1042,15 +965,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = set_queue()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 21)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.queue_id = reader.read("!L")[0]
         return obj
 
@@ -1059,13 +980,6 @@
         if self.queue_id != other.queue_id: 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("set_queue {")
         with q.group():
@@ -1076,47 +990,6 @@
             q.breakable()
         q.text('}')
 
+action.subtypes[21] = set_queue
 
-def parse_experimenter(reader):
-    experimenter, = reader.peek("!4xL")
-    if experimenter == 0x005c16c7: # Big Switch Networks
-        subtype, = reader.peek("!8xL")
-    elif experimenter == 0x00002320: # Nicira
-        subtype, = reader.peek("!8xH")
-    else:
-        raise loxi.ProtocolError("unexpected experimenter id %#x" % experimenter)
 
-    if subtype in experimenter_parsers[experimenter]:
-        return experimenter_parsers[experimenter][subtype](reader)
-    else:
-        raise loxi.ProtocolError("unexpected BSN experimenter subtype %#x" % subtype)
-
-parsers = {
-    const.OFPAT_OUTPUT : output.unpack,
-    const.OFPAT_COPY_TTL_OUT : copy_ttl_out.unpack,
-    const.OFPAT_COPY_TTL_IN : copy_ttl_in.unpack,
-    const.OFPAT_SET_MPLS_TTL : set_mpls_ttl.unpack,
-    const.OFPAT_DEC_MPLS_TTL : dec_mpls_ttl.unpack,
-    const.OFPAT_PUSH_VLAN : push_vlan.unpack,
-    const.OFPAT_POP_VLAN : pop_vlan.unpack,
-    const.OFPAT_PUSH_MPLS : push_mpls.unpack,
-    const.OFPAT_POP_MPLS : pop_mpls.unpack,
-    const.OFPAT_SET_QUEUE : set_queue.unpack,
-    const.OFPAT_GROUP : group.unpack,
-    const.OFPAT_SET_NW_TTL : set_nw_ttl.unpack,
-    const.OFPAT_DEC_NW_TTL : dec_nw_ttl.unpack,
-    const.OFPAT_SET_FIELD : set_field.unpack,
-    const.OFPAT_PUSH_PBB : push_pbb.unpack,
-    const.OFPAT_POP_PBB : pop_pbb.unpack,
-    const.OFPAT_EXPERIMENTER : parse_experimenter,
-}
-
-experimenter_parsers = {
-    8992 : {
-        18: nicira_dec_ttl.unpack,
-    },
-    6035143 : {
-        1: bsn_mirror.unpack,
-        2: bsn_set_tunnel_dst.unpack,
-    },
-}
diff --git a/src/python/loxi/of13/action_id.py b/src/python/loxi/of13/action_id.py
new file mode 100644
index 0000000..431e112
--- /dev/null
+++ b/src/python/loxi/of13/action_id.py
@@ -0,0 +1,855 @@
+# Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University
+# 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 module.py
+# Do not modify
+
+import struct
+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
+
+class action_id(loxi.OFObject):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 0)
+        try:
+            subclass = action_id.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown action_id subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+
+class experimenter(action_id):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 4)
+        try:
+            subclass = experimenter.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter action_id subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+action_id.subtypes[65535] = experimenter
+
+class bsn(experimenter):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 8)
+        try:
+            subclass = bsn.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown bsn experimenter action_id subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter.subtypes[6035143] = bsn
+
+class bsn_mirror(bsn):
+    type = 65535
+    experimenter = 6035143
+    subtype = 1
+
+    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' * 3)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_mirror()
+        _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 == 1)
+        reader.skip(3)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_mirror {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+bsn.subtypes[1] = bsn_mirror
+
+class bsn_set_tunnel_dst(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_set_tunnel_dst()
+        _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_set_tunnel_dst {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+bsn.subtypes[2] = bsn_set_tunnel_dst
+
+class copy_ttl_in(action_id):
+    type = 12
+
+    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('\x00' * 4)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = copy_ttl_in()
+        _type = reader.read("!H")[0]
+        assert(_type == 12)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 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("copy_ttl_in {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+action_id.subtypes[12] = copy_ttl_in
+
+class copy_ttl_out(action_id):
+    type = 11
+
+    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('\x00' * 4)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = copy_ttl_out()
+        _type = reader.read("!H")[0]
+        assert(_type == 11)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 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("copy_ttl_out {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+action_id.subtypes[11] = copy_ttl_out
+
+class dec_mpls_ttl(action_id):
+    type = 16
+
+    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('\x00' * 4)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = dec_mpls_ttl()
+        _type = reader.read("!H")[0]
+        assert(_type == 16)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 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("dec_mpls_ttl {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+action_id.subtypes[16] = dec_mpls_ttl
+
+class dec_nw_ttl(action_id):
+    type = 24
+
+    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('\x00' * 4)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = dec_nw_ttl()
+        _type = reader.read("!H")[0]
+        assert(_type == 24)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 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("dec_nw_ttl {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+action_id.subtypes[24] = dec_nw_ttl
+
+class group(action_id):
+    type = 22
+
+    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
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = group()
+        _type = reader.read("!H")[0]
+        assert(_type == 22)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("group {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+action_id.subtypes[22] = group
+
+class nicira(experimenter):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 8)
+        try:
+            subclass = nicira.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown nicira experimenter action_id subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter.subtypes[8992] = nicira
+
+class nicira_dec_ttl(nicira):
+    type = 65535
+    experimenter = 8992
+    subtype = 18
+
+    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("!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)
+
+    @staticmethod
+    def unpack(reader):
+        obj = nicira_dec_ttl()
+        _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 == 8992)
+        _subtype = reader.read("!H")[0]
+        assert(_subtype == 18)
+        reader.skip(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("nicira_dec_ttl {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+nicira.subtypes[18] = nicira_dec_ttl
+
+class output(action_id):
+    type = 0
+
+    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('\x00' * 6)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = output()
+        _type = reader.read("!H")[0]
+        assert(_type == 0)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        reader.skip(6)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("output {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+action_id.subtypes[0] = output
+
+class pop_mpls(action_id):
+    type = 20
+
+    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('\x00' * 2)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = pop_mpls()
+        _type = reader.read("!H")[0]
+        assert(_type == 20)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        reader.skip(2)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("pop_mpls {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+action_id.subtypes[20] = pop_mpls
+
+class pop_pbb(action_id):
+    type = 27
+
+    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('\x00' * 4)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = pop_pbb()
+        _type = reader.read("!H")[0]
+        assert(_type == 27)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 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("pop_pbb {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+action_id.subtypes[27] = pop_pbb
+
+class pop_vlan(action_id):
+    type = 18
+
+    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('\x00' * 4)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = pop_vlan()
+        _type = reader.read("!H")[0]
+        assert(_type == 18)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 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("pop_vlan {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+action_id.subtypes[18] = pop_vlan
+
+class push_mpls(action_id):
+    type = 19
+
+    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('\x00' * 2)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = push_mpls()
+        _type = reader.read("!H")[0]
+        assert(_type == 19)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        reader.skip(2)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("push_mpls {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+action_id.subtypes[19] = push_mpls
+
+class push_pbb(action_id):
+    type = 26
+
+    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('\x00' * 2)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = push_pbb()
+        _type = reader.read("!H")[0]
+        assert(_type == 26)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        reader.skip(2)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("push_pbb {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+action_id.subtypes[26] = push_pbb
+
+class push_vlan(action_id):
+    type = 17
+
+    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('\x00' * 2)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = push_vlan()
+        _type = reader.read("!H")[0]
+        assert(_type == 17)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        reader.skip(2)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("push_vlan {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+action_id.subtypes[17] = push_vlan
+
+class set_field(action_id):
+    type = 25
+
+    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
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = set_field()
+        _type = reader.read("!H")[0]
+        assert(_type == 25)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("set_field {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+action_id.subtypes[25] = set_field
+
+class set_mpls_ttl(action_id):
+    type = 15
+
+    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('\x00' * 3)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = set_mpls_ttl()
+        _type = reader.read("!H")[0]
+        assert(_type == 15)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        reader.skip(3)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("set_mpls_ttl {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+action_id.subtypes[15] = set_mpls_ttl
+
+class set_nw_ttl(action_id):
+    type = 23
+
+    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('\x00' * 3)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = set_nw_ttl()
+        _type = reader.read("!H")[0]
+        assert(_type == 23)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        reader.skip(3)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("set_nw_ttl {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+action_id.subtypes[23] = set_nw_ttl
+
+class set_queue(action_id):
+    type = 21
+
+    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
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = set_queue()
+        _type = reader.read("!H")[0]
+        assert(_type == 21)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("set_queue {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+action_id.subtypes[21] = set_queue
+
+
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
diff --git a/src/python/loxi/of13/const.py b/src/python/loxi/of13/const.py
index 08fcf2b..af982a5 100644
--- a/src/python/loxi/of13/const.py
+++ b/src/python/loxi/of13/const.py
@@ -43,6 +43,19 @@
     255: 'BSN_PDU_SLOT_NUM_ANY',
 }
 
+# Identifiers from group of_bsn_vlan_counter_t
+OFP_BSN_VLAN_COUNTER_RX_BYTES = 0
+OFP_BSN_VLAN_COUNTER_RX_PACKETS = 1
+OFP_BSN_VLAN_COUNTER_TX_BYTES = 2
+OFP_BSN_VLAN_COUNTER_TX_PACKETS = 3
+
+of_bsn_vlan_counter_t_map = {
+    0: 'OFP_BSN_VLAN_COUNTER_RX_BYTES',
+    1: 'OFP_BSN_VLAN_COUNTER_RX_PACKETS',
+    2: 'OFP_BSN_VLAN_COUNTER_TX_BYTES',
+    3: 'OFP_BSN_VLAN_COUNTER_TX_PACKETS',
+}
+
 # Identifiers from group ofp_action_type
 OFPAT_OUTPUT = 0
 OFPAT_COPY_TTL_OUT = 11
@@ -204,6 +217,35 @@
     13: 'OFPBRC_MULTIPART_BUFFER_OVERFLOW',
 }
 
+# Identifiers from group ofp_bsn_port_counter
+OFP_BSN_PORT_COUNTER_RX_BYTES = 0
+OFP_BSN_PORT_COUNTER_RX_PACKETS_UNICAST = 1
+OFP_BSN_PORT_COUNTER_RX_PACKETS_BROADCAST = 2
+OFP_BSN_PORT_COUNTER_RX_PACKETS_MULTICAST = 3
+OFP_BSN_PORT_COUNTER_RX_DROPPED = 4
+OFP_BSN_PORT_COUNTER_RX_ERRORS = 5
+OFP_BSN_PORT_COUNTER_TX_BYTES = 6
+OFP_BSN_PORT_COUNTER_TX_PACKETS_UNICAST = 7
+OFP_BSN_PORT_COUNTER_TX_PACKETS_BROADCAST = 8
+OFP_BSN_PORT_COUNTER_TX_PACKETS_MULTICAST = 9
+OFP_BSN_PORT_COUNTER_TX_DROPPED = 10
+OFP_BSN_PORT_COUNTER_TX_ERRORS = 11
+
+ofp_bsn_port_counter_map = {
+    0: 'OFP_BSN_PORT_COUNTER_RX_BYTES',
+    1: 'OFP_BSN_PORT_COUNTER_RX_PACKETS_UNICAST',
+    2: 'OFP_BSN_PORT_COUNTER_RX_PACKETS_BROADCAST',
+    3: 'OFP_BSN_PORT_COUNTER_RX_PACKETS_MULTICAST',
+    4: 'OFP_BSN_PORT_COUNTER_RX_DROPPED',
+    5: 'OFP_BSN_PORT_COUNTER_RX_ERRORS',
+    6: 'OFP_BSN_PORT_COUNTER_TX_BYTES',
+    7: 'OFP_BSN_PORT_COUNTER_TX_PACKETS_UNICAST',
+    8: 'OFP_BSN_PORT_COUNTER_TX_PACKETS_BROADCAST',
+    9: 'OFP_BSN_PORT_COUNTER_TX_PACKETS_MULTICAST',
+    10: 'OFP_BSN_PORT_COUNTER_TX_DROPPED',
+    11: 'OFP_BSN_PORT_COUNTER_TX_ERRORS',
+}
+
 # Identifiers from group ofp_bsn_vport_q_in_q_untagged
 OF_BSN_VPORT_Q_IN_Q_UNTAGGED = 65535
 
diff --git a/src/python/loxi/of13/instruction.py b/src/python/loxi/of13/instruction.py
index b5d3fc8..e36cc73 100644
--- a/src/python/loxi/of13/instruction.py
+++ b/src/python/loxi/of13/instruction.py
@@ -3,28 +3,36 @@
 # 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 instruction.py
+# Automatically generated by LOXI from template module.py
 # Do not modify
 
 import struct
-import action
+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 loxi
 
-def unpack_list(reader):
-    def deserializer(reader, typ):
-        parser = parsers.get(typ)
-        if not parser: raise loxi.ProtocolError("unknown instruction type %d" % typ)
-        return parser(reader)
-    return loxi.generic_util.unpack_list_tlv16(reader, deserializer)
+class instruction(loxi.OFObject):
+    subtypes = {}
 
-class Instruction(object):
-    type = None # override in subclass
-    pass
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 0)
+        try:
+            subclass = instruction.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown instruction subtype %#x" % subtype)
+        return subclass.unpack(reader)
 
-class apply_actions(Instruction):
+
+class apply_actions(instruction):
     type = 4
 
     def __init__(self, actions=None):
@@ -39,23 +47,21 @@
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
         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[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = 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 == 4)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         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):
@@ -63,13 +69,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("apply_actions {")
         with q.group():
@@ -80,7 +79,37 @@
             q.breakable()
         q.text('}')
 
-class bsn_disable_src_mac_check(Instruction):
+instruction.subtypes[4] = apply_actions
+
+class experimenter(instruction):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 4)
+        try:
+            subclass = experimenter.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter instruction subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+instruction.subtypes[65535] = experimenter
+
+class bsn(experimenter):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 8)
+        try:
+            subclass = bsn.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown bsn experimenter instruction subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter.subtypes[6035143] = bsn
+
+class bsn_disable_src_mac_check(bsn):
     type = 65535
     experimenter = 6035143
     subtype = 0
@@ -100,15 +129,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_disable_src_mac_check()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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]
@@ -120,13 +147,6 @@
         if type(self) != type(other): 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_disable_src_mac_check {")
         with q.group():
@@ -135,7 +155,9 @@
             q.breakable()
         q.text('}')
 
-class clear_actions(Instruction):
+bsn.subtypes[0] = bsn_disable_src_mac_check
+
+class clear_actions(instruction):
     type = 5
 
     def __init__(self):
@@ -151,15 +173,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = clear_actions()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 5)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         reader.skip(4)
         return obj
 
@@ -167,13 +187,6 @@
         if type(self) != type(other): 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("clear_actions {")
         with q.group():
@@ -182,7 +195,9 @@
             q.breakable()
         q.text('}')
 
-class goto_table(Instruction):
+instruction.subtypes[5] = clear_actions
+
+class goto_table(instruction):
     type = 1
 
     def __init__(self, table_id=None):
@@ -203,15 +218,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = goto_table()
-        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))
         obj.table_id = reader.read("!B")[0]
         reader.skip(3)
         return obj
@@ -221,13 +234,6 @@
         if self.table_id != other.table_id: 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("goto_table {")
         with q.group():
@@ -238,7 +244,9 @@
             q.breakable()
         q.text('}')
 
-class meter(Instruction):
+instruction.subtypes[1] = goto_table
+
+class meter(instruction):
     type = 6
 
     def __init__(self, meter_id=None):
@@ -258,15 +266,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = meter()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type = reader.read("!H")[0]
         assert(_type == 6)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.meter_id = reader.read("!L")[0]
         return obj
 
@@ -275,13 +281,6 @@
         if self.meter_id != other.meter_id: 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 {")
         with q.group():
@@ -292,7 +291,9 @@
             q.breakable()
         q.text('}')
 
-class write_actions(Instruction):
+instruction.subtypes[6] = meter
+
+class write_actions(instruction):
     type = 3
 
     def __init__(self, actions=None):
@@ -307,23 +308,21 @@
         packed.append(struct.pack("!H", self.type))
         packed.append(struct.pack("!H", 0)) # placeholder for len at index 1
         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[1] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = 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 == 3)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         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):
@@ -331,13 +330,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("write_actions {")
         with q.group():
@@ -348,7 +340,9 @@
             q.breakable()
         q.text('}')
 
-class write_metadata(Instruction):
+instruction.subtypes[3] = write_actions
+
+class write_metadata(instruction):
     type = 2
 
     def __init__(self, metadata=None, metadata_mask=None):
@@ -374,15 +368,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = write_metadata()
-        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.metadata = reader.read("!Q")[0]
         obj.metadata_mask = reader.read("!Q")[0]
@@ -394,13 +386,6 @@
         if self.metadata_mask != other.metadata_mask: 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("write_metadata {")
         with q.group():
@@ -414,31 +399,6 @@
             q.breakable()
         q.text('}')
 
+instruction.subtypes[2] = write_metadata
 
-def parse_experimenter(reader):
-    experimenter, = reader.peek("!4xL")
-    if experimenter == 0x005c16c7: # Big Switch Networks
-        subtype, = reader.peek("!8xL")
-    else:
-        raise loxi.ProtocolError("unexpected experimenter id %#x" % experimenter)
 
-    if subtype in experimenter_parsers[experimenter]:
-        return experimenter_parsers[experimenter][subtype](reader)
-    else:
-        raise loxi.ProtocolError("unexpected experimenter id %#x subtype %#x" % (experimenter, subtype))
-
-parsers = {
-    const.OFPIT_GOTO_TABLE : goto_table.unpack,
-    const.OFPIT_WRITE_METADATA : write_metadata.unpack,
-    const.OFPIT_WRITE_ACTIONS : write_actions.unpack,
-    const.OFPIT_APPLY_ACTIONS : apply_actions.unpack,
-    const.OFPIT_CLEAR_ACTIONS : clear_actions.unpack,
-    const.OFPIT_METER : meter.unpack,
-    const.OFPIT_EXPERIMENTER : parse_experimenter,
-}
-
-experimenter_parsers = {
-    6035143 : {
-        0: bsn_disable_src_mac_check.unpack,
-    },
-}
diff --git a/src/python/loxi/of13/instruction_id.py b/src/python/loxi/of13/instruction_id.py
new file mode 100644
index 0000000..752788a
--- /dev/null
+++ b/src/python/loxi/of13/instruction_id.py
@@ -0,0 +1,349 @@
+# Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University
+# 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 module.py
+# Do not modify
+
+import struct
+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
+
+class instruction_id(loxi.OFObject):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 0)
+        try:
+            subclass = instruction_id.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown instruction_id subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+
+class apply_actions(instruction_id):
+    type = 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('\x00' * 4)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = apply_actions()
+        _type = reader.read("!H")[0]
+        assert(_type == 4)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 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("apply_actions {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+instruction_id.subtypes[4] = apply_actions
+
+class experimenter(instruction_id):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 4)
+        try:
+            subclass = experimenter.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter instruction_id subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+instruction_id.subtypes[65535] = experimenter
+
+class bsn(experimenter):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 8)
+        try:
+            subclass = bsn.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown bsn experimenter instruction_id subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter.subtypes[6035143] = bsn
+
+class bsn_disable_src_mac_check(bsn):
+    type = 65535
+    experimenter = 6035143
+    subtype = 0
+
+    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_src_mac_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 == 0)
+        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_src_mac_check {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+bsn.subtypes[0] = bsn_disable_src_mac_check
+
+class clear_actions(instruction_id):
+    type = 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('\x00' * 4)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = clear_actions()
+        _type = reader.read("!H")[0]
+        assert(_type == 5)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 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("clear_actions {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+instruction_id.subtypes[5] = clear_actions
+
+class goto_table(instruction_id):
+    type = 1
+
+    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('\x00' * 3)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = goto_table()
+        _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(3)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("goto_table {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+instruction_id.subtypes[1] = goto_table
+
+class meter(instruction_id):
+    type = 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
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = meter()
+        _type = reader.read("!H")[0]
+        assert(_type == 6)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("meter {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+instruction_id.subtypes[6] = meter
+
+class write_actions(instruction_id):
+    type = 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('\x00' * 4)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = write_actions()
+        _type = reader.read("!H")[0]
+        assert(_type == 3)
+        _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 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("write_actions {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+instruction_id.subtypes[3] = write_actions
+
+class write_metadata(instruction_id):
+    type = 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('\x00' * 4)
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = write_metadata()
+        _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)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("write_metadata {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+            q.breakable()
+        q.text('}')
+
+instruction_id.subtypes[2] = write_metadata
+
+
diff --git a/src/python/loxi/of13/message.py b/src/python/loxi/of13/message.py
index 9de2440..2737bd1 100644
--- a/src/python/loxi/of13/message.py
+++ b/src/python/loxi/of13/message.py
@@ -3,31 +3,59 @@
 # 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 message.py
+# Automatically generated by LOXI from template module.py
 # Do not modify
 
 import struct
 import loxi
 import const
 import common
-import action # for unpack_list
-import instruction # for unpack_list
-import meter_band # for unpack_list
+import action
+import instruction
+import oxm
+import action_id
+import instruction_id
+import meter_band
 import util
 import loxi.generic_util
 
-class Message(object):
-    version = const.OFP_VERSION
-    type = None # override in subclass
-    xid = None
+class message(loxi.OFObject):
+    subtypes = {}
 
-class aggregate_stats_reply(Message):
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('B', 1)
+        try:
+            subclass = message.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+
+class stats_reply(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 8)
+        try:
+            subclass = stats_reply.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown stats_reply message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[19] = stats_reply
+
+class aggregate_stats_reply(stats_reply):
     version = 4
     type = 19
     stats_type = 2
 
     def __init__(self, xid=None, flags=None, packet_count=None, byte_count=None, flow_count=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -44,6 +72,7 @@
             self.flow_count = flow_count
         else:
             self.flow_count = 0
+        return
 
     def pack(self):
         packed = []
@@ -63,18 +92,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = aggregate_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 2)
@@ -88,8 +114,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.packet_count != other.packet_count: return False
@@ -97,16 +121,6 @@
         if self.flow_count != other.flow_count: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("aggregate_stats_reply {")
         with q.group():
@@ -132,13 +146,32 @@
             q.breakable()
         q.text('}')
 
-class aggregate_stats_request(Message):
+stats_reply.subtypes[2] = aggregate_stats_reply
+
+class stats_request(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 8)
+        try:
+            subclass = stats_request.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown stats_request message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[18] = stats_request
+
+class aggregate_stats_request(stats_request):
     version = 4
     type = 18
     stats_type = 2
 
     def __init__(self, xid=None, flags=None, table_id=None, out_port=None, out_group=None, cookie=None, cookie_mask=None, match=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -167,6 +200,7 @@
             self.match = match
         else:
             self.match = common.match()
+        return
 
     def pack(self):
         packed = []
@@ -190,18 +224,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = aggregate_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 2)
@@ -219,8 +250,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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
@@ -231,16 +260,6 @@
         if self.match != other.match: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("aggregate_stats_request {")
         with q.group():
@@ -275,12 +294,17 @@
             q.breakable()
         q.text('}')
 
-class async_get_reply(Message):
+stats_request.subtypes[2] = aggregate_stats_request
+
+class async_get_reply(message):
     version = 4
     type = 27
 
     def __init__(self, xid=None, packet_in_mask_equal_master=None, packet_in_mask_slave=None, port_status_mask_equal_master=None, port_status_mask_slave=None, flow_removed_mask_equal_master=None, flow_removed_mask_slave=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if packet_in_mask_equal_master != None:
             self.packet_in_mask_equal_master = packet_in_mask_equal_master
         else:
@@ -305,6 +329,7 @@
             self.flow_removed_mask_slave = flow_removed_mask_slave
         else:
             self.flow_removed_mask_slave = 0
+        return
 
     def pack(self):
         packed = []
@@ -323,18 +348,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = async_get_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 27)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.packet_in_mask_equal_master = reader.read("!L")[0]
         obj.packet_in_mask_slave = reader.read("!L")[0]
@@ -346,8 +368,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.packet_in_mask_equal_master != other.packet_in_mask_equal_master: return False
         if self.packet_in_mask_slave != other.packet_in_mask_slave: return False
@@ -357,16 +377,6 @@
         if self.flow_removed_mask_slave != other.flow_removed_mask_slave: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("async_get_reply {")
         with q.group():
@@ -398,12 +408,17 @@
             q.breakable()
         q.text('}')
 
-class async_get_request(Message):
+message.subtypes[27] = async_get_reply
+
+class async_get_request(message):
     version = 4
     type = 26
 
     def __init__(self, xid=None, packet_in_mask_equal_master=None, packet_in_mask_slave=None, port_status_mask_equal_master=None, port_status_mask_slave=None, flow_removed_mask_equal_master=None, flow_removed_mask_slave=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if packet_in_mask_equal_master != None:
             self.packet_in_mask_equal_master = packet_in_mask_equal_master
         else:
@@ -428,6 +443,7 @@
             self.flow_removed_mask_slave = flow_removed_mask_slave
         else:
             self.flow_removed_mask_slave = 0
+        return
 
     def pack(self):
         packed = []
@@ -446,18 +462,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = async_get_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 26)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.packet_in_mask_equal_master = reader.read("!L")[0]
         obj.packet_in_mask_slave = reader.read("!L")[0]
@@ -469,8 +482,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.packet_in_mask_equal_master != other.packet_in_mask_equal_master: return False
         if self.packet_in_mask_slave != other.packet_in_mask_slave: return False
@@ -480,16 +491,6 @@
         if self.flow_removed_mask_slave != other.flow_removed_mask_slave: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("async_get_request {")
         with q.group():
@@ -521,12 +522,17 @@
             q.breakable()
         q.text('}')
 
-class async_set(Message):
+message.subtypes[26] = async_get_request
+
+class async_set(message):
     version = 4
     type = 28
 
     def __init__(self, xid=None, packet_in_mask_equal_master=None, packet_in_mask_slave=None, port_status_mask_equal_master=None, port_status_mask_slave=None, flow_removed_mask_equal_master=None, flow_removed_mask_slave=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if packet_in_mask_equal_master != None:
             self.packet_in_mask_equal_master = packet_in_mask_equal_master
         else:
@@ -551,6 +557,7 @@
             self.flow_removed_mask_slave = flow_removed_mask_slave
         else:
             self.flow_removed_mask_slave = 0
+        return
 
     def pack(self):
         packed = []
@@ -569,18 +576,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = async_set()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 28)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.packet_in_mask_equal_master = reader.read("!L")[0]
         obj.packet_in_mask_slave = reader.read("!L")[0]
@@ -592,8 +596,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.packet_in_mask_equal_master != other.packet_in_mask_equal_master: return False
         if self.packet_in_mask_slave != other.packet_in_mask_slave: return False
@@ -603,16 +605,6 @@
         if self.flow_removed_mask_slave != other.flow_removed_mask_slave: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("async_set {")
         with q.group():
@@ -644,13 +636,32 @@
             q.breakable()
         q.text('}')
 
-class bad_action_error_msg(Message):
+message.subtypes[28] = async_set
+
+class error_msg(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 8)
+        try:
+            subclass = error_msg.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown error_msg message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[1] = error_msg
+
+class bad_action_error_msg(error_msg):
     version = 4
     type = 1
     err_type = 2
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -659,6 +670,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -674,18 +686,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bad_action_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 2)
@@ -695,23 +704,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bad_action_error_msg {")
         with q.group():
@@ -731,13 +728,18 @@
             q.breakable()
         q.text('}')
 
-class bad_instruction_error_msg(Message):
+error_msg.subtypes[2] = bad_action_error_msg
+
+class bad_instruction_error_msg(error_msg):
     version = 4
     type = 1
     err_type = 3
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -746,6 +748,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -761,18 +764,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bad_instruction_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 3)
@@ -782,23 +782,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bad_instruction_error_msg {")
         with q.group():
@@ -818,13 +806,18 @@
             q.breakable()
         q.text('}')
 
-class bad_match_error_msg(Message):
+error_msg.subtypes[3] = bad_instruction_error_msg
+
+class bad_match_error_msg(error_msg):
     version = 4
     type = 1
     err_type = 4
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -833,6 +826,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -848,18 +842,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bad_match_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 4)
@@ -869,23 +860,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bad_match_error_msg {")
         with q.group():
@@ -905,13 +884,18 @@
             q.breakable()
         q.text('}')
 
-class bad_request_error_msg(Message):
+error_msg.subtypes[4] = bad_match_error_msg
+
+class bad_request_error_msg(error_msg):
     version = 4
     type = 1
     err_type = 1
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -920,6 +904,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -935,18 +920,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bad_request_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 1)
@@ -956,23 +938,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bad_request_error_msg {")
         with q.group():
@@ -992,12 +962,18 @@
             q.breakable()
         q.text('}')
 
-class barrier_reply(Message):
+error_msg.subtypes[1] = bad_request_error_msg
+
+class barrier_reply(message):
     version = 4
     type = 21
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -1010,38 +986,23 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = barrier_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 21)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("barrier_reply {")
         with q.group():
@@ -1055,12 +1016,18 @@
             q.breakable()
         q.text('}')
 
-class barrier_request(Message):
+message.subtypes[21] = barrier_reply
+
+class barrier_request(message):
     version = 4
     type = 20
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -1073,38 +1040,23 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = barrier_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 20)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("barrier_request {")
         with q.group():
@@ -1118,18 +1070,52 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_clear_data_reply(Message):
+message.subtypes[20] = barrier_request
+
+class experimenter(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 8)
+        try:
+            subclass = experimenter.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[4] = experimenter
+
+class bsn_header(experimenter):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 12)
+        try:
+            subclass = bsn_header.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown bsn_header experimenter message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter.subtypes[6035143] = bsn_header
+
+class bsn_bw_clear_data_reply(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 22
 
     def __init__(self, xid=None, status=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
             self.status = 0
+        return
 
     def pack(self):
         packed = []
@@ -1145,18 +1131,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_clear_data_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -1167,22 +1150,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_clear_data_reply {")
         with q.group():
@@ -1199,14 +1170,20 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_clear_data_request(Message):
+bsn_header.subtypes[22] = bsn_bw_clear_data_reply
+
+class bsn_bw_clear_data_request(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 21
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -1221,18 +1198,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_clear_data_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -1242,21 +1216,9 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_clear_data_request {")
         with q.group():
@@ -1270,18 +1232,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_enable_get_reply(Message):
+bsn_header.subtypes[21] = bsn_bw_clear_data_request
+
+class bsn_bw_enable_get_reply(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 20
 
     def __init__(self, xid=None, enabled=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if enabled != None:
             self.enabled = enabled
         else:
             self.enabled = 0
+        return
 
     def pack(self):
         packed = []
@@ -1297,18 +1265,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_enable_get_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -1319,22 +1284,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.enabled != other.enabled: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_enable_get_reply {")
         with q.group():
@@ -1351,14 +1304,20 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_enable_get_request(Message):
+bsn_header.subtypes[20] = bsn_bw_enable_get_reply
+
+class bsn_bw_enable_get_request(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 19
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -1373,18 +1332,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_enable_get_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -1394,21 +1350,9 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_enable_get_request {")
         with q.group():
@@ -1422,14 +1366,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_enable_set_reply(Message):
+bsn_header.subtypes[19] = bsn_bw_enable_get_request
+
+class bsn_bw_enable_set_reply(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 23
 
     def __init__(self, xid=None, enable=None, status=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if enable != None:
             self.enable = enable
         else:
@@ -1438,6 +1387,7 @@
             self.status = status
         else:
             self.status = 0
+        return
 
     def pack(self):
         packed = []
@@ -1454,18 +1404,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_enable_set_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -1477,23 +1424,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.enable != other.enable: return False
         if self.status != other.status: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_enable_set_reply {")
         with q.group():
@@ -1513,18 +1448,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_bw_enable_set_request(Message):
+bsn_header.subtypes[23] = bsn_bw_enable_set_reply
+
+class bsn_bw_enable_set_request(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 18
 
     def __init__(self, xid=None, enable=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if enable != None:
             self.enable = enable
         else:
             self.enable = 0
+        return
 
     def pack(self):
         packed = []
@@ -1540,18 +1481,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_bw_enable_set_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -1562,22 +1500,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.enable != other.enable: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_bw_enable_set_request {")
         with q.group():
@@ -1594,14 +1520,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_flow_idle(Message):
+bsn_header.subtypes[18] = bsn_bw_enable_set_request
+
+class bsn_flow_idle(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 40
 
     def __init__(self, xid=None, cookie=None, priority=None, table_id=None, match=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if cookie != None:
             self.cookie = cookie
         else:
@@ -1618,6 +1549,7 @@
             self.match = match
         else:
             self.match = common.match()
+        return
 
     def pack(self):
         packed = []
@@ -1637,18 +1569,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_flow_idle()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -1663,8 +1592,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.cookie != other.cookie: return False
         if self.priority != other.priority: return False
@@ -1672,16 +1599,6 @@
         if self.match != other.match: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_flow_idle {")
         with q.group():
@@ -1707,18 +1624,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_flow_idle_enable_get_reply(Message):
+bsn_header.subtypes[40] = bsn_flow_idle
+
+class bsn_flow_idle_enable_get_reply(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 39
 
     def __init__(self, xid=None, enabled=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if enabled != None:
             self.enabled = enabled
         else:
             self.enabled = 0
+        return
 
     def pack(self):
         packed = []
@@ -1734,18 +1657,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_flow_idle_enable_get_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -1756,22 +1676,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.enabled != other.enabled: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_flow_idle_enable_get_reply {")
         with q.group():
@@ -1788,14 +1696,20 @@
             q.breakable()
         q.text('}')
 
-class bsn_flow_idle_enable_get_request(Message):
+bsn_header.subtypes[39] = bsn_flow_idle_enable_get_reply
+
+class bsn_flow_idle_enable_get_request(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 38
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -1810,18 +1724,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_flow_idle_enable_get_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -1831,21 +1742,9 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_flow_idle_enable_get_request {")
         with q.group():
@@ -1859,14 +1758,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_flow_idle_enable_set_reply(Message):
+bsn_header.subtypes[38] = bsn_flow_idle_enable_get_request
+
+class bsn_flow_idle_enable_set_reply(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 37
 
     def __init__(self, xid=None, enable=None, status=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if enable != None:
             self.enable = enable
         else:
@@ -1875,6 +1779,7 @@
             self.status = status
         else:
             self.status = 0
+        return
 
     def pack(self):
         packed = []
@@ -1891,18 +1796,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_flow_idle_enable_set_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -1914,23 +1816,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.enable != other.enable: return False
         if self.status != other.status: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_flow_idle_enable_set_reply {")
         with q.group():
@@ -1950,18 +1840,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_flow_idle_enable_set_request(Message):
+bsn_header.subtypes[37] = bsn_flow_idle_enable_set_reply
+
+class bsn_flow_idle_enable_set_request(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 36
 
     def __init__(self, xid=None, enable=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if enable != None:
             self.enable = enable
         else:
             self.enable = 0
+        return
 
     def pack(self):
         packed = []
@@ -1977,18 +1873,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_flow_idle_enable_set_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -1999,22 +1892,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.enable != other.enable: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_flow_idle_enable_set_request {")
         with q.group():
@@ -2031,18 +1912,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_get_interfaces_reply(Message):
+bsn_header.subtypes[36] = bsn_flow_idle_enable_set_request
+
+class bsn_get_interfaces_reply(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 10
 
     def __init__(self, xid=None, interfaces=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if interfaces != None:
             self.interfaces = interfaces
         else:
             self.interfaces = []
+        return
 
     def pack(self):
         packed = []
@@ -2052,24 +1939,21 @@
         packed.append(struct.pack("!L", self.xid))
         packed.append(struct.pack("!L", self.experimenter))
         packed.append(struct.pack("!L", self.subtype))
-        packed.append(util.pack_list(self.interfaces))
+        packed.append(loxi.generic_util.pack_list(self.interfaces))
         length = sum([len(x) for x in packed])
         packed[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_get_interfaces_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -2080,22 +1964,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.interfaces != other.interfaces: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_get_interfaces_reply {")
         with q.group():
@@ -2112,14 +1984,20 @@
             q.breakable()
         q.text('}')
 
-class bsn_get_interfaces_request(Message):
+bsn_header.subtypes[10] = bsn_get_interfaces_reply
+
+class bsn_get_interfaces_request(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 9
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -2134,18 +2012,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_get_interfaces_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -2155,21 +2030,9 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_get_interfaces_request {")
         with q.group():
@@ -2183,18 +2046,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_get_mirroring_reply(Message):
+bsn_header.subtypes[9] = bsn_get_interfaces_request
+
+class bsn_get_mirroring_reply(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 5
 
     def __init__(self, xid=None, report_mirror_ports=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if report_mirror_ports != None:
             self.report_mirror_ports = report_mirror_ports
         else:
             self.report_mirror_ports = 0
+        return
 
     def pack(self):
         packed = []
@@ -2211,18 +2080,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_get_mirroring_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -2234,22 +2100,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.report_mirror_ports != other.report_mirror_ports: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_get_mirroring_reply {")
         with q.group():
@@ -2266,18 +2120,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_get_mirroring_request(Message):
+bsn_header.subtypes[5] = bsn_get_mirroring_reply
+
+class bsn_get_mirroring_request(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 4
 
     def __init__(self, xid=None, report_mirror_ports=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if report_mirror_ports != None:
             self.report_mirror_ports = report_mirror_ports
         else:
             self.report_mirror_ports = 0
+        return
 
     def pack(self):
         packed = []
@@ -2294,18 +2154,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_get_mirroring_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -2317,22 +2174,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.report_mirror_ports != other.report_mirror_ports: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_get_mirroring_request {")
         with q.group():
@@ -2349,14 +2194,153 @@
             q.breakable()
         q.text('}')
 
-class bsn_lacp_convergence_notif(Message):
+bsn_header.subtypes[4] = bsn_get_mirroring_request
+
+class bsn_get_switch_pipeline_reply(bsn_header):
+    version = 4
+    type = 4
+    experimenter = 6035143
+    subtype = 52
+
+    def __init__(self, xid=None, pipeline=None):
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        if pipeline != None:
+            self.pipeline = pipeline
+        else:
+            self.pipeline = ""
+        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("!256s", self.pipeline))
+        length = sum([len(x) for x in packed])
+        packed[2] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_get_switch_pipeline_reply()
+        _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 == 52)
+        obj.pipeline = reader.read("!256s")[0].rstrip("\x00")
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.xid != other.xid: return False
+        if self.pipeline != other.pipeline: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_get_switch_pipeline_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("pipeline = ");
+                q.pp(self.pipeline)
+            q.breakable()
+        q.text('}')
+
+bsn_header.subtypes[52] = bsn_get_switch_pipeline_reply
+
+class bsn_get_switch_pipeline_request(bsn_header):
+    version = 4
+    type = 4
+    experimenter = 6035143
+    subtype = 51
+
+    def __init__(self, xid=None):
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        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))
+        length = sum([len(x) for x in packed])
+        packed[2] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_get_switch_pipeline_request()
+        _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 == 51)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.xid != other.xid: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_get_switch_pipeline_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.breakable()
+        q.text('}')
+
+bsn_header.subtypes[51] = bsn_get_switch_pipeline_request
+
+class bsn_lacp_convergence_notif(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 43
 
     def __init__(self, xid=None, convergence_status=None, port_no=None, actor_sys_priority=None, actor_sys_mac=None, actor_port_priority=None, actor_port_num=None, actor_key=None, partner_sys_priority=None, partner_sys_mac=None, partner_port_priority=None, partner_port_num=None, partner_key=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if convergence_status != None:
             self.convergence_status = convergence_status
         else:
@@ -2405,6 +2389,7 @@
             self.partner_key = partner_key
         else:
             self.partner_key = 0
+        return
 
     def pack(self):
         packed = []
@@ -2432,18 +2417,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_lacp_convergence_notif()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -2466,8 +2448,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.convergence_status != other.convergence_status: return False
         if self.port_no != other.port_no: return False
@@ -2483,16 +2463,6 @@
         if self.partner_key != other.partner_key: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_lacp_convergence_notif {")
         with q.group():
@@ -2542,7 +2512,37 @@
             q.breakable()
         q.text('}')
 
-class bsn_lacp_stats_reply(Message):
+bsn_header.subtypes[43] = bsn_lacp_convergence_notif
+
+class experimenter_stats_reply(stats_reply):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 16)
+        try:
+            subclass = experimenter_stats_reply.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter_stats_reply stats_reply message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+stats_reply.subtypes[65535] = experimenter_stats_reply
+
+class bsn_stats_reply(experimenter_stats_reply):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 20)
+        try:
+            subclass = bsn_stats_reply.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown bsn_stats_reply experimenter_stats_reply stats_reply message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter_stats_reply.subtypes[6035143] = bsn_stats_reply
+
+class bsn_lacp_stats_reply(bsn_stats_reply):
     version = 4
     type = 19
     stats_type = 65535
@@ -2550,7 +2550,10 @@
     subtype = 1
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -2559,6 +2562,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -2571,24 +2575,21 @@
         packed.append('\x00' * 4)
         packed.append(struct.pack("!L", self.experimenter))
         packed.append(struct.pack("!L", self.subtype))
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_lacp_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -2603,23 +2604,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_lacp_stats_reply {")
         with q.group():
@@ -2639,7 +2628,37 @@
             q.breakable()
         q.text('}')
 
-class bsn_lacp_stats_request(Message):
+bsn_stats_reply.subtypes[1] = bsn_lacp_stats_reply
+
+class experimenter_stats_request(stats_request):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 16)
+        try:
+            subclass = experimenter_stats_request.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown experimenter_stats_request stats_request message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+stats_request.subtypes[65535] = experimenter_stats_request
+
+class bsn_stats_request(experimenter_stats_request):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 20)
+        try:
+            subclass = bsn_stats_request.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown bsn_stats_request experimenter_stats_request stats_request message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter_stats_request.subtypes[6035143] = bsn_stats_request
+
+class bsn_lacp_stats_request(bsn_stats_request):
     version = 4
     type = 18
     stats_type = 65535
@@ -2647,11 +2666,15 @@
     subtype = 1
 
     def __init__(self, xid=None, flags=None):
-        self.xid = xid
+        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 = []
@@ -2669,18 +2692,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_lacp_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -2694,22 +2714,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_lacp_stats_request {")
         with q.group():
@@ -2726,14 +2734,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_pdu_rx_reply(Message):
+bsn_stats_request.subtypes[1] = bsn_lacp_stats_request
+
+class bsn_pdu_rx_reply(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 34
 
     def __init__(self, xid=None, status=None, port_no=None, slot_num=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
@@ -2746,6 +2759,7 @@
             self.slot_num = slot_num
         else:
             self.slot_num = 0
+        return
 
     def pack(self):
         packed = []
@@ -2763,18 +2777,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_pdu_rx_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -2787,24 +2798,12 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         if self.port_no != other.port_no: return False
         if self.slot_num != other.slot_num: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_pdu_rx_reply {")
         with q.group():
@@ -2827,14 +2826,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_pdu_rx_request(Message):
+bsn_header.subtypes[34] = bsn_pdu_rx_reply
+
+class bsn_pdu_rx_request(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 33
 
     def __init__(self, xid=None, timeout_ms=None, port_no=None, slot_num=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if timeout_ms != None:
             self.timeout_ms = timeout_ms
         else:
@@ -2851,6 +2855,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -2870,18 +2875,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_pdu_rx_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -2896,8 +2898,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.timeout_ms != other.timeout_ms: return False
         if self.port_no != other.port_no: return False
@@ -2905,16 +2905,6 @@
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_pdu_rx_request {")
         with q.group():
@@ -2940,14 +2930,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_pdu_rx_timeout(Message):
+bsn_header.subtypes[33] = bsn_pdu_rx_request
+
+class bsn_pdu_rx_timeout(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 35
 
     def __init__(self, xid=None, port_no=None, slot_num=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if port_no != None:
             self.port_no = port_no
         else:
@@ -2956,6 +2951,7 @@
             self.slot_num = slot_num
         else:
             self.slot_num = 0
+        return
 
     def pack(self):
         packed = []
@@ -2972,18 +2968,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_pdu_rx_timeout()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -2995,23 +2988,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.port_no != other.port_no: return False
         if self.slot_num != other.slot_num: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_pdu_rx_timeout {")
         with q.group():
@@ -3031,14 +3012,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_pdu_tx_reply(Message):
+bsn_header.subtypes[35] = bsn_pdu_rx_timeout
+
+class bsn_pdu_tx_reply(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 32
 
     def __init__(self, xid=None, status=None, port_no=None, slot_num=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
@@ -3051,6 +3037,7 @@
             self.slot_num = slot_num
         else:
             self.slot_num = 0
+        return
 
     def pack(self):
         packed = []
@@ -3068,18 +3055,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_pdu_tx_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -3092,24 +3076,12 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         if self.port_no != other.port_no: return False
         if self.slot_num != other.slot_num: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_pdu_tx_reply {")
         with q.group():
@@ -3132,14 +3104,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_pdu_tx_request(Message):
+bsn_header.subtypes[32] = bsn_pdu_tx_reply
+
+class bsn_pdu_tx_request(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 31
 
     def __init__(self, xid=None, tx_interval_ms=None, port_no=None, slot_num=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if tx_interval_ms != None:
             self.tx_interval_ms = tx_interval_ms
         else:
@@ -3156,6 +3133,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -3175,18 +3153,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_pdu_tx_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -3201,8 +3176,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.tx_interval_ms != other.tx_interval_ms: return False
         if self.port_no != other.port_no: return False
@@ -3210,16 +3183,6 @@
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_pdu_tx_request {")
         with q.group():
@@ -3245,14 +3208,195 @@
             q.breakable()
         q.text('}')
 
-class bsn_set_lacp_reply(Message):
+bsn_header.subtypes[31] = bsn_pdu_tx_request
+
+class bsn_port_counter_stats_reply(bsn_stats_reply):
+    version = 4
+    type = 19
+    stats_type = 65535
+    experimenter = 6035143
+    subtype = 8
+
+    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_port_counter_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 == 8)
+        obj.entries = loxi.generic_util.unpack_list(reader, common.bsn_port_counter_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_port_counter_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[8] = bsn_port_counter_stats_reply
+
+class bsn_port_counter_stats_request(bsn_stats_request):
+    version = 4
+    type = 18
+    stats_type = 65535
+    experimenter = 6035143
+    subtype = 8
+
+    def __init__(self, xid=None, flags=None, port_no=None):
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        if flags != None:
+            self.flags = flags
+        else:
+            self.flags = 0
+        if port_no != None:
+            self.port_no = port_no
+        else:
+            self.port_no = 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(util.pack_port_no(self.port_no))
+        length = sum([len(x) for x in packed])
+        packed[2] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_port_counter_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 == 8)
+        obj.port_no = util.unpack_port_no(reader)
+        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.port_no != other.port_no: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_port_counter_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("port_no = ");
+                q.text(util.pretty_port(self.port_no))
+            q.breakable()
+        q.text('}')
+
+bsn_stats_request.subtypes[8] = bsn_port_counter_stats_request
+
+class bsn_set_lacp_reply(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 42
 
     def __init__(self, xid=None, status=None, port_no=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
@@ -3261,6 +3405,7 @@
             self.port_no = port_no
         else:
             self.port_no = 0
+        return
 
     def pack(self):
         packed = []
@@ -3277,18 +3422,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_set_lacp_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -3300,23 +3442,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         if self.port_no != other.port_no: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_set_lacp_reply {")
         with q.group():
@@ -3336,14 +3466,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_set_lacp_request(Message):
+bsn_header.subtypes[42] = bsn_set_lacp_reply
+
+class bsn_set_lacp_request(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 41
 
     def __init__(self, xid=None, enabled=None, port_no=None, actor_sys_priority=None, actor_sys_mac=None, actor_port_priority=None, actor_port_num=None, actor_key=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if enabled != None:
             self.enabled = enabled
         else:
@@ -3372,6 +3507,7 @@
             self.actor_key = actor_key
         else:
             self.actor_key = 0
+        return
 
     def pack(self):
         packed = []
@@ -3394,18 +3530,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_set_lacp_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -3423,8 +3556,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.enabled != other.enabled: return False
         if self.port_no != other.port_no: return False
@@ -3435,16 +3566,6 @@
         if self.actor_key != other.actor_key: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_set_lacp_request {")
         with q.group():
@@ -3479,18 +3600,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_set_mirroring(Message):
+bsn_header.subtypes[41] = bsn_set_lacp_request
+
+class bsn_set_mirroring(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 3
 
     def __init__(self, xid=None, report_mirror_ports=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if report_mirror_ports != None:
             self.report_mirror_ports = report_mirror_ports
         else:
             self.report_mirror_ports = 0
+        return
 
     def pack(self):
         packed = []
@@ -3507,18 +3634,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_set_mirroring()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -3530,22 +3654,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.report_mirror_ports != other.report_mirror_ports: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_set_mirroring {")
         with q.group():
@@ -3562,18 +3674,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_set_pktin_suppression_reply(Message):
+bsn_header.subtypes[3] = bsn_set_mirroring
+
+class bsn_set_pktin_suppression_reply(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 25
 
     def __init__(self, xid=None, status=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
             self.status = 0
+        return
 
     def pack(self):
         packed = []
@@ -3589,18 +3707,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_set_pktin_suppression_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -3611,22 +3726,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_set_pktin_suppression_reply {")
         with q.group():
@@ -3643,14 +3746,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_set_pktin_suppression_request(Message):
+bsn_header.subtypes[25] = bsn_set_pktin_suppression_reply
+
+class bsn_set_pktin_suppression_request(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 11
 
     def __init__(self, xid=None, enabled=None, idle_timeout=None, hard_timeout=None, priority=None, cookie=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if enabled != None:
             self.enabled = enabled
         else:
@@ -3671,6 +3779,7 @@
             self.cookie = cookie
         else:
             self.cookie = 0
+        return
 
     def pack(self):
         packed = []
@@ -3691,18 +3800,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_set_pktin_suppression_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -3718,8 +3824,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.enabled != other.enabled: return False
         if self.idle_timeout != other.idle_timeout: return False
@@ -3728,16 +3832,6 @@
         if self.cookie != other.cookie: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_set_pktin_suppression_request {")
         with q.group():
@@ -3766,18 +3860,334 @@
             q.breakable()
         q.text('}')
 
-class bsn_time_reply(Message):
+bsn_header.subtypes[11] = bsn_set_pktin_suppression_request
+
+class bsn_set_switch_pipeline_reply(bsn_header):
+    version = 4
+    type = 4
+    experimenter = 6035143
+    subtype = 54
+
+    def __init__(self, xid=None, status=None):
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        if status != None:
+            self.status = status
+        else:
+            self.status = 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("!L", self.status))
+        length = sum([len(x) for x in packed])
+        packed[2] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_set_switch_pipeline_reply()
+        _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 == 54)
+        obj.status = 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.status != other.status: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_set_switch_pipeline_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("status = ");
+                q.text("%#x" % self.status)
+            q.breakable()
+        q.text('}')
+
+bsn_header.subtypes[54] = bsn_set_switch_pipeline_reply
+
+class bsn_set_switch_pipeline_request(bsn_header):
+    version = 4
+    type = 4
+    experimenter = 6035143
+    subtype = 53
+
+    def __init__(self, xid=None, pipeline=None):
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        if pipeline != None:
+            self.pipeline = pipeline
+        else:
+            self.pipeline = ""
+        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("!256s", self.pipeline))
+        length = sum([len(x) for x in packed])
+        packed[2] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_set_switch_pipeline_request()
+        _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 == 53)
+        obj.pipeline = reader.read("!256s")[0].rstrip("\x00")
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.xid != other.xid: return False
+        if self.pipeline != other.pipeline: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_set_switch_pipeline_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("pipeline = ");
+                q.pp(self.pipeline)
+            q.breakable()
+        q.text('}')
+
+bsn_header.subtypes[53] = bsn_set_switch_pipeline_request
+
+class bsn_switch_pipeline_stats_reply(bsn_stats_reply):
+    version = 4
+    type = 19
+    stats_type = 65535
+    experimenter = 6035143
+    subtype = 6
+
+    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_switch_pipeline_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 == 6)
+        obj.entries = loxi.generic_util.unpack_list(reader, common.bsn_switch_pipeline_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_switch_pipeline_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[6] = bsn_switch_pipeline_stats_reply
+
+class bsn_switch_pipeline_stats_request(bsn_stats_request):
+    version = 4
+    type = 18
+    stats_type = 65535
+    experimenter = 6035143
+    subtype = 6
+
+    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_switch_pipeline_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 == 6)
+        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_switch_pipeline_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[6] = bsn_switch_pipeline_stats_request
+
+class bsn_time_reply(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 45
 
     def __init__(self, xid=None, time_ms=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if time_ms != None:
             self.time_ms = time_ms
         else:
             self.time_ms = 0
+        return
 
     def pack(self):
         packed = []
@@ -3793,18 +4203,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_time_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -3815,22 +4222,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.time_ms != other.time_ms: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_time_reply {")
         with q.group():
@@ -3847,14 +4242,20 @@
             q.breakable()
         q.text('}')
 
-class bsn_time_request(Message):
+bsn_header.subtypes[45] = bsn_time_reply
+
+class bsn_time_request(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 44
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -3869,18 +4270,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_time_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -3890,21 +4288,9 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_time_request {")
         with q.group():
@@ -3918,14 +4304,19 @@
             q.breakable()
         q.text('}')
 
-class bsn_virtual_port_create_reply(Message):
+bsn_header.subtypes[44] = bsn_time_request
+
+class bsn_virtual_port_create_reply(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 16
 
     def __init__(self, xid=None, status=None, vport_no=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
@@ -3934,6 +4325,7 @@
             self.vport_no = vport_no
         else:
             self.vport_no = 0
+        return
 
     def pack(self):
         packed = []
@@ -3950,18 +4342,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_virtual_port_create_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -3973,23 +4362,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         if self.vport_no != other.vport_no: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_virtual_port_create_reply {")
         with q.group():
@@ -4009,18 +4386,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_virtual_port_create_request(Message):
+bsn_header.subtypes[16] = bsn_virtual_port_create_reply
+
+class bsn_virtual_port_create_request(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 15
 
     def __init__(self, xid=None, vport=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if vport != None:
             self.vport = vport
         else:
             self.vport = common.bsn_vport_q_in_q()
+        return
 
     def pack(self):
         packed = []
@@ -4036,18 +4419,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_virtual_port_create_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -4058,22 +4438,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.vport != other.vport: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_virtual_port_create_request {")
         with q.group():
@@ -4090,18 +4458,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_virtual_port_remove_reply(Message):
+bsn_header.subtypes[15] = bsn_virtual_port_create_request
+
+class bsn_virtual_port_remove_reply(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 26
 
     def __init__(self, xid=None, status=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if status != None:
             self.status = status
         else:
             self.status = 0
+        return
 
     def pack(self):
         packed = []
@@ -4117,18 +4491,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_virtual_port_remove_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -4139,22 +4510,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.status != other.status: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_virtual_port_remove_reply {")
         with q.group():
@@ -4171,18 +4530,24 @@
             q.breakable()
         q.text('}')
 
-class bsn_virtual_port_remove_request(Message):
+bsn_header.subtypes[26] = bsn_virtual_port_remove_reply
+
+class bsn_virtual_port_remove_request(bsn_header):
     version = 4
     type = 4
     experimenter = 6035143
     subtype = 17
 
     def __init__(self, xid=None, vport_no=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if vport_no != None:
             self.vport_no = vport_no
         else:
             self.vport_no = 0
+        return
 
     def pack(self):
         packed = []
@@ -4198,18 +4563,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = bsn_virtual_port_remove_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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)
@@ -4220,22 +4582,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.vport_no != other.vport_no: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("bsn_virtual_port_remove_request {")
         with q.group():
@@ -4252,13 +4602,194 @@
             q.breakable()
         q.text('}')
 
-class desc_stats_reply(Message):
+bsn_header.subtypes[17] = bsn_virtual_port_remove_request
+
+class bsn_vlan_counter_stats_reply(bsn_stats_reply):
+    version = 4
+    type = 19
+    stats_type = 65535
+    experimenter = 6035143
+    subtype = 9
+
+    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_vlan_counter_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 == 9)
+        obj.entries = loxi.generic_util.unpack_list(reader, common.bsn_vlan_counter_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_vlan_counter_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[9] = bsn_vlan_counter_stats_reply
+
+class bsn_vlan_counter_stats_request(bsn_stats_request):
+    version = 4
+    type = 18
+    stats_type = 65535
+    experimenter = 6035143
+    subtype = 9
+
+    def __init__(self, xid=None, flags=None, vlan_vid=None):
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        if flags != None:
+            self.flags = flags
+        else:
+            self.flags = 0
+        if vlan_vid != None:
+            self.vlan_vid = vlan_vid
+        else:
+            self.vlan_vid = 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("!H", self.vlan_vid))
+        length = sum([len(x) for x in packed])
+        packed[2] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_vlan_counter_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 == 9)
+        obj.vlan_vid = reader.read("!H")[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.vlan_vid != other.vlan_vid: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_vlan_counter_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("vlan_vid = ");
+                q.text("%#x" % self.vlan_vid)
+            q.breakable()
+        q.text('}')
+
+bsn_stats_request.subtypes[9] = bsn_vlan_counter_stats_request
+
+class desc_stats_reply(stats_reply):
     version = 4
     type = 19
     stats_type = 0
 
     def __init__(self, xid=None, flags=None, mfr_desc=None, hw_desc=None, sw_desc=None, serial_num=None, dp_desc=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -4283,6 +4814,7 @@
             self.dp_desc = dp_desc
         else:
             self.dp_desc = ""
+        return
 
     def pack(self):
         packed = []
@@ -4303,18 +4835,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = desc_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 0)
@@ -4329,8 +4858,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.mfr_desc != other.mfr_desc: return False
@@ -4340,16 +4867,6 @@
         if self.dp_desc != other.dp_desc: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("desc_stats_reply {")
         with q.group():
@@ -4381,17 +4898,23 @@
             q.breakable()
         q.text('}')
 
-class desc_stats_request(Message):
+stats_reply.subtypes[0] = desc_stats_reply
+
+class desc_stats_request(stats_request):
     version = 4
     type = 18
     stats_type = 0
 
     def __init__(self, xid=None, flags=None):
-        self.xid = xid
+        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 = []
@@ -4407,18 +4930,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = desc_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 0)
@@ -4428,22 +4948,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("desc_stats_request {")
         with q.group():
@@ -4460,16 +4968,22 @@
             q.breakable()
         q.text('}')
 
-class echo_reply(Message):
+stats_request.subtypes[0] = desc_stats_request
+
+class echo_reply(message):
     version = 4
     type = 3
 
     def __init__(self, xid=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if data != None:
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -4483,40 +4997,25 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = echo_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 3)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.data = str(reader.read_all())
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("echo_reply {")
         with q.group():
@@ -4533,16 +5032,22 @@
             q.breakable()
         q.text('}')
 
-class echo_request(Message):
+message.subtypes[3] = echo_reply
+
+class echo_request(message):
     version = 4
     type = 2
 
     def __init__(self, xid=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if data != None:
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -4556,40 +5061,25 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = echo_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 2)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.data = str(reader.read_all())
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("echo_request {")
         with q.group():
@@ -4606,13 +5096,18 @@
             q.breakable()
         q.text('}')
 
-class experimenter_error_msg(Message):
+message.subtypes[2] = echo_request
+
+class experimenter_error_msg(error_msg):
     version = 4
     type = 1
     err_type = 65535
 
     def __init__(self, xid=None, subtype=None, experimenter=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if subtype != None:
             self.subtype = subtype
         else:
@@ -4625,6 +5120,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -4641,18 +5137,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = experimenter_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 65535)
@@ -4663,24 +5156,12 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.subtype != other.subtype: return False
         if self.experimenter != other.experimenter: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("experimenter_error_msg {")
         with q.group():
@@ -4703,12 +5184,17 @@
             q.breakable()
         q.text('}')
 
-class features_reply(Message):
+error_msg.subtypes[65535] = experimenter_error_msg
+
+class features_reply(message):
     version = 4
     type = 6
 
     def __init__(self, xid=None, datapath_id=None, n_buffers=None, n_tables=None, auxiliary_id=None, capabilities=None, reserved=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if datapath_id != None:
             self.datapath_id = datapath_id
         else:
@@ -4733,6 +5219,7 @@
             self.reserved = reserved
         else:
             self.reserved = 0
+        return
 
     def pack(self):
         packed = []
@@ -4752,18 +5239,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = features_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 6)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.datapath_id = reader.read("!Q")[0]
         obj.n_buffers = reader.read("!L")[0]
@@ -4776,8 +5260,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.datapath_id != other.datapath_id: return False
         if self.n_buffers != other.n_buffers: return False
@@ -4787,16 +5269,6 @@
         if self.reserved != other.reserved: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("features_reply {")
         with q.group():
@@ -4828,12 +5300,18 @@
             q.breakable()
         q.text('}')
 
-class features_request(Message):
+message.subtypes[6] = features_reply
+
+class features_request(message):
     version = 4
     type = 5
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -4846,38 +5324,23 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = features_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 5)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("features_request {")
         with q.group():
@@ -4891,13 +5354,32 @@
             q.breakable()
         q.text('}')
 
-class flow_add(Message):
+message.subtypes[5] = features_request
+
+class flow_mod(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('B', 25)
+        try:
+            subclass = flow_mod.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown flow_mod message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[14] = flow_mod
+
+class flow_add(flow_mod):
     version = 4
     type = 14
     _command = 0
 
     def __init__(self, xid=None, cookie=None, cookie_mask=None, table_id=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, out_group=None, flags=None, match=None, instructions=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if cookie != None:
             self.cookie = cookie
         else:
@@ -4946,6 +5428,7 @@
             self.instructions = instructions
         else:
             self.instructions = []
+        return
 
     def pack(self):
         packed = []
@@ -4966,24 +5449,21 @@
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 2)
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_add()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 14)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.cookie = reader.read("!Q")[0]
         obj.cookie_mask = reader.read("!Q")[0]
@@ -4999,13 +5479,11 @@
         obj.flags = reader.read("!H")[0]
         reader.skip(2)
         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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.cookie != other.cookie: return False
         if self.cookie_mask != other.cookie_mask: return False
@@ -5021,16 +5499,6 @@
         if self.instructions != other.instructions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_add {")
         with q.group():
@@ -5080,13 +5548,18 @@
             q.breakable()
         q.text('}')
 
-class flow_delete(Message):
+flow_mod.subtypes[0] = flow_add
+
+class flow_delete(flow_mod):
     version = 4
     type = 14
     _command = 3
 
     def __init__(self, xid=None, cookie=None, cookie_mask=None, table_id=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, out_group=None, flags=None, match=None, instructions=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if cookie != None:
             self.cookie = cookie
         else:
@@ -5135,6 +5608,7 @@
             self.instructions = instructions
         else:
             self.instructions = []
+        return
 
     def pack(self):
         packed = []
@@ -5155,24 +5629,21 @@
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 2)
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_delete()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 14)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.cookie = reader.read("!Q")[0]
         obj.cookie_mask = reader.read("!Q")[0]
@@ -5188,13 +5659,11 @@
         obj.flags = reader.read("!H")[0]
         reader.skip(2)
         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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.cookie != other.cookie: return False
         if self.cookie_mask != other.cookie_mask: return False
@@ -5210,16 +5679,6 @@
         if self.instructions != other.instructions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_delete {")
         with q.group():
@@ -5269,13 +5728,18 @@
             q.breakable()
         q.text('}')
 
-class flow_delete_strict(Message):
+flow_mod.subtypes[3] = flow_delete
+
+class flow_delete_strict(flow_mod):
     version = 4
     type = 14
     _command = 4
 
     def __init__(self, xid=None, cookie=None, cookie_mask=None, table_id=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, out_group=None, flags=None, match=None, instructions=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if cookie != None:
             self.cookie = cookie
         else:
@@ -5324,6 +5788,7 @@
             self.instructions = instructions
         else:
             self.instructions = []
+        return
 
     def pack(self):
         packed = []
@@ -5344,24 +5809,21 @@
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 2)
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_delete_strict()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 14)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.cookie = reader.read("!Q")[0]
         obj.cookie_mask = reader.read("!Q")[0]
@@ -5377,13 +5839,11 @@
         obj.flags = reader.read("!H")[0]
         reader.skip(2)
         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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.cookie != other.cookie: return False
         if self.cookie_mask != other.cookie_mask: return False
@@ -5399,16 +5859,6 @@
         if self.instructions != other.instructions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_delete_strict {")
         with q.group():
@@ -5458,13 +5908,18 @@
             q.breakable()
         q.text('}')
 
-class flow_mod_failed_error_msg(Message):
+flow_mod.subtypes[4] = flow_delete_strict
+
+class flow_mod_failed_error_msg(error_msg):
     version = 4
     type = 1
     err_type = 5
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -5473,6 +5928,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -5488,18 +5944,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_mod_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 5)
@@ -5509,23 +5962,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_mod_failed_error_msg {")
         with q.group():
@@ -5545,13 +5986,18 @@
             q.breakable()
         q.text('}')
 
-class flow_modify(Message):
+error_msg.subtypes[5] = flow_mod_failed_error_msg
+
+class flow_modify(flow_mod):
     version = 4
     type = 14
     _command = 1
 
     def __init__(self, xid=None, cookie=None, cookie_mask=None, table_id=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, out_group=None, flags=None, match=None, instructions=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if cookie != None:
             self.cookie = cookie
         else:
@@ -5600,6 +6046,7 @@
             self.instructions = instructions
         else:
             self.instructions = []
+        return
 
     def pack(self):
         packed = []
@@ -5620,24 +6067,21 @@
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 2)
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_modify()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 14)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.cookie = reader.read("!Q")[0]
         obj.cookie_mask = reader.read("!Q")[0]
@@ -5653,13 +6097,11 @@
         obj.flags = reader.read("!H")[0]
         reader.skip(2)
         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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.cookie != other.cookie: return False
         if self.cookie_mask != other.cookie_mask: return False
@@ -5675,16 +6117,6 @@
         if self.instructions != other.instructions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_modify {")
         with q.group():
@@ -5734,13 +6166,18 @@
             q.breakable()
         q.text('}')
 
-class flow_modify_strict(Message):
+flow_mod.subtypes[1] = flow_modify
+
+class flow_modify_strict(flow_mod):
     version = 4
     type = 14
     _command = 2
 
     def __init__(self, xid=None, cookie=None, cookie_mask=None, table_id=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, out_group=None, flags=None, match=None, instructions=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if cookie != None:
             self.cookie = cookie
         else:
@@ -5789,6 +6226,7 @@
             self.instructions = instructions
         else:
             self.instructions = []
+        return
 
     def pack(self):
         packed = []
@@ -5809,24 +6247,21 @@
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 2)
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_modify_strict()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 14)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.cookie = reader.read("!Q")[0]
         obj.cookie_mask = reader.read("!Q")[0]
@@ -5842,13 +6277,11 @@
         obj.flags = reader.read("!H")[0]
         reader.skip(2)
         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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.cookie != other.cookie: return False
         if self.cookie_mask != other.cookie_mask: return False
@@ -5864,16 +6297,6 @@
         if self.instructions != other.instructions: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_modify_strict {")
         with q.group():
@@ -5923,12 +6346,17 @@
             q.breakable()
         q.text('}')
 
-class flow_removed(Message):
+flow_mod.subtypes[2] = flow_modify_strict
+
+class flow_removed(message):
     version = 4
     type = 11
 
     def __init__(self, xid=None, cookie=None, priority=None, reason=None, table_id=None, duration_sec=None, duration_nsec=None, idle_timeout=None, hard_timeout=None, packet_count=None, byte_count=None, match=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if cookie != None:
             self.cookie = cookie
         else:
@@ -5973,6 +6401,7 @@
             self.match = match
         else:
             self.match = common.match()
+        return
 
     def pack(self):
         packed = []
@@ -5996,18 +6425,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_removed()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 11)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.cookie = reader.read("!Q")[0]
         obj.priority = reader.read("!H")[0]
@@ -6024,8 +6450,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.cookie != other.cookie: return False
         if self.priority != other.priority: return False
@@ -6040,16 +6464,6 @@
         if self.match != other.match: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_removed {")
         with q.group():
@@ -6096,13 +6510,18 @@
             q.breakable()
         q.text('}')
 
-class flow_stats_reply(Message):
+message.subtypes[11] = flow_removed
+
+class flow_stats_reply(stats_reply):
     version = 4
     type = 19
     stats_type = 1
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -6111,6 +6530,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -6121,51 +6541,36 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 1)
         obj.flags = reader.read("!H")[0]
         reader.skip(4)
-        obj.entries = common.unpack_list_flow_stats_entry(reader)
+        obj.entries = loxi.generic_util.unpack_list(reader, common.flow_stats_entry.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_stats_reply {")
         with q.group():
@@ -6185,13 +6590,18 @@
             q.breakable()
         q.text('}')
 
-class flow_stats_request(Message):
+stats_reply.subtypes[1] = flow_stats_reply
+
+class flow_stats_request(stats_request):
     version = 4
     type = 18
     stats_type = 1
 
     def __init__(self, xid=None, flags=None, table_id=None, out_port=None, out_group=None, cookie=None, cookie_mask=None, match=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -6220,6 +6630,7 @@
             self.match = match
         else:
             self.match = common.match()
+        return
 
     def pack(self):
         packed = []
@@ -6243,18 +6654,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = flow_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 1)
@@ -6272,8 +6680,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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
@@ -6284,16 +6690,6 @@
         if self.match != other.match: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("flow_stats_request {")
         with q.group():
@@ -6328,12 +6724,17 @@
             q.breakable()
         q.text('}')
 
-class get_config_reply(Message):
+stats_request.subtypes[1] = flow_stats_request
+
+class get_config_reply(message):
     version = 4
     type = 8
 
     def __init__(self, xid=None, flags=None, miss_send_len=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -6342,6 +6743,7 @@
             self.miss_send_len = miss_send_len
         else:
             self.miss_send_len = 0
+        return
 
     def pack(self):
         packed = []
@@ -6356,18 +6758,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = get_config_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 8)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.flags = reader.read("!H")[0]
         obj.miss_send_len = reader.read("!H")[0]
@@ -6375,23 +6774,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.miss_send_len != other.miss_send_len: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("get_config_reply {")
         with q.group():
@@ -6411,12 +6798,18 @@
             q.breakable()
         q.text('}')
 
-class get_config_request(Message):
+message.subtypes[8] = get_config_reply
+
+class get_config_request(message):
     version = 4
     type = 7
 
     def __init__(self, xid=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
 
     def pack(self):
         packed = []
@@ -6429,38 +6822,23 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = get_config_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 7)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("get_config_request {")
         with q.group():
@@ -6474,13 +6852,32 @@
             q.breakable()
         q.text('}')
 
-class group_add(Message):
+message.subtypes[7] = get_config_request
+
+class group_mod(message):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 8)
+        try:
+            subclass = group_mod.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown group_mod message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+message.subtypes[15] = group_mod
+
+class group_add(group_mod):
     version = 4
     type = 15
     command = 0
 
     def __init__(self, xid=None, group_type=None, group_id=None, buckets=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if group_type != None:
             self.group_type = group_type
         else:
@@ -6493,6 +6890,7 @@
             self.buckets = buckets
         else:
             self.buckets = []
+        return
 
     def pack(self):
         packed = []
@@ -6504,53 +6902,38 @@
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_add()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 15)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _command = reader.read("!H")[0]
         assert(_command == 0)
         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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.group_type != other.group_type: return False
         if self.group_id != other.group_id: return False
         if self.buckets != other.buckets: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_add {")
         with q.group():
@@ -6573,13 +6956,18 @@
             q.breakable()
         q.text('}')
 
-class group_delete(Message):
+group_mod.subtypes[0] = group_add
+
+class group_delete(group_mod):
     version = 4
     type = 15
     command = 2
 
     def __init__(self, xid=None, group_type=None, group_id=None, buckets=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if group_type != None:
             self.group_type = group_type
         else:
@@ -6592,6 +6980,7 @@
             self.buckets = buckets
         else:
             self.buckets = []
+        return
 
     def pack(self):
         packed = []
@@ -6603,53 +6992,38 @@
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_delete()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 15)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _command = reader.read("!H")[0]
         assert(_command == 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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.group_type != other.group_type: return False
         if self.group_id != other.group_id: return False
         if self.buckets != other.buckets: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_delete {")
         with q.group():
@@ -6672,13 +7046,18 @@
             q.breakable()
         q.text('}')
 
-class group_desc_stats_reply(Message):
+group_mod.subtypes[2] = group_delete
+
+class group_desc_stats_reply(stats_reply):
     version = 4
     type = 19
     stats_type = 7
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -6687,6 +7066,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -6697,51 +7077,36 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_desc_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 7)
         obj.flags = reader.read("!H")[0]
         reader.skip(4)
-        obj.entries = common.unpack_list_group_desc_stats_entry(reader)
+        obj.entries = loxi.generic_util.unpack_list(reader, common.group_desc_stats_entry.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_desc_stats_reply {")
         with q.group():
@@ -6761,17 +7126,23 @@
             q.breakable()
         q.text('}')
 
-class group_desc_stats_request(Message):
+stats_reply.subtypes[7] = group_desc_stats_reply
+
+class group_desc_stats_request(stats_request):
     version = 4
     type = 18
     stats_type = 7
 
     def __init__(self, xid=None, flags=None):
-        self.xid = xid
+        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 = []
@@ -6787,18 +7158,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_desc_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 7)
@@ -6808,22 +7176,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_desc_stats_request {")
         with q.group():
@@ -6840,13 +7196,18 @@
             q.breakable()
         q.text('}')
 
-class group_features_stats_reply(Message):
+stats_request.subtypes[7] = group_desc_stats_request
+
+class group_features_stats_reply(stats_reply):
     version = 4
     type = 19
     stats_type = 8
 
     def __init__(self, xid=None, flags=None, types=None, capabilities=None, max_groups_all=None, max_groups_select=None, max_groups_indirect=None, max_groups_ff=None, actions_all=None, actions_select=None, actions_indirect=None, actions_ff=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -6891,6 +7252,7 @@
             self.actions_ff = actions_ff
         else:
             self.actions_ff = 0
+        return
 
     def pack(self):
         packed = []
@@ -6916,18 +7278,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_features_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 8)
@@ -6947,8 +7306,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.types != other.types: return False
@@ -6963,16 +7320,6 @@
         if self.actions_ff != other.actions_ff: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_features_stats_reply {")
         with q.group():
@@ -7019,17 +7366,23 @@
             q.breakable()
         q.text('}')
 
-class group_features_stats_request(Message):
+stats_reply.subtypes[8] = group_features_stats_reply
+
+class group_features_stats_request(stats_request):
     version = 4
     type = 18
     stats_type = 8
 
     def __init__(self, xid=None, flags=None):
-        self.xid = xid
+        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 = []
@@ -7045,18 +7398,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_features_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 8)
@@ -7066,22 +7416,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_features_stats_request {")
         with q.group():
@@ -7098,13 +7436,18 @@
             q.breakable()
         q.text('}')
 
-class group_mod_failed_error_msg(Message):
+stats_request.subtypes[8] = group_features_stats_request
+
+class group_mod_failed_error_msg(error_msg):
     version = 4
     type = 1
     err_type = 6
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -7113,6 +7456,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -7128,18 +7472,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_mod_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 6)
@@ -7149,23 +7490,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_mod_failed_error_msg {")
         with q.group():
@@ -7185,13 +7514,18 @@
             q.breakable()
         q.text('}')
 
-class group_modify(Message):
+error_msg.subtypes[6] = group_mod_failed_error_msg
+
+class group_modify(group_mod):
     version = 4
     type = 15
     command = 1
 
     def __init__(self, xid=None, group_type=None, group_id=None, buckets=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if group_type != None:
             self.group_type = group_type
         else:
@@ -7204,6 +7538,7 @@
             self.buckets = buckets
         else:
             self.buckets = []
+        return
 
     def pack(self):
         packed = []
@@ -7215,53 +7550,38 @@
         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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_modify()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 15)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _command = reader.read("!H")[0]
         assert(_command == 1)
         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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.group_type != other.group_type: return False
         if self.group_id != other.group_id: return False
         if self.buckets != other.buckets: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_modify {")
         with q.group():
@@ -7284,13 +7604,18 @@
             q.breakable()
         q.text('}')
 
-class group_stats_reply(Message):
+group_mod.subtypes[1] = group_modify
+
+class group_stats_reply(stats_reply):
     version = 4
     type = 19
     stats_type = 6
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -7299,6 +7624,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -7309,51 +7635,36 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 6)
         obj.flags = reader.read("!H")[0]
         reader.skip(4)
-        obj.entries = common.unpack_list_group_stats_entry(reader)
+        obj.entries = loxi.generic_util.unpack_list(reader, common.group_stats_entry.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_stats_reply {")
         with q.group():
@@ -7373,13 +7684,18 @@
             q.breakable()
         q.text('}')
 
-class group_stats_request(Message):
+stats_reply.subtypes[6] = group_stats_reply
+
+class group_stats_request(stats_request):
     version = 4
     type = 18
     stats_type = 6
 
     def __init__(self, xid=None, flags=None, group_id=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -7388,6 +7704,7 @@
             self.group_id = group_id
         else:
             self.group_id = 0
+        return
 
     def pack(self):
         packed = []
@@ -7405,18 +7722,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = group_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 6)
@@ -7428,23 +7742,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.group_id != other.group_id: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("group_stats_request {")
         with q.group():
@@ -7464,16 +7766,22 @@
             q.breakable()
         q.text('}')
 
-class hello(Message):
+stats_request.subtypes[6] = group_stats_request
+
+class hello(message):
     version = 4
     type = 0
 
     def __init__(self, xid=None, elements=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if elements != None:
             self.elements = elements
         else:
             self.elements = []
+        return
 
     def pack(self):
         packed = []
@@ -7481,46 +7789,31 @@
         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(util.pack_list(self.elements))
+        packed.append(loxi.generic_util.pack_list(self.elements))
         length = sum([len(x) for x in packed])
         packed[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = hello()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 0)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
-        obj.elements = common.unpack_list_hello_elem(reader)
+        obj.elements = util.unpack_list_hello_elem(reader)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.elements != other.elements: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("hello {")
         with q.group():
@@ -7537,13 +7830,18 @@
             q.breakable()
         q.text('}')
 
-class hello_failed_error_msg(Message):
+message.subtypes[0] = hello
+
+class hello_failed_error_msg(error_msg):
     version = 4
     type = 1
     err_type = 0
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -7552,6 +7850,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -7567,18 +7866,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = hello_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 0)
@@ -7588,23 +7884,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("hello_failed_error_msg {")
         with q.group():
@@ -7624,13 +7908,18 @@
             q.breakable()
         q.text('}')
 
-class meter_config_stats_reply(Message):
+error_msg.subtypes[0] = hello_failed_error_msg
+
+class meter_config_stats_reply(stats_reply):
     version = 4
     type = 19
     stats_type = 10
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -7639,6 +7928,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -7649,51 +7939,36 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = meter_config_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 10)
         obj.flags = reader.read("!H")[0]
         reader.skip(4)
-        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):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("meter_config_stats_reply {")
         with q.group():
@@ -7713,13 +7988,18 @@
             q.breakable()
         q.text('}')
 
-class meter_config_stats_request(Message):
+stats_reply.subtypes[10] = meter_config_stats_reply
+
+class meter_config_stats_request(stats_request):
     version = 4
     type = 18
     stats_type = 10
 
     def __init__(self, xid=None, flags=None, meter_id=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -7728,6 +8008,7 @@
             self.meter_id = meter_id
         else:
             self.meter_id = 0
+        return
 
     def pack(self):
         packed = []
@@ -7745,18 +8026,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = meter_config_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 10)
@@ -7768,23 +8046,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.meter_id != other.meter_id: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("meter_config_stats_request {")
         with q.group():
@@ -7804,13 +8070,18 @@
             q.breakable()
         q.text('}')
 
-class meter_features_stats_reply(Message):
+stats_request.subtypes[10] = meter_config_stats_request
+
+class meter_features_stats_reply(stats_reply):
     version = 4
     type = 19
     stats_type = 11
 
     def __init__(self, xid=None, flags=None, features=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -7819,6 +8090,7 @@
             self.features = features
         else:
             self.features = common.meter_features()
+        return
 
     def pack(self):
         packed = []
@@ -7835,18 +8107,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = meter_features_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 11)
@@ -7857,23 +8126,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.features != other.features: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("meter_features_stats_reply {")
         with q.group():
@@ -7893,17 +8150,23 @@
             q.breakable()
         q.text('}')
 
-class meter_features_stats_request(Message):
+stats_reply.subtypes[11] = meter_features_stats_reply
+
+class meter_features_stats_request(stats_request):
     version = 4
     type = 18
     stats_type = 11
 
     def __init__(self, xid=None, flags=None):
-        self.xid = xid
+        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 = []
@@ -7919,18 +8182,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = meter_features_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 11)
@@ -7940,22 +8200,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("meter_features_stats_request {")
         with q.group():
@@ -7972,12 +8220,17 @@
             q.breakable()
         q.text('}')
 
-class meter_mod(Message):
+stats_request.subtypes[11] = meter_features_stats_request
+
+class meter_mod(message):
     version = 4
     type = 29
 
     def __init__(self, xid=None, command=None, flags=None, meter_id=None, meters=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if command != None:
             self.command = command
         else:
@@ -7994,6 +8247,7 @@
             self.meters = meters
         else:
             self.meters = []
+        return
 
     def pack(self):
         packed = []
@@ -8004,35 +8258,30 @@
         packed.append(struct.pack("!H", self.command))
         packed.append(struct.pack("!H", self.flags))
         packed.append(struct.pack("!L", self.meter_id))
-        packed.append(util.pack_list(self.meters))
+        packed.append(loxi.generic_util.pack_list(self.meters))
         length = sum([len(x) for x in packed])
         packed[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = meter_mod()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 29)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.command = reader.read("!H")[0]
         obj.flags = reader.read("!H")[0]
         obj.meter_id = reader.read("!L")[0]
-        obj.meters = meter_band.unpack_list(reader)
+        obj.meters = loxi.generic_util.unpack_list(reader, meter_band.meter_band.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.command != other.command: return False
         if self.flags != other.flags: return False
@@ -8040,16 +8289,6 @@
         if self.meters != other.meters: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("meter_mod {")
         with q.group():
@@ -8075,13 +8314,18 @@
             q.breakable()
         q.text('}')
 
-class meter_mod_failed_error_msg(Message):
+message.subtypes[29] = meter_mod
+
+class meter_mod_failed_error_msg(error_msg):
     version = 4
     type = 1
     err_type = 12
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -8090,6 +8334,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -8105,18 +8350,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = meter_mod_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 12)
@@ -8126,23 +8368,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("meter_mod_failed_error_msg {")
         with q.group():
@@ -8162,13 +8392,18 @@
             q.breakable()
         q.text('}')
 
-class meter_stats_reply(Message):
+error_msg.subtypes[12] = meter_mod_failed_error_msg
+
+class meter_stats_reply(stats_reply):
     version = 4
     type = 19
     stats_type = 9
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -8177,6 +8412,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -8187,51 +8423,36 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = meter_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 9)
         obj.flags = reader.read("!H")[0]
         reader.skip(4)
-        obj.entries = common.unpack_list_meter_stats(reader)
+        obj.entries = loxi.generic_util.unpack_list(reader, common.meter_stats.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("meter_stats_reply {")
         with q.group():
@@ -8251,13 +8472,18 @@
             q.breakable()
         q.text('}')
 
-class meter_stats_request(Message):
+stats_reply.subtypes[9] = meter_stats_reply
+
+class meter_stats_request(stats_request):
     version = 4
     type = 18
     stats_type = 9
 
     def __init__(self, xid=None, flags=None, meter_id=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -8266,6 +8492,7 @@
             self.meter_id = meter_id
         else:
             self.meter_id = 0
+        return
 
     def pack(self):
         packed = []
@@ -8283,18 +8510,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = meter_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 9)
@@ -8306,23 +8530,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.meter_id != other.meter_id: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("meter_stats_request {")
         with q.group():
@@ -8342,12 +8554,31 @@
             q.breakable()
         q.text('}')
 
-class packet_in(Message):
+stats_request.subtypes[9] = meter_stats_request
+
+class nicira_header(experimenter):
+    subtypes = {}
+
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 12)
+        try:
+            subclass = nicira_header.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown nicira_header experimenter message subtype %#x" % subtype)
+        return subclass.unpack(reader)
+
+experimenter.subtypes[8992] = nicira_header
+
+class packet_in(message):
     version = 4
     type = 10
 
     def __init__(self, xid=None, buffer_id=None, total_len=None, reason=None, table_id=None, cookie=None, match=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if buffer_id != None:
             self.buffer_id = buffer_id
         else:
@@ -8376,6 +8607,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -8396,18 +8628,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = packet_in()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 10)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.buffer_id = reader.read("!L")[0]
         obj.total_len = reader.read("!H")[0]
@@ -8421,8 +8650,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.buffer_id != other.buffer_id: return False
         if self.total_len != other.total_len: return False
@@ -8433,16 +8660,6 @@
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("packet_in {")
         with q.group():
@@ -8477,12 +8694,17 @@
             q.breakable()
         q.text('}')
 
-class packet_out(Message):
+message.subtypes[10] = packet_in
+
+class packet_out(message):
     version = 4
     type = 13
 
     def __init__(self, xid=None, buffer_id=None, in_port=None, actions=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if buffer_id != None:
             self.buffer_id = buffer_id
         else:
@@ -8499,6 +8721,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -8510,7 +8733,7 @@
         packed.append(util.pack_port_no(self.in_port))
         packed.append(struct.pack("!H", 0)) # placeholder for actions_len at index 6
         packed.append('\x00' * 6)
-        packed.append(util.pack_list(self.actions))
+        packed.append(loxi.generic_util.pack_list(self.actions))
         packed[6] = struct.pack("!H", len(packed[-1]))
         packed.append(self.data)
         length = sum([len(x) for x in packed])
@@ -8518,31 +8741,26 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = packet_out()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 13)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.buffer_id = reader.read("!L")[0]
         obj.in_port = util.unpack_port_no(reader)
         _actions_len = reader.read("!H")[0]
         reader.skip(6)
-        obj.actions = action.unpack_list(reader.slice(_actions_len))
+        obj.actions = loxi.generic_util.unpack_list(reader.slice(_actions_len), action.action.unpack)
         obj.data = str(reader.read_all())
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.buffer_id != other.buffer_id: return False
         if self.in_port != other.in_port: return False
@@ -8550,16 +8768,6 @@
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("packet_out {")
         with q.group():
@@ -8585,13 +8793,18 @@
             q.breakable()
         q.text('}')
 
-class port_desc_stats_reply(Message):
+message.subtypes[13] = packet_out
+
+class port_desc_stats_reply(stats_reply):
     version = 4
     type = 19
     stats_type = 13
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -8600,6 +8813,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -8610,24 +8824,21 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_desc_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 13)
@@ -8638,23 +8849,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_desc_stats_reply {")
         with q.group():
@@ -8674,17 +8873,23 @@
             q.breakable()
         q.text('}')
 
-class port_desc_stats_request(Message):
+stats_reply.subtypes[13] = port_desc_stats_reply
+
+class port_desc_stats_request(stats_request):
     version = 4
     type = 18
     stats_type = 13
 
     def __init__(self, xid=None, flags=None):
-        self.xid = xid
+        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 = []
@@ -8700,18 +8905,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_desc_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 13)
@@ -8721,22 +8923,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_desc_stats_request {")
         with q.group():
@@ -8753,12 +8943,17 @@
             q.breakable()
         q.text('}')
 
-class port_mod(Message):
+stats_request.subtypes[13] = port_desc_stats_request
+
+class port_mod(message):
     version = 4
     type = 16
 
     def __init__(self, xid=None, port_no=None, hw_addr=None, config=None, mask=None, advertise=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if port_no != None:
             self.port_no = port_no
         else:
@@ -8779,6 +8974,7 @@
             self.advertise = advertise
         else:
             self.advertise = 0
+        return
 
     def pack(self):
         packed = []
@@ -8799,18 +8995,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_mod()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 16)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.port_no = util.unpack_port_no(reader)
         reader.skip(4)
@@ -8824,8 +9017,6 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.port_no != other.port_no: return False
         if self.hw_addr != other.hw_addr: return False
@@ -8834,16 +9025,6 @@
         if self.advertise != other.advertise: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_mod {")
         with q.group():
@@ -8872,13 +9053,18 @@
             q.breakable()
         q.text('}')
 
-class port_mod_failed_error_msg(Message):
+message.subtypes[16] = port_mod
+
+class port_mod_failed_error_msg(error_msg):
     version = 4
     type = 1
     err_type = 7
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -8887,6 +9073,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -8902,18 +9089,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_mod_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 7)
@@ -8923,23 +9107,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_mod_failed_error_msg {")
         with q.group():
@@ -8959,13 +9131,18 @@
             q.breakable()
         q.text('}')
 
-class port_stats_reply(Message):
+error_msg.subtypes[7] = port_mod_failed_error_msg
+
+class port_stats_reply(stats_reply):
     version = 4
     type = 19
     stats_type = 4
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -8974,6 +9151,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -8984,24 +9162,21 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 4)
@@ -9012,23 +9187,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_stats_reply {")
         with q.group():
@@ -9048,13 +9211,18 @@
             q.breakable()
         q.text('}')
 
-class port_stats_request(Message):
+stats_reply.subtypes[4] = port_stats_reply
+
+class port_stats_request(stats_request):
     version = 4
     type = 18
     stats_type = 4
 
     def __init__(self, xid=None, flags=None, port_no=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -9063,6 +9231,7 @@
             self.port_no = port_no
         else:
             self.port_no = 0
+        return
 
     def pack(self):
         packed = []
@@ -9080,18 +9249,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 4)
@@ -9103,23 +9269,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.port_no != other.port_no: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_stats_request {")
         with q.group():
@@ -9139,12 +9293,17 @@
             q.breakable()
         q.text('}')
 
-class port_status(Message):
+stats_request.subtypes[4] = port_stats_request
+
+class port_status(message):
     version = 4
     type = 12
 
     def __init__(self, xid=None, reason=None, desc=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if reason != None:
             self.reason = reason
         else:
@@ -9153,6 +9312,7 @@
             self.desc = desc
         else:
             self.desc = common.port_desc()
+        return
 
     def pack(self):
         packed = []
@@ -9168,18 +9328,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = port_status()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 12)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.reason = reader.read("!B")[0]
         reader.skip(7)
@@ -9188,23 +9345,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.reason != other.reason: return False
         if self.desc != other.desc: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("port_status {")
         with q.group():
@@ -9224,12 +9369,17 @@
             q.breakable()
         q.text('}')
 
-class queue_get_config_reply(Message):
+message.subtypes[12] = port_status
+
+class queue_get_config_reply(message):
     version = 4
     type = 23
 
     def __init__(self, xid=None, port=None, queues=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if port != None:
             self.port = port
         else:
@@ -9238,6 +9388,7 @@
             self.queues = queues
         else:
             self.queues = []
+        return
 
     def pack(self):
         packed = []
@@ -9247,49 +9398,34 @@
         packed.append(struct.pack("!L", self.xid))
         packed.append(util.pack_port_no(self.port))
         packed.append('\x00' * 4)
-        packed.append(util.pack_list(self.queues))
+        packed.append(loxi.generic_util.pack_list(self.queues))
         length = sum([len(x) for x in packed])
         packed[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = queue_get_config_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 23)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.port = util.unpack_port_no(reader)
         reader.skip(4)
-        obj.queues = common.unpack_list_packet_queue(reader)
+        obj.queues = loxi.generic_util.unpack_list(reader, common.packet_queue.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.port != other.port: return False
         if self.queues != other.queues: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_get_config_reply {")
         with q.group():
@@ -9309,16 +9445,22 @@
             q.breakable()
         q.text('}')
 
-class queue_get_config_request(Message):
+message.subtypes[23] = queue_get_config_reply
+
+class queue_get_config_request(message):
     version = 4
     type = 22
 
     def __init__(self, xid=None, port=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if port != None:
             self.port = port
         else:
             self.port = 0
+        return
 
     def pack(self):
         packed = []
@@ -9333,18 +9475,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = queue_get_config_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 22)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.port = util.unpack_port_no(reader)
         reader.skip(4)
@@ -9352,22 +9491,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.port != other.port: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_get_config_request {")
         with q.group():
@@ -9384,13 +9511,18 @@
             q.breakable()
         q.text('}')
 
-class queue_op_failed_error_msg(Message):
+message.subtypes[22] = queue_get_config_request
+
+class queue_op_failed_error_msg(error_msg):
     version = 4
     type = 1
     err_type = 9
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -9399,6 +9531,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -9414,18 +9547,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = queue_op_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 9)
@@ -9435,23 +9565,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_op_failed_error_msg {")
         with q.group():
@@ -9471,13 +9589,18 @@
             q.breakable()
         q.text('}')
 
-class queue_stats_reply(Message):
+error_msg.subtypes[9] = queue_op_failed_error_msg
+
+class queue_stats_reply(stats_reply):
     version = 4
     type = 19
     stats_type = 5
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -9486,6 +9609,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -9496,24 +9620,21 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = queue_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 5)
@@ -9524,23 +9645,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_stats_reply {")
         with q.group():
@@ -9560,13 +9669,18 @@
             q.breakable()
         q.text('}')
 
-class queue_stats_request(Message):
+stats_reply.subtypes[5] = queue_stats_reply
+
+class queue_stats_request(stats_request):
     version = 4
     type = 18
     stats_type = 5
 
     def __init__(self, xid=None, flags=None, port_no=None, queue_id=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -9579,6 +9693,7 @@
             self.queue_id = queue_id
         else:
             self.queue_id = 0
+        return
 
     def pack(self):
         packed = []
@@ -9596,18 +9711,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = queue_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 5)
@@ -9619,24 +9731,12 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.port_no != other.port_no: return False
         if self.queue_id != other.queue_id: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("queue_stats_request {")
         with q.group():
@@ -9659,12 +9759,17 @@
             q.breakable()
         q.text('}')
 
-class role_reply(Message):
+stats_request.subtypes[5] = queue_stats_request
+
+class role_reply(message):
     version = 4
     type = 25
 
     def __init__(self, xid=None, role=None, generation_id=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if role != None:
             self.role = role
         else:
@@ -9673,6 +9778,7 @@
             self.generation_id = generation_id
         else:
             self.generation_id = 0
+        return
 
     def pack(self):
         packed = []
@@ -9688,18 +9794,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = role_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 25)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.role = reader.read("!L")[0]
         reader.skip(4)
@@ -9708,23 +9811,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.role != other.role: return False
         if self.generation_id != other.generation_id: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("role_reply {")
         with q.group():
@@ -9744,12 +9835,17 @@
             q.breakable()
         q.text('}')
 
-class role_request(Message):
+message.subtypes[25] = role_reply
+
+class role_request(message):
     version = 4
     type = 24
 
     def __init__(self, xid=None, role=None, generation_id=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if role != None:
             self.role = role
         else:
@@ -9758,6 +9854,7 @@
             self.generation_id = generation_id
         else:
             self.generation_id = 0
+        return
 
     def pack(self):
         packed = []
@@ -9773,18 +9870,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = role_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 24)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.role = reader.read("!L")[0]
         reader.skip(4)
@@ -9793,23 +9887,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.role != other.role: return False
         if self.generation_id != other.generation_id: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("role_request {")
         with q.group():
@@ -9829,13 +9911,18 @@
             q.breakable()
         q.text('}')
 
-class role_request_failed_error_msg(Message):
+message.subtypes[24] = role_request
+
+class role_request_failed_error_msg(error_msg):
     version = 4
     type = 1
     err_type = 11
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -9844,6 +9931,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -9859,18 +9947,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = role_request_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 11)
@@ -9880,23 +9965,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("role_request_failed_error_msg {")
         with q.group():
@@ -9916,12 +9989,17 @@
             q.breakable()
         q.text('}')
 
-class set_config(Message):
+error_msg.subtypes[11] = role_request_failed_error_msg
+
+class set_config(message):
     version = 4
     type = 9
 
     def __init__(self, xid=None, flags=None, miss_send_len=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -9930,6 +10008,7 @@
             self.miss_send_len = miss_send_len
         else:
             self.miss_send_len = 0
+        return
 
     def pack(self):
         packed = []
@@ -9944,18 +10023,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = set_config()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 9)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.flags = reader.read("!H")[0]
         obj.miss_send_len = reader.read("!H")[0]
@@ -9963,23 +10039,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         if self.miss_send_len != other.miss_send_len: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("set_config {")
         with q.group():
@@ -9999,13 +10063,18 @@
             q.breakable()
         q.text('}')
 
-class switch_config_failed_error_msg(Message):
+message.subtypes[9] = set_config
+
+class switch_config_failed_error_msg(error_msg):
     version = 4
     type = 1
     err_type = 10
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -10014,6 +10083,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -10029,18 +10099,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = switch_config_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 10)
@@ -10050,23 +10117,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("switch_config_failed_error_msg {")
         with q.group():
@@ -10086,13 +10141,18 @@
             q.breakable()
         q.text('}')
 
-class table_features_failed_error_msg(Message):
+error_msg.subtypes[10] = switch_config_failed_error_msg
+
+class table_features_failed_error_msg(error_msg):
     version = 4
     type = 1
     err_type = 13
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -10101,6 +10161,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -10116,18 +10177,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = table_features_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 13)
@@ -10137,23 +10195,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_features_failed_error_msg {")
         with q.group():
@@ -10173,13 +10219,18 @@
             q.breakable()
         q.text('}')
 
-class table_features_stats_reply(Message):
+error_msg.subtypes[13] = table_features_failed_error_msg
+
+class table_features_stats_reply(stats_reply):
     version = 4
     type = 19
     stats_type = 12
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -10188,6 +10239,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -10198,51 +10250,36 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = table_features_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 12)
         obj.flags = reader.read("!H")[0]
         reader.skip(4)
-        obj.entries = loxi.unimplemented('unpack list(of_table_features_t)')
+        obj.entries = loxi.generic_util.unpack_list(reader, common.table_features.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_features_stats_reply {")
         with q.group():
@@ -10262,13 +10299,18 @@
             q.breakable()
         q.text('}')
 
-class table_features_stats_request(Message):
+stats_reply.subtypes[12] = table_features_stats_reply
+
+class table_features_stats_request(stats_request):
     version = 4
     type = 18
     stats_type = 12
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -10277,6 +10319,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -10287,51 +10330,36 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = table_features_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 12)
         obj.flags = reader.read("!H")[0]
         reader.skip(4)
-        obj.entries = loxi.unimplemented('unpack list(of_table_features_t)')
+        obj.entries = loxi.generic_util.unpack_list(reader, common.table_features.unpack)
         return obj
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_features_stats_request {")
         with q.group():
@@ -10351,12 +10379,17 @@
             q.breakable()
         q.text('}')
 
-class table_mod(Message):
+stats_request.subtypes[12] = table_features_stats_request
+
+class table_mod(message):
     version = 4
     type = 17
 
     def __init__(self, xid=None, table_id=None, config=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if table_id != None:
             self.table_id = table_id
         else:
@@ -10365,6 +10398,7 @@
             self.config = config
         else:
             self.config = 0
+        return
 
     def pack(self):
         packed = []
@@ -10380,18 +10414,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = table_mod()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 17)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         obj.table_id = reader.read("!B")[0]
         reader.skip(3)
@@ -10400,23 +10431,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.table_id != other.table_id: return False
         if self.config != other.config: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_mod {")
         with q.group():
@@ -10436,13 +10455,18 @@
             q.breakable()
         q.text('}')
 
-class table_mod_failed_error_msg(Message):
+message.subtypes[17] = table_mod
+
+class table_mod_failed_error_msg(error_msg):
     version = 4
     type = 1
     err_type = 8
 
     def __init__(self, xid=None, code=None, data=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if code != None:
             self.code = code
         else:
@@ -10451,6 +10475,7 @@
             self.data = data
         else:
             self.data = ''
+        return
 
     def pack(self):
         packed = []
@@ -10466,18 +10491,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = table_mod_failed_error_msg()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _version = reader.read("!B")[0]
         assert(_version == 4)
         _type = reader.read("!B")[0]
         assert(_type == 1)
         _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length - (2 + 2))
         obj.xid = reader.read("!L")[0]
         _err_type = reader.read("!H")[0]
         assert(_err_type == 8)
@@ -10487,23 +10509,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.code != other.code: return False
         if self.data != other.data: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_mod_failed_error_msg {")
         with q.group():
@@ -10523,13 +10533,18 @@
             q.breakable()
         q.text('}')
 
-class table_stats_reply(Message):
+error_msg.subtypes[8] = table_mod_failed_error_msg
+
+class table_stats_reply(stats_reply):
     version = 4
     type = 19
     stats_type = 3
 
     def __init__(self, xid=None, flags=None, entries=None):
-        self.xid = xid
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
         if flags != None:
             self.flags = flags
         else:
@@ -10538,6 +10553,7 @@
             self.entries = entries
         else:
             self.entries = []
+        return
 
     def pack(self):
         packed = []
@@ -10548,24 +10564,21 @@
         packed.append(struct.pack("!H", self.stats_type))
         packed.append(struct.pack("!H", self.flags))
         packed.append('\x00' * 4)
-        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[2] = struct.pack("!H", length)
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = table_stats_reply()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 3)
@@ -10576,23 +10589,11 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: 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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_stats_reply {")
         with q.group():
@@ -10612,17 +10613,23 @@
             q.breakable()
         q.text('}')
 
-class table_stats_request(Message):
+stats_reply.subtypes[3] = table_stats_reply
+
+class table_stats_request(stats_request):
     version = 4
     type = 18
     stats_type = 3
 
     def __init__(self, xid=None, flags=None):
-        self.xid = xid
+        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 = []
@@ -10638,18 +10645,15 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
-        if len(buf) < 8: raise loxi.ProtocolError("buffer too short to contain an OpenFlow message")
+    def unpack(reader):
         obj = table_stats_request()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _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 == 3)
@@ -10659,22 +10663,10 @@
 
     def __eq__(self, other):
         if type(self) != type(other): return False
-        if self.version != other.version: return False
-        if self.type != other.type: return False
         if self.xid != other.xid: return False
         if self.flags != other.flags: return False
         return True
 
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return self.show()
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
     def pretty_print(self, q):
         q.text("table_stats_request {")
         with q.group():
@@ -10691,6 +10683,8 @@
             q.breakable()
         q.text('}')
 
+stats_request.subtypes[3] = table_stats_request
+
 
 def parse_header(buf):
     if len(buf) < 8:
@@ -10703,244 +10697,4 @@
         raise loxi.ProtocolError("wrong OpenFlow version (expected %d, got %d)" % (const.OFP_VERSION, msg_ver))
     if len(buf) != msg_len:
         raise loxi.ProtocolError("incorrect message size")
-    if msg_type in parsers:
-        return parsers[msg_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected message type")
-
-def parse_error(buf):
-    if len(buf) < 8 + 2:
-        raise loxi.ProtocolError("message too short")
-    err_type, = struct.unpack_from("!H", buf, 8)
-    if err_type in error_msg_parsers:
-        return error_msg_parsers[err_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected error type %u" % err_type)
-
-def parse_flow_mod(buf):
-    if len(buf) < 25 + 1:
-        raise loxi.ProtocolError("message too short")
-    # Technically uint16_t for OF 1.0
-    cmd, = struct.unpack_from("!B", buf, 25)
-    if cmd in flow_mod_parsers:
-        return flow_mod_parsers[cmd](buf)
-    else:
-        raise loxi.ProtocolError("unexpected flow mod cmd %u" % cmd)
-
-def parse_group_mod(buf):
-    if len(buf) < 8 + 2:
-        raise loxi.ProtocolError("message too short")
-    cmd, = struct.unpack_from("!H", buf, 8)
-    if cmd in flow_mod_parsers:
-        return group_mod_parsers[cmd](buf)
-    else:
-        raise loxi.ProtocolError("unexpected group mod cmd %u" % cmd)
-
-def parse_stats_reply(buf):
-    if len(buf) < 8 + 2:
-        raise loxi.ProtocolError("message too short")
-    stats_type, = struct.unpack_from("!H", buf, 8)
-    if stats_type in stats_reply_parsers:
-        return stats_reply_parsers[stats_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected stats type %u" % stats_type)
-
-def parse_stats_request(buf):
-    if len(buf) < 8 + 2:
-        raise loxi.ProtocolError("message too short")
-    stats_type, = struct.unpack_from("!H", buf, 8)
-    if stats_type in stats_request_parsers:
-        return stats_request_parsers[stats_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected stats type %u" % stats_type)
-
-def parse_experimenter_stats_request(buf):
-    if len(buf) < 24:
-        raise loxi.ProtocolError("experimenter stats request message too short")
-
-    experimenter, exp_type = struct.unpack_from("!LL", buf, 16)
-
-    if experimenter in experimenter_stats_request_parsers and \
-            exp_type in experimenter_stats_request_parsers[experimenter]:
-        return experimenter_stats_request_parsers[experimenter][exp_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected stats request experimenter %#x exp_type %#x" % (experimenter, exp_type))
-
-def parse_experimenter_stats_reply(buf):
-    if len(buf) < 24:
-        raise loxi.ProtocolError("experimenter stats reply message too short")
-
-    experimenter, exp_type = struct.unpack_from("!LL", buf, 16)
-
-    if experimenter in experimenter_stats_reply_parsers and \
-            exp_type in experimenter_stats_reply_parsers[experimenter]:
-        return experimenter_stats_reply_parsers[experimenter][exp_type](buf)
-    else:
-        raise loxi.ProtocolError("unexpected stats reply experimenter %#x exp_type %#x" % (experimenter, exp_type))
-
-def parse_experimenter(buf):
-    if len(buf) < 16:
-        raise loxi.ProtocolError("experimenter message too short")
-
-    experimenter, = struct.unpack_from("!L", buf, 8)
-    if experimenter == 0x005c16c7: # Big Switch Networks
-        subtype, = struct.unpack_from("!L", buf, 12)
-    elif experimenter == 0x00002320: # Nicira
-        subtype, = struct.unpack_from("!L", buf, 12)
-    else:
-        raise loxi.ProtocolError("unexpected experimenter id %#x" % experimenter)
-
-    if subtype in experimenter_parsers[experimenter]:
-        return experimenter_parsers[experimenter][subtype](buf)
-    else:
-        raise loxi.ProtocolError("unexpected experimenter %#x subtype %#x" % (experimenter, subtype))
-
-parsers = {
-    const.OFPT_HELLO : hello.unpack,
-    const.OFPT_ERROR : parse_error,
-    const.OFPT_ECHO_REQUEST : echo_request.unpack,
-    const.OFPT_ECHO_REPLY : echo_reply.unpack,
-    const.OFPT_EXPERIMENTER : parse_experimenter,
-    const.OFPT_FEATURES_REQUEST : features_request.unpack,
-    const.OFPT_FEATURES_REPLY : features_reply.unpack,
-    const.OFPT_GET_CONFIG_REQUEST : get_config_request.unpack,
-    const.OFPT_GET_CONFIG_REPLY : get_config_reply.unpack,
-    const.OFPT_SET_CONFIG : set_config.unpack,
-    const.OFPT_PACKET_IN : packet_in.unpack,
-    const.OFPT_FLOW_REMOVED : flow_removed.unpack,
-    const.OFPT_PORT_STATUS : port_status.unpack,
-    const.OFPT_PACKET_OUT : packet_out.unpack,
-    const.OFPT_FLOW_MOD : parse_flow_mod,
-    const.OFPT_GROUP_MOD : parse_group_mod,
-    const.OFPT_PORT_MOD : port_mod.unpack,
-    const.OFPT_TABLE_MOD : table_mod.unpack,
-    const.OFPT_STATS_REQUEST : parse_stats_request,
-    const.OFPT_STATS_REPLY : parse_stats_reply,
-    const.OFPT_BARRIER_REQUEST : barrier_request.unpack,
-    const.OFPT_BARRIER_REPLY : barrier_reply.unpack,
-    const.OFPT_QUEUE_GET_CONFIG_REQUEST : queue_get_config_request.unpack,
-    const.OFPT_QUEUE_GET_CONFIG_REPLY : queue_get_config_reply.unpack,
-    const.OFPT_ROLE_REQUEST : role_request.unpack,
-    const.OFPT_ROLE_REPLY : role_reply.unpack,
-    const.OFPT_GET_ASYNC_REQUEST : async_get_request.unpack,
-    const.OFPT_GET_ASYNC_REPLY : async_get_reply.unpack,
-    const.OFPT_SET_ASYNC : async_set.unpack,
-    const.OFPT_METER_MOD : meter_mod.unpack,
-}
-
-error_msg_parsers = {
-    const.OFPET_HELLO_FAILED : hello_failed_error_msg.unpack,
-    const.OFPET_BAD_REQUEST : bad_request_error_msg.unpack,
-    const.OFPET_BAD_ACTION : bad_action_error_msg.unpack,
-    const.OFPET_FLOW_MOD_FAILED : flow_mod_failed_error_msg.unpack,
-    const.OFPET_PORT_MOD_FAILED : port_mod_failed_error_msg.unpack,
-    const.OFPET_QUEUE_OP_FAILED : queue_op_failed_error_msg.unpack,
-    const.OFPET_BAD_INSTRUCTION : bad_instruction_error_msg.unpack,
-    const.OFPET_BAD_MATCH : bad_match_error_msg.unpack,
-    const.OFPET_GROUP_MOD_FAILED : group_mod_failed_error_msg.unpack,
-    const.OFPET_TABLE_MOD_FAILED : table_mod_failed_error_msg.unpack,
-    const.OFPET_SWITCH_CONFIG_FAILED : switch_config_failed_error_msg.unpack,
-    const.OFPET_ROLE_REQUEST_FAILED : role_request_failed_error_msg.unpack,
-    const.OFPET_EXPERIMENTER : experimenter_error_msg.unpack,
-    const.OFPET_METER_MOD_FAILED : meter_mod_failed_error_msg.unpack,
-    const.OFPET_TABLE_FEATURES_FAILED : table_features_failed_error_msg.unpack,
-}
-
-flow_mod_parsers = {
-    const.OFPFC_ADD : flow_add.unpack,
-    const.OFPFC_MODIFY : flow_modify.unpack,
-    const.OFPFC_MODIFY_STRICT : flow_modify_strict.unpack,
-    const.OFPFC_DELETE : flow_delete.unpack,
-    const.OFPFC_DELETE_STRICT : flow_delete_strict.unpack,
-}
-
-group_mod_parsers = {
-    const.OFPGC_ADD : group_add.unpack,
-    const.OFPGC_MODIFY : group_modify.unpack,
-    const.OFPGC_DELETE : group_delete.unpack,
-}
-
-stats_reply_parsers = {
-    const.OFPST_DESC : desc_stats_reply.unpack,
-    const.OFPST_FLOW : flow_stats_reply.unpack,
-    const.OFPST_AGGREGATE : aggregate_stats_reply.unpack,
-    const.OFPST_TABLE : table_stats_reply.unpack,
-    const.OFPST_PORT : port_stats_reply.unpack,
-    const.OFPST_QUEUE : queue_stats_reply.unpack,
-    const.OFPST_EXPERIMENTER : parse_experimenter_stats_reply,
-    const.OFPST_GROUP : group_stats_reply.unpack,
-    const.OFPST_GROUP_DESC : group_desc_stats_reply.unpack,
-    const.OFPST_GROUP_FEATURES : group_features_stats_reply.unpack,
-    const.OFPST_METER : meter_stats_reply.unpack,
-    const.OFPST_METER_CONFIG : meter_config_stats_reply.unpack,
-    const.OFPST_METER_FEATURES : meter_features_stats_reply.unpack,
-    const.OFPST_TABLE_FEATURES : table_features_stats_reply.unpack,
-    const.OFPST_PORT_DESC : port_desc_stats_reply.unpack,
-}
-
-stats_request_parsers = {
-    const.OFPST_DESC : desc_stats_request.unpack,
-    const.OFPST_FLOW : flow_stats_request.unpack,
-    const.OFPST_AGGREGATE : aggregate_stats_request.unpack,
-    const.OFPST_TABLE : table_stats_request.unpack,
-    const.OFPST_PORT : port_stats_request.unpack,
-    const.OFPST_QUEUE : queue_stats_request.unpack,
-    const.OFPST_EXPERIMENTER : parse_experimenter_stats_request,
-    const.OFPST_GROUP : group_stats_request.unpack,
-    const.OFPST_GROUP_DESC : group_desc_stats_request.unpack,
-    const.OFPST_GROUP_FEATURES : group_features_stats_request.unpack,
-    const.OFPST_METER : meter_stats_request.unpack,
-    const.OFPST_METER_CONFIG : meter_config_stats_request.unpack,
-    const.OFPST_METER_FEATURES : meter_features_stats_request.unpack,
-    const.OFPST_TABLE_FEATURES : table_features_stats_request.unpack,
-    const.OFPST_PORT_DESC : port_desc_stats_request.unpack,
-}
-
-experimenter_parsers = {
-    6035143 : {
-        22: bsn_bw_clear_data_reply.unpack,
-        21: bsn_bw_clear_data_request.unpack,
-        20: bsn_bw_enable_get_reply.unpack,
-        19: bsn_bw_enable_get_request.unpack,
-        23: bsn_bw_enable_set_reply.unpack,
-        18: bsn_bw_enable_set_request.unpack,
-        40: bsn_flow_idle.unpack,
-        39: bsn_flow_idle_enable_get_reply.unpack,
-        38: bsn_flow_idle_enable_get_request.unpack,
-        37: bsn_flow_idle_enable_set_reply.unpack,
-        36: bsn_flow_idle_enable_set_request.unpack,
-        10: bsn_get_interfaces_reply.unpack,
-        9: bsn_get_interfaces_request.unpack,
-        5: bsn_get_mirroring_reply.unpack,
-        4: bsn_get_mirroring_request.unpack,
-        43: bsn_lacp_convergence_notif.unpack,
-        34: bsn_pdu_rx_reply.unpack,
-        33: bsn_pdu_rx_request.unpack,
-        35: bsn_pdu_rx_timeout.unpack,
-        32: bsn_pdu_tx_reply.unpack,
-        31: bsn_pdu_tx_request.unpack,
-        42: bsn_set_lacp_reply.unpack,
-        41: bsn_set_lacp_request.unpack,
-        3: bsn_set_mirroring.unpack,
-        25: bsn_set_pktin_suppression_reply.unpack,
-        11: bsn_set_pktin_suppression_request.unpack,
-        45: bsn_time_reply.unpack,
-        44: bsn_time_request.unpack,
-        16: bsn_virtual_port_create_reply.unpack,
-        15: bsn_virtual_port_create_request.unpack,
-        26: bsn_virtual_port_remove_reply.unpack,
-        17: bsn_virtual_port_remove_request.unpack,
-    },
-}
-
-experimenter_stats_request_parsers = {
-    0x005c16c7: {
-        1: bsn_lacp_stats_request.unpack,
-    },
-}
-
-experimenter_stats_reply_parsers = {
-    0x005c16c7: {
-        1: bsn_lacp_stats_reply.unpack,
-    },
-}
+    return message.unpack(loxi.generic_util.OFReader(buf))
diff --git a/src/python/loxi/of13/meter_band.py b/src/python/loxi/of13/meter_band.py
index 5573beb..9c7a23f 100644
--- a/src/python/loxi/of13/meter_band.py
+++ b/src/python/loxi/of13/meter_band.py
@@ -3,27 +3,36 @@
 # 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 meter_band.py
+# Automatically generated by LOXI from template module.py
 # Do not modify
 
 import struct
+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 loxi
 
-def unpack_list(reader):
-    def deserializer(reader, typ):
-        parser = parsers.get(typ)
-        if not parser: raise loxi.ProtocolError("unknown meter band type %d" % typ)
-        return parser(reader)
-    return loxi.generic_util.unpack_list_tlv16(reader, deserializer)
+class meter_band(loxi.OFObject):
+    subtypes = {}
 
-class MeterBand(object):
-    type = None # override in subclass
-    pass
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!H', 0)
+        try:
+            subclass = meter_band.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown meter_band subtype %#x" % subtype)
+        return subclass.unpack(reader)
 
-class drop(MeterBand):
+
+class drop(meter_band):
     type = 1
 
     def __init__(self, rate=None, burst_size=None):
@@ -49,15 +58,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = drop()
-        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))
         obj.rate = reader.read("!L")[0]
         obj.burst_size = reader.read("!L")[0]
         reader.skip(4)
@@ -69,13 +76,6 @@
         if self.burst_size != other.burst_size: 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("drop {")
         with q.group():
@@ -89,7 +89,9 @@
             q.breakable()
         q.text('}')
 
-class dscp_remark(MeterBand):
+meter_band.subtypes[1] = drop
+
+class dscp_remark(meter_band):
     type = 2
 
     def __init__(self, rate=None, burst_size=None, prec_level=None):
@@ -120,15 +122,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = dscp_remark()
-        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))
         obj.rate = reader.read("!L")[0]
         obj.burst_size = reader.read("!L")[0]
         obj.prec_level = reader.read("!B")[0]
@@ -142,13 +142,6 @@
         if self.prec_level != other.prec_level: 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("dscp_remark {")
         with q.group():
@@ -165,7 +158,9 @@
             q.breakable()
         q.text('}')
 
-class experimenter(MeterBand):
+meter_band.subtypes[2] = dscp_remark
+
+class experimenter(meter_band):
     type = 65535
 
     def __init__(self, rate=None, burst_size=None, experimenter=None):
@@ -195,15 +190,13 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = 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)
         _len = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_len - (2 + 2))
         obj.rate = reader.read("!L")[0]
         obj.burst_size = reader.read("!L")[0]
         obj.experimenter = reader.read("!L")[0]
@@ -216,13 +209,6 @@
         if self.experimenter != other.experimenter: 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("experimenter {")
         with q.group():
@@ -239,9 +225,6 @@
             q.breakable()
         q.text('}')
 
+meter_band.subtypes[65535] = experimenter
 
-parsers = {
-    const.OFPMBT_DROP : drop.unpack,
-    const.OFPMBT_DSCP_REMARK : dscp_remark.unpack,
-    const.OFPMBT_EXPERIMENTER : experimenter.unpack,
-}
+
diff --git a/src/python/loxi/of13/oxm.py b/src/python/loxi/of13/oxm.py
index de53112..2abee43 100644
--- a/src/python/loxi/of13/oxm.py
+++ b/src/python/loxi/of13/oxm.py
@@ -3,31 +3,36 @@
 # 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 oxm.py
+# Automatically generated by LOXI from template module.py
 # Do not modify
 
 import struct
+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 loxi
 
-def unpack(reader):
-    type_len, = reader.peek('!L')
-    if type_len in parsers:
-        return parsers[type_len](reader)
-    else:
-        raise loxi.ProtocolError("unknown OXM cls=%#x type=%#x masked=%d len=%d (%#x)" % \
-            ((type_len >> 16) & 0xffff, (type_len >> 9) & 0x7f, (type_len >> 8) & 1, type_len & 0xff, type_len))
+class oxm(loxi.OFObject):
+    subtypes = {}
 
-def unpack_list(reader):
-    return loxi.generic_util.unpack_list(reader, unpack)
+    @staticmethod
+    def unpack(reader):
+        subtype, = reader.peek('!L', 0)
+        try:
+            subclass = oxm.subtypes[subtype]
+        except KeyError:
+            raise loxi.ProtocolError("unknown oxm subtype %#x" % subtype)
+        return subclass.unpack(reader)
 
-class OXM(object):
-    type_len = None # override in subclass
-    pass
 
-class arp_op(OXM):
+class arp_op(oxm):
     type_len = 2147494402
 
     def __init__(self, value=None):
@@ -35,6 +40,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -43,12 +49,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = arp_op()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147494402)
         obj.value = reader.read("!H")[0]
@@ -59,13 +61,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("arp_op {")
         with q.group():
@@ -76,7 +71,9 @@
             q.breakable()
         q.text('}')
 
-class arp_op_masked(OXM):
+oxm.subtypes[2147494402] = arp_op
+
+class arp_op_masked(oxm):
     type_len = 2147494660
 
     def __init__(self, value=None, value_mask=None):
@@ -88,6 +85,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -97,12 +95,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = arp_op_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147494660)
         obj.value = reader.read("!H")[0]
@@ -115,13 +109,6 @@
         if self.value_mask != other.value_mask: 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("arp_op_masked {")
         with q.group():
@@ -135,7 +122,9 @@
             q.breakable()
         q.text('}')
 
-class arp_sha(OXM):
+oxm.subtypes[2147494660] = arp_op_masked
+
+class arp_sha(oxm):
     type_len = 2147495942
 
     def __init__(self, value=None):
@@ -143,6 +132,7 @@
             self.value = value
         else:
             self.value = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -151,12 +141,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = arp_sha()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147495942)
         obj.value = list(reader.read('!6B'))
@@ -167,13 +153,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("arp_sha {")
         with q.group():
@@ -184,7 +163,9 @@
             q.breakable()
         q.text('}')
 
-class arp_sha_masked(OXM):
+oxm.subtypes[2147495942] = arp_sha
+
+class arp_sha_masked(oxm):
     type_len = 2147496204
 
     def __init__(self, value=None, value_mask=None):
@@ -196,6 +177,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -205,12 +187,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = arp_sha_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147496204)
         obj.value = list(reader.read('!6B'))
@@ -223,13 +201,6 @@
         if self.value_mask != other.value_mask: 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("arp_sha_masked {")
         with q.group():
@@ -243,7 +214,9 @@
             q.breakable()
         q.text('}')
 
-class arp_spa(OXM):
+oxm.subtypes[2147496204] = arp_sha_masked
+
+class arp_spa(oxm):
     type_len = 2147494916
 
     def __init__(self, value=None):
@@ -251,6 +224,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -259,12 +233,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = arp_spa()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147494916)
         obj.value = reader.read("!L")[0]
@@ -275,13 +245,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("arp_spa {")
         with q.group():
@@ -292,7 +255,9 @@
             q.breakable()
         q.text('}')
 
-class arp_spa_masked(OXM):
+oxm.subtypes[2147494916] = arp_spa
+
+class arp_spa_masked(oxm):
     type_len = 2147495176
 
     def __init__(self, value=None, value_mask=None):
@@ -304,6 +269,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -313,12 +279,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = arp_spa_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147495176)
         obj.value = reader.read("!L")[0]
@@ -331,13 +293,6 @@
         if self.value_mask != other.value_mask: 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("arp_spa_masked {")
         with q.group():
@@ -351,7 +306,9 @@
             q.breakable()
         q.text('}')
 
-class arp_tha(OXM):
+oxm.subtypes[2147495176] = arp_spa_masked
+
+class arp_tha(oxm):
     type_len = 2147496454
 
     def __init__(self, value=None):
@@ -359,6 +316,7 @@
             self.value = value
         else:
             self.value = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -367,12 +325,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = arp_tha()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147496454)
         obj.value = list(reader.read('!6B'))
@@ -383,13 +337,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("arp_tha {")
         with q.group():
@@ -400,7 +347,9 @@
             q.breakable()
         q.text('}')
 
-class arp_tha_masked(OXM):
+oxm.subtypes[2147496454] = arp_tha
+
+class arp_tha_masked(oxm):
     type_len = 2147496716
 
     def __init__(self, value=None, value_mask=None):
@@ -412,6 +361,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -421,12 +371,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = arp_tha_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147496716)
         obj.value = list(reader.read('!6B'))
@@ -439,13 +385,6 @@
         if self.value_mask != other.value_mask: 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("arp_tha_masked {")
         with q.group():
@@ -459,7 +398,9 @@
             q.breakable()
         q.text('}')
 
-class arp_tpa(OXM):
+oxm.subtypes[2147496716] = arp_tha_masked
+
+class arp_tpa(oxm):
     type_len = 2147495428
 
     def __init__(self, value=None):
@@ -467,6 +408,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -475,12 +417,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = arp_tpa()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147495428)
         obj.value = reader.read("!L")[0]
@@ -491,13 +429,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("arp_tpa {")
         with q.group():
@@ -508,7 +439,9 @@
             q.breakable()
         q.text('}')
 
-class arp_tpa_masked(OXM):
+oxm.subtypes[2147495428] = arp_tpa
+
+class arp_tpa_masked(oxm):
     type_len = 2147495688
 
     def __init__(self, value=None, value_mask=None):
@@ -520,6 +453,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -529,12 +463,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = arp_tpa_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147495688)
         obj.value = reader.read("!L")[0]
@@ -547,13 +477,6 @@
         if self.value_mask != other.value_mask: 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("arp_tpa_masked {")
         with q.group():
@@ -567,7 +490,9 @@
             q.breakable()
         q.text('}')
 
-class bsn_global_vrf_allowed(OXM):
+oxm.subtypes[2147495688] = arp_tpa_masked
+
+class bsn_global_vrf_allowed(oxm):
     type_len = 198145
 
     def __init__(self, value=None):
@@ -575,6 +500,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -583,12 +509,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_global_vrf_allowed()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 198145)
         obj.value = reader.read("!B")[0]
@@ -599,13 +521,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("bsn_global_vrf_allowed {")
         with q.group():
@@ -616,8 +531,10 @@
             q.breakable()
         q.text('}')
 
-class bsn_global_vrf_allowed_masked(OXM):
-    type_len = 198401
+oxm.subtypes[198145] = bsn_global_vrf_allowed
+
+class bsn_global_vrf_allowed_masked(oxm):
+    type_len = 198402
 
     def __init__(self, value=None, value_mask=None):
         if value != None:
@@ -628,6 +545,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -637,14 +555,10 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_global_vrf_allowed_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
-        assert(_type_len == 198401)
+        assert(_type_len == 198402)
         obj.value = reader.read("!B")[0]
         obj.value_mask = reader.read("!B")[0]
         return obj
@@ -655,13 +569,6 @@
         if self.value_mask != other.value_mask: 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_global_vrf_allowed_masked {")
         with q.group():
@@ -675,14 +582,17 @@
             q.breakable()
         q.text('}')
 
-class bsn_in_ports_128(OXM):
-    type_len = 196640
+oxm.subtypes[198402] = bsn_global_vrf_allowed_masked
+
+class bsn_in_ports_128(oxm):
+    type_len = 196624
 
     def __init__(self, value=None):
         if value != None:
             self.value = value
         else:
             self.value = set()
+        return
 
     def pack(self):
         packed = []
@@ -691,14 +601,10 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_in_ports_128()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
-        assert(_type_len == 196640)
+        assert(_type_len == 196624)
         obj.value = util.unpack_bitmap_128(reader)
         return obj
 
@@ -707,13 +613,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("bsn_in_ports_128 {")
         with q.group():
@@ -724,7 +623,9 @@
             q.breakable()
         q.text('}')
 
-class bsn_in_ports_128_masked(OXM):
+oxm.subtypes[196624] = bsn_in_ports_128
+
+class bsn_in_ports_128_masked(oxm):
     type_len = 196896
 
     def __init__(self, value=None, value_mask=None):
@@ -736,6 +637,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = set()
+        return
 
     def pack(self):
         packed = []
@@ -745,12 +647,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_in_ports_128_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 196896)
         obj.value = util.unpack_bitmap_128(reader)
@@ -763,13 +661,6 @@
         if self.value_mask != other.value_mask: 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_in_ports_128_masked {")
         with q.group():
@@ -783,7 +674,9 @@
             q.breakable()
         q.text('}')
 
-class bsn_l3_dst_class_id(OXM):
+oxm.subtypes[196896] = bsn_in_ports_128_masked
+
+class bsn_l3_dst_class_id(oxm):
     type_len = 199684
 
     def __init__(self, value=None):
@@ -791,6 +684,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -799,12 +693,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_l3_dst_class_id()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 199684)
         obj.value = reader.read("!L")[0]
@@ -815,13 +705,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("bsn_l3_dst_class_id {")
         with q.group():
@@ -832,8 +715,10 @@
             q.breakable()
         q.text('}')
 
-class bsn_l3_dst_class_id_masked(OXM):
-    type_len = 199940
+oxm.subtypes[199684] = bsn_l3_dst_class_id
+
+class bsn_l3_dst_class_id_masked(oxm):
+    type_len = 199944
 
     def __init__(self, value=None, value_mask=None):
         if value != None:
@@ -844,6 +729,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -853,14 +739,10 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_l3_dst_class_id_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
-        assert(_type_len == 199940)
+        assert(_type_len == 199944)
         obj.value = reader.read("!L")[0]
         obj.value_mask = reader.read("!L")[0]
         return obj
@@ -871,13 +753,6 @@
         if self.value_mask != other.value_mask: 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_l3_dst_class_id_masked {")
         with q.group():
@@ -891,7 +766,9 @@
             q.breakable()
         q.text('}')
 
-class bsn_l3_interface_class_id(OXM):
+oxm.subtypes[199944] = bsn_l3_dst_class_id_masked
+
+class bsn_l3_interface_class_id(oxm):
     type_len = 198660
 
     def __init__(self, value=None):
@@ -899,6 +776,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -907,12 +785,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_l3_interface_class_id()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 198660)
         obj.value = reader.read("!L")[0]
@@ -923,13 +797,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("bsn_l3_interface_class_id {")
         with q.group():
@@ -940,8 +807,10 @@
             q.breakable()
         q.text('}')
 
-class bsn_l3_interface_class_id_masked(OXM):
-    type_len = 198916
+oxm.subtypes[198660] = bsn_l3_interface_class_id
+
+class bsn_l3_interface_class_id_masked(oxm):
+    type_len = 198920
 
     def __init__(self, value=None, value_mask=None):
         if value != None:
@@ -952,6 +821,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -961,14 +831,10 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_l3_interface_class_id_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
-        assert(_type_len == 198916)
+        assert(_type_len == 198920)
         obj.value = reader.read("!L")[0]
         obj.value_mask = reader.read("!L")[0]
         return obj
@@ -979,13 +845,6 @@
         if self.value_mask != other.value_mask: 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_l3_interface_class_id_masked {")
         with q.group():
@@ -999,7 +858,9 @@
             q.breakable()
         q.text('}')
 
-class bsn_l3_src_class_id(OXM):
+oxm.subtypes[198920] = bsn_l3_interface_class_id_masked
+
+class bsn_l3_src_class_id(oxm):
     type_len = 199172
 
     def __init__(self, value=None):
@@ -1007,6 +868,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -1015,12 +877,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_l3_src_class_id()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 199172)
         obj.value = reader.read("!L")[0]
@@ -1031,13 +889,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("bsn_l3_src_class_id {")
         with q.group():
@@ -1048,8 +899,10 @@
             q.breakable()
         q.text('}')
 
-class bsn_l3_src_class_id_masked(OXM):
-    type_len = 199428
+oxm.subtypes[199172] = bsn_l3_src_class_id
+
+class bsn_l3_src_class_id_masked(oxm):
+    type_len = 199432
 
     def __init__(self, value=None, value_mask=None):
         if value != None:
@@ -1060,6 +913,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -1069,14 +923,10 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_l3_src_class_id_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
-        assert(_type_len == 199428)
+        assert(_type_len == 199432)
         obj.value = reader.read("!L")[0]
         obj.value_mask = reader.read("!L")[0]
         return obj
@@ -1087,13 +937,6 @@
         if self.value_mask != other.value_mask: 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_l3_src_class_id_masked {")
         with q.group():
@@ -1107,7 +950,9 @@
             q.breakable()
         q.text('}')
 
-class bsn_lag_id(OXM):
+oxm.subtypes[199432] = bsn_l3_src_class_id_masked
+
+class bsn_lag_id(oxm):
     type_len = 197124
 
     def __init__(self, value=None):
@@ -1115,6 +960,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -1123,12 +969,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_lag_id()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 197124)
         obj.value = reader.read("!L")[0]
@@ -1139,13 +981,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("bsn_lag_id {")
         with q.group():
@@ -1156,8 +991,10 @@
             q.breakable()
         q.text('}')
 
-class bsn_lag_id_masked(OXM):
-    type_len = 197380
+oxm.subtypes[197124] = bsn_lag_id
+
+class bsn_lag_id_masked(oxm):
+    type_len = 197384
 
     def __init__(self, value=None, value_mask=None):
         if value != None:
@@ -1168,6 +1005,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -1177,14 +1015,10 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_lag_id_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
-        assert(_type_len == 197380)
+        assert(_type_len == 197384)
         obj.value = reader.read("!L")[0]
         obj.value_mask = reader.read("!L")[0]
         return obj
@@ -1195,13 +1029,6 @@
         if self.value_mask != other.value_mask: 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_lag_id_masked {")
         with q.group():
@@ -1215,7 +1042,9 @@
             q.breakable()
         q.text('}')
 
-class bsn_vrf(OXM):
+oxm.subtypes[197384] = bsn_lag_id_masked
+
+class bsn_vrf(oxm):
     type_len = 197636
 
     def __init__(self, value=None):
@@ -1223,6 +1052,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -1231,12 +1061,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_vrf()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 197636)
         obj.value = reader.read("!L")[0]
@@ -1247,13 +1073,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("bsn_vrf {")
         with q.group():
@@ -1264,8 +1083,10 @@
             q.breakable()
         q.text('}')
 
-class bsn_vrf_masked(OXM):
-    type_len = 197892
+oxm.subtypes[197636] = bsn_vrf
+
+class bsn_vrf_masked(oxm):
+    type_len = 197896
 
     def __init__(self, value=None, value_mask=None):
         if value != None:
@@ -1276,6 +1097,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -1285,14 +1107,10 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = bsn_vrf_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
-        assert(_type_len == 197892)
+        assert(_type_len == 197896)
         obj.value = reader.read("!L")[0]
         obj.value_mask = reader.read("!L")[0]
         return obj
@@ -1303,13 +1121,6 @@
         if self.value_mask != other.value_mask: 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_vrf_masked {")
         with q.group():
@@ -1323,7 +1134,9 @@
             q.breakable()
         q.text('}')
 
-class eth_dst(OXM):
+oxm.subtypes[197896] = bsn_vrf_masked
+
+class eth_dst(oxm):
     type_len = 2147485190
 
     def __init__(self, value=None):
@@ -1331,6 +1144,7 @@
             self.value = value
         else:
             self.value = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -1339,12 +1153,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = eth_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147485190)
         obj.value = list(reader.read('!6B'))
@@ -1355,13 +1165,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("eth_dst {")
         with q.group():
@@ -1372,7 +1175,9 @@
             q.breakable()
         q.text('}')
 
-class eth_dst_masked(OXM):
+oxm.subtypes[2147485190] = eth_dst
+
+class eth_dst_masked(oxm):
     type_len = 2147485452
 
     def __init__(self, value=None, value_mask=None):
@@ -1384,6 +1189,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -1393,12 +1199,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = eth_dst_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147485452)
         obj.value = list(reader.read('!6B'))
@@ -1411,13 +1213,6 @@
         if self.value_mask != other.value_mask: 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("eth_dst_masked {")
         with q.group():
@@ -1431,7 +1226,9 @@
             q.breakable()
         q.text('}')
 
-class eth_src(OXM):
+oxm.subtypes[2147485452] = eth_dst_masked
+
+class eth_src(oxm):
     type_len = 2147485702
 
     def __init__(self, value=None):
@@ -1439,6 +1236,7 @@
             self.value = value
         else:
             self.value = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -1447,12 +1245,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = eth_src()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147485702)
         obj.value = list(reader.read('!6B'))
@@ -1463,13 +1257,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("eth_src {")
         with q.group():
@@ -1480,7 +1267,9 @@
             q.breakable()
         q.text('}')
 
-class eth_src_masked(OXM):
+oxm.subtypes[2147485702] = eth_src
+
+class eth_src_masked(oxm):
     type_len = 2147485964
 
     def __init__(self, value=None, value_mask=None):
@@ -1492,6 +1281,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -1501,12 +1291,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = eth_src_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147485964)
         obj.value = list(reader.read('!6B'))
@@ -1519,13 +1305,6 @@
         if self.value_mask != other.value_mask: 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("eth_src_masked {")
         with q.group():
@@ -1539,7 +1318,9 @@
             q.breakable()
         q.text('}')
 
-class eth_type(OXM):
+oxm.subtypes[2147485964] = eth_src_masked
+
+class eth_type(oxm):
     type_len = 2147486210
 
     def __init__(self, value=None):
@@ -1547,6 +1328,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -1555,12 +1337,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = eth_type()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147486210)
         obj.value = reader.read("!H")[0]
@@ -1571,13 +1349,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("eth_type {")
         with q.group():
@@ -1588,7 +1359,9 @@
             q.breakable()
         q.text('}')
 
-class eth_type_masked(OXM):
+oxm.subtypes[2147486210] = eth_type
+
+class eth_type_masked(oxm):
     type_len = 2147486468
 
     def __init__(self, value=None, value_mask=None):
@@ -1600,6 +1373,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -1609,12 +1383,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = eth_type_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147486468)
         obj.value = reader.read("!H")[0]
@@ -1627,13 +1397,6 @@
         if self.value_mask != other.value_mask: 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("eth_type_masked {")
         with q.group():
@@ -1647,7 +1410,9 @@
             q.breakable()
         q.text('}')
 
-class icmpv4_code(OXM):
+oxm.subtypes[2147486468] = eth_type_masked
+
+class icmpv4_code(oxm):
     type_len = 2147493889
 
     def __init__(self, value=None):
@@ -1655,6 +1420,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -1663,12 +1429,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = icmpv4_code()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147493889)
         obj.value = reader.read("!B")[0]
@@ -1679,13 +1441,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("icmpv4_code {")
         with q.group():
@@ -1696,7 +1451,9 @@
             q.breakable()
         q.text('}')
 
-class icmpv4_code_masked(OXM):
+oxm.subtypes[2147493889] = icmpv4_code
+
+class icmpv4_code_masked(oxm):
     type_len = 2147494146
 
     def __init__(self, value=None, value_mask=None):
@@ -1708,6 +1465,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -1717,12 +1475,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = icmpv4_code_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147494146)
         obj.value = reader.read("!B")[0]
@@ -1735,13 +1489,6 @@
         if self.value_mask != other.value_mask: 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("icmpv4_code_masked {")
         with q.group():
@@ -1755,7 +1502,9 @@
             q.breakable()
         q.text('}')
 
-class icmpv4_type(OXM):
+oxm.subtypes[2147494146] = icmpv4_code_masked
+
+class icmpv4_type(oxm):
     type_len = 2147493377
 
     def __init__(self, value=None):
@@ -1763,6 +1512,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -1771,12 +1521,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = icmpv4_type()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147493377)
         obj.value = reader.read("!B")[0]
@@ -1787,13 +1533,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("icmpv4_type {")
         with q.group():
@@ -1804,7 +1543,9 @@
             q.breakable()
         q.text('}')
 
-class icmpv4_type_masked(OXM):
+oxm.subtypes[2147493377] = icmpv4_type
+
+class icmpv4_type_masked(oxm):
     type_len = 2147493634
 
     def __init__(self, value=None, value_mask=None):
@@ -1816,6 +1557,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -1825,12 +1567,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = icmpv4_type_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147493634)
         obj.value = reader.read("!B")[0]
@@ -1843,13 +1581,6 @@
         if self.value_mask != other.value_mask: 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("icmpv4_type_masked {")
         with q.group():
@@ -1863,7 +1594,9 @@
             q.breakable()
         q.text('}')
 
-class icmpv6_code(OXM):
+oxm.subtypes[2147493634] = icmpv4_type_masked
+
+class icmpv6_code(oxm):
     type_len = 2147499009
 
     def __init__(self, value=None):
@@ -1871,6 +1604,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -1879,12 +1613,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = icmpv6_code()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147499009)
         obj.value = reader.read("!B")[0]
@@ -1895,13 +1625,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("icmpv6_code {")
         with q.group():
@@ -1912,7 +1635,9 @@
             q.breakable()
         q.text('}')
 
-class icmpv6_code_masked(OXM):
+oxm.subtypes[2147499009] = icmpv6_code
+
+class icmpv6_code_masked(oxm):
     type_len = 2147499266
 
     def __init__(self, value=None, value_mask=None):
@@ -1924,6 +1649,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -1933,12 +1659,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = icmpv6_code_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147499266)
         obj.value = reader.read("!B")[0]
@@ -1951,13 +1673,6 @@
         if self.value_mask != other.value_mask: 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("icmpv6_code_masked {")
         with q.group():
@@ -1971,7 +1686,9 @@
             q.breakable()
         q.text('}')
 
-class icmpv6_type(OXM):
+oxm.subtypes[2147499266] = icmpv6_code_masked
+
+class icmpv6_type(oxm):
     type_len = 2147498497
 
     def __init__(self, value=None):
@@ -1979,6 +1696,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -1987,12 +1705,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = icmpv6_type()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147498497)
         obj.value = reader.read("!B")[0]
@@ -2003,13 +1717,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("icmpv6_type {")
         with q.group():
@@ -2020,7 +1727,9 @@
             q.breakable()
         q.text('}')
 
-class icmpv6_type_masked(OXM):
+oxm.subtypes[2147498497] = icmpv6_type
+
+class icmpv6_type_masked(oxm):
     type_len = 2147498754
 
     def __init__(self, value=None, value_mask=None):
@@ -2032,6 +1741,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -2041,12 +1751,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = icmpv6_type_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147498754)
         obj.value = reader.read("!B")[0]
@@ -2059,13 +1765,6 @@
         if self.value_mask != other.value_mask: 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("icmpv6_type_masked {")
         with q.group():
@@ -2079,7 +1778,9 @@
             q.breakable()
         q.text('}')
 
-class in_phy_port(OXM):
+oxm.subtypes[2147498754] = icmpv6_type_masked
+
+class in_phy_port(oxm):
     type_len = 2147484164
 
     def __init__(self, value=None):
@@ -2087,6 +1788,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -2095,12 +1797,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = in_phy_port()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147484164)
         obj.value = util.unpack_port_no(reader)
@@ -2111,13 +1809,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("in_phy_port {")
         with q.group():
@@ -2128,7 +1819,9 @@
             q.breakable()
         q.text('}')
 
-class in_phy_port_masked(OXM):
+oxm.subtypes[2147484164] = in_phy_port
+
+class in_phy_port_masked(oxm):
     type_len = 2147484424
 
     def __init__(self, value=None, value_mask=None):
@@ -2140,6 +1833,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -2149,12 +1843,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = in_phy_port_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147484424)
         obj.value = util.unpack_port_no(reader)
@@ -2167,13 +1857,6 @@
         if self.value_mask != other.value_mask: 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("in_phy_port_masked {")
         with q.group():
@@ -2187,7 +1870,9 @@
             q.breakable()
         q.text('}')
 
-class in_port(OXM):
+oxm.subtypes[2147484424] = in_phy_port_masked
+
+class in_port(oxm):
     type_len = 2147483652
 
     def __init__(self, value=None):
@@ -2195,6 +1880,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -2203,12 +1889,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = in_port()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147483652)
         obj.value = util.unpack_port_no(reader)
@@ -2219,13 +1901,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("in_port {")
         with q.group():
@@ -2236,7 +1911,9 @@
             q.breakable()
         q.text('}')
 
-class in_port_masked(OXM):
+oxm.subtypes[2147483652] = in_port
+
+class in_port_masked(oxm):
     type_len = 2147483912
 
     def __init__(self, value=None, value_mask=None):
@@ -2248,6 +1925,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -2257,12 +1935,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = in_port_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147483912)
         obj.value = util.unpack_port_no(reader)
@@ -2275,13 +1949,6 @@
         if self.value_mask != other.value_mask: 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("in_port_masked {")
         with q.group():
@@ -2295,7 +1962,9 @@
             q.breakable()
         q.text('}')
 
-class ip_dscp(OXM):
+oxm.subtypes[2147483912] = in_port_masked
+
+class ip_dscp(oxm):
     type_len = 2147487745
 
     def __init__(self, value=None):
@@ -2303,6 +1972,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -2311,12 +1981,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ip_dscp()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147487745)
         obj.value = reader.read("!B")[0]
@@ -2327,13 +1993,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("ip_dscp {")
         with q.group():
@@ -2344,7 +2003,9 @@
             q.breakable()
         q.text('}')
 
-class ip_dscp_masked(OXM):
+oxm.subtypes[2147487745] = ip_dscp
+
+class ip_dscp_masked(oxm):
     type_len = 2147488002
 
     def __init__(self, value=None, value_mask=None):
@@ -2356,6 +2017,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -2365,12 +2027,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ip_dscp_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147488002)
         obj.value = reader.read("!B")[0]
@@ -2383,13 +2041,6 @@
         if self.value_mask != other.value_mask: 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("ip_dscp_masked {")
         with q.group():
@@ -2403,7 +2054,9 @@
             q.breakable()
         q.text('}')
 
-class ip_ecn(OXM):
+oxm.subtypes[2147488002] = ip_dscp_masked
+
+class ip_ecn(oxm):
     type_len = 2147488257
 
     def __init__(self, value=None):
@@ -2411,6 +2064,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -2419,12 +2073,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ip_ecn()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147488257)
         obj.value = reader.read("!B")[0]
@@ -2435,13 +2085,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("ip_ecn {")
         with q.group():
@@ -2452,7 +2095,9 @@
             q.breakable()
         q.text('}')
 
-class ip_ecn_masked(OXM):
+oxm.subtypes[2147488257] = ip_ecn
+
+class ip_ecn_masked(oxm):
     type_len = 2147488514
 
     def __init__(self, value=None, value_mask=None):
@@ -2464,6 +2109,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -2473,12 +2119,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ip_ecn_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147488514)
         obj.value = reader.read("!B")[0]
@@ -2491,13 +2133,6 @@
         if self.value_mask != other.value_mask: 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("ip_ecn_masked {")
         with q.group():
@@ -2511,7 +2146,9 @@
             q.breakable()
         q.text('}')
 
-class ip_proto(OXM):
+oxm.subtypes[2147488514] = ip_ecn_masked
+
+class ip_proto(oxm):
     type_len = 2147488769
 
     def __init__(self, value=None):
@@ -2519,6 +2156,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -2527,12 +2165,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ip_proto()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147488769)
         obj.value = reader.read("!B")[0]
@@ -2543,13 +2177,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("ip_proto {")
         with q.group():
@@ -2560,7 +2187,9 @@
             q.breakable()
         q.text('}')
 
-class ip_proto_masked(OXM):
+oxm.subtypes[2147488769] = ip_proto
+
+class ip_proto_masked(oxm):
     type_len = 2147489026
 
     def __init__(self, value=None, value_mask=None):
@@ -2572,6 +2201,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -2581,12 +2211,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ip_proto_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147489026)
         obj.value = reader.read("!B")[0]
@@ -2599,13 +2225,6 @@
         if self.value_mask != other.value_mask: 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("ip_proto_masked {")
         with q.group():
@@ -2619,7 +2238,9 @@
             q.breakable()
         q.text('}')
 
-class ipv4_dst(OXM):
+oxm.subtypes[2147489026] = ip_proto_masked
+
+class ipv4_dst(oxm):
     type_len = 2147489796
 
     def __init__(self, value=None):
@@ -2627,6 +2248,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -2635,12 +2257,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv4_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147489796)
         obj.value = reader.read("!L")[0]
@@ -2651,13 +2269,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("ipv4_dst {")
         with q.group():
@@ -2668,7 +2279,9 @@
             q.breakable()
         q.text('}')
 
-class ipv4_dst_masked(OXM):
+oxm.subtypes[2147489796] = ipv4_dst
+
+class ipv4_dst_masked(oxm):
     type_len = 2147490056
 
     def __init__(self, value=None, value_mask=None):
@@ -2680,6 +2293,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -2689,12 +2303,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv4_dst_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147490056)
         obj.value = reader.read("!L")[0]
@@ -2707,13 +2317,6 @@
         if self.value_mask != other.value_mask: 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("ipv4_dst_masked {")
         with q.group():
@@ -2727,7 +2330,9 @@
             q.breakable()
         q.text('}')
 
-class ipv4_src(OXM):
+oxm.subtypes[2147490056] = ipv4_dst_masked
+
+class ipv4_src(oxm):
     type_len = 2147489284
 
     def __init__(self, value=None):
@@ -2735,6 +2340,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -2743,12 +2349,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv4_src()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147489284)
         obj.value = reader.read("!L")[0]
@@ -2759,13 +2361,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("ipv4_src {")
         with q.group():
@@ -2776,7 +2371,9 @@
             q.breakable()
         q.text('}')
 
-class ipv4_src_masked(OXM):
+oxm.subtypes[2147489284] = ipv4_src
+
+class ipv4_src_masked(oxm):
     type_len = 2147489544
 
     def __init__(self, value=None, value_mask=None):
@@ -2788,6 +2385,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -2797,12 +2395,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv4_src_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147489544)
         obj.value = reader.read("!L")[0]
@@ -2815,13 +2409,6 @@
         if self.value_mask != other.value_mask: 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("ipv4_src_masked {")
         with q.group():
@@ -2835,7 +2422,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_dst(OXM):
+oxm.subtypes[2147489544] = ipv4_src_masked
+
+class ipv6_dst(oxm):
     type_len = 2147497488
 
     def __init__(self, value=None):
@@ -2843,6 +2432,7 @@
             self.value = value
         else:
             self.value = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+        return
 
     def pack(self):
         packed = []
@@ -2851,12 +2441,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147497488)
         obj.value = reader.read('!16s')[0]
@@ -2867,13 +2453,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("ipv6_dst {")
         with q.group():
@@ -2884,7 +2463,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_dst_masked(OXM):
+oxm.subtypes[2147497488] = ipv6_dst
+
+class ipv6_dst_masked(oxm):
     type_len = 2147497760
 
     def __init__(self, value=None, value_mask=None):
@@ -2896,6 +2477,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+        return
 
     def pack(self):
         packed = []
@@ -2905,12 +2487,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_dst_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147497760)
         obj.value = reader.read('!16s')[0]
@@ -2923,13 +2501,6 @@
         if self.value_mask != other.value_mask: 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("ipv6_dst_masked {")
         with q.group():
@@ -2943,7 +2514,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_flabel(OXM):
+oxm.subtypes[2147497760] = ipv6_dst_masked
+
+class ipv6_flabel(oxm):
     type_len = 2147497988
 
     def __init__(self, value=None):
@@ -2951,6 +2524,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -2959,12 +2533,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_flabel()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147497988)
         obj.value = reader.read("!L")[0]
@@ -2975,13 +2545,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("ipv6_flabel {")
         with q.group():
@@ -2992,7 +2555,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_flabel_masked(OXM):
+oxm.subtypes[2147497988] = ipv6_flabel
+
+class ipv6_flabel_masked(oxm):
     type_len = 2147498248
 
     def __init__(self, value=None, value_mask=None):
@@ -3004,6 +2569,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -3013,12 +2579,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_flabel_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147498248)
         obj.value = reader.read("!L")[0]
@@ -3031,13 +2593,6 @@
         if self.value_mask != other.value_mask: 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("ipv6_flabel_masked {")
         with q.group():
@@ -3051,7 +2606,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_nd_sll(OXM):
+oxm.subtypes[2147498248] = ipv6_flabel_masked
+
+class ipv6_nd_sll(oxm):
     type_len = 2147500038
 
     def __init__(self, value=None):
@@ -3059,6 +2616,7 @@
             self.value = value
         else:
             self.value = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -3067,12 +2625,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_nd_sll()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147500038)
         obj.value = list(reader.read('!6B'))
@@ -3083,13 +2637,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("ipv6_nd_sll {")
         with q.group():
@@ -3100,7 +2647,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_nd_sll_masked(OXM):
+oxm.subtypes[2147500038] = ipv6_nd_sll
+
+class ipv6_nd_sll_masked(oxm):
     type_len = 2147500300
 
     def __init__(self, value=None, value_mask=None):
@@ -3112,6 +2661,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -3121,12 +2671,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_nd_sll_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147500300)
         obj.value = list(reader.read('!6B'))
@@ -3139,13 +2685,6 @@
         if self.value_mask != other.value_mask: 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("ipv6_nd_sll_masked {")
         with q.group():
@@ -3159,7 +2698,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_nd_target(OXM):
+oxm.subtypes[2147500300] = ipv6_nd_sll_masked
+
+class ipv6_nd_target(oxm):
     type_len = 2147499536
 
     def __init__(self, value=None):
@@ -3167,6 +2708,7 @@
             self.value = value
         else:
             self.value = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+        return
 
     def pack(self):
         packed = []
@@ -3175,12 +2717,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_nd_target()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147499536)
         obj.value = reader.read('!16s')[0]
@@ -3191,13 +2729,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("ipv6_nd_target {")
         with q.group():
@@ -3208,7 +2739,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_nd_target_masked(OXM):
+oxm.subtypes[2147499536] = ipv6_nd_target
+
+class ipv6_nd_target_masked(oxm):
     type_len = 2147499808
 
     def __init__(self, value=None, value_mask=None):
@@ -3220,6 +2753,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+        return
 
     def pack(self):
         packed = []
@@ -3229,12 +2763,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_nd_target_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147499808)
         obj.value = reader.read('!16s')[0]
@@ -3247,13 +2777,6 @@
         if self.value_mask != other.value_mask: 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("ipv6_nd_target_masked {")
         with q.group():
@@ -3267,7 +2790,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_nd_tll(OXM):
+oxm.subtypes[2147499808] = ipv6_nd_target_masked
+
+class ipv6_nd_tll(oxm):
     type_len = 2147500550
 
     def __init__(self, value=None):
@@ -3275,6 +2800,7 @@
             self.value = value
         else:
             self.value = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -3283,12 +2809,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_nd_tll()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147500550)
         obj.value = list(reader.read('!6B'))
@@ -3299,13 +2821,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("ipv6_nd_tll {")
         with q.group():
@@ -3316,7 +2831,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_nd_tll_masked(OXM):
+oxm.subtypes[2147500550] = ipv6_nd_tll
+
+class ipv6_nd_tll_masked(oxm):
     type_len = 2147500812
 
     def __init__(self, value=None, value_mask=None):
@@ -3328,6 +2845,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = [0,0,0,0,0,0]
+        return
 
     def pack(self):
         packed = []
@@ -3337,12 +2855,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_nd_tll_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147500812)
         obj.value = list(reader.read('!6B'))
@@ -3355,13 +2869,6 @@
         if self.value_mask != other.value_mask: 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("ipv6_nd_tll_masked {")
         with q.group():
@@ -3375,7 +2882,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_src(OXM):
+oxm.subtypes[2147500812] = ipv6_nd_tll_masked
+
+class ipv6_src(oxm):
     type_len = 2147496976
 
     def __init__(self, value=None):
@@ -3383,6 +2892,7 @@
             self.value = value
         else:
             self.value = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+        return
 
     def pack(self):
         packed = []
@@ -3391,12 +2901,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_src()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147496976)
         obj.value = reader.read('!16s')[0]
@@ -3407,13 +2913,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("ipv6_src {")
         with q.group():
@@ -3424,7 +2923,9 @@
             q.breakable()
         q.text('}')
 
-class ipv6_src_masked(OXM):
+oxm.subtypes[2147496976] = ipv6_src
+
+class ipv6_src_masked(oxm):
     type_len = 2147497248
 
     def __init__(self, value=None, value_mask=None):
@@ -3436,6 +2937,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+        return
 
     def pack(self):
         packed = []
@@ -3445,12 +2947,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = ipv6_src_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147497248)
         obj.value = reader.read('!16s')[0]
@@ -3463,13 +2961,6 @@
         if self.value_mask != other.value_mask: 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("ipv6_src_masked {")
         with q.group():
@@ -3483,7 +2974,9 @@
             q.breakable()
         q.text('}')
 
-class metadata(OXM):
+oxm.subtypes[2147497248] = ipv6_src_masked
+
+class metadata(oxm):
     type_len = 2147484680
 
     def __init__(self, value=None):
@@ -3491,6 +2984,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -3499,12 +2993,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = metadata()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147484680)
         obj.value = reader.read("!Q")[0]
@@ -3515,13 +3005,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("metadata {")
         with q.group():
@@ -3532,7 +3015,9 @@
             q.breakable()
         q.text('}')
 
-class metadata_masked(OXM):
+oxm.subtypes[2147484680] = metadata
+
+class metadata_masked(oxm):
     type_len = 2147484944
 
     def __init__(self, value=None, value_mask=None):
@@ -3544,6 +3029,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -3553,12 +3039,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = metadata_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147484944)
         obj.value = reader.read("!Q")[0]
@@ -3571,13 +3053,6 @@
         if self.value_mask != other.value_mask: 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("metadata_masked {")
         with q.group():
@@ -3591,7 +3066,9 @@
             q.breakable()
         q.text('}')
 
-class mpls_label(OXM):
+oxm.subtypes[2147484944] = metadata_masked
+
+class mpls_label(oxm):
     type_len = 2147501060
 
     def __init__(self, value=None):
@@ -3599,6 +3076,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -3607,12 +3085,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = mpls_label()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147501060)
         obj.value = reader.read("!L")[0]
@@ -3623,13 +3097,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("mpls_label {")
         with q.group():
@@ -3640,7 +3107,9 @@
             q.breakable()
         q.text('}')
 
-class mpls_label_masked(OXM):
+oxm.subtypes[2147501060] = mpls_label
+
+class mpls_label_masked(oxm):
     type_len = 2147501320
 
     def __init__(self, value=None, value_mask=None):
@@ -3652,6 +3121,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -3661,12 +3131,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = mpls_label_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147501320)
         obj.value = reader.read("!L")[0]
@@ -3679,13 +3145,6 @@
         if self.value_mask != other.value_mask: 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("mpls_label_masked {")
         with q.group():
@@ -3699,7 +3158,9 @@
             q.breakable()
         q.text('}')
 
-class mpls_tc(OXM):
+oxm.subtypes[2147501320] = mpls_label_masked
+
+class mpls_tc(oxm):
     type_len = 2147501569
 
     def __init__(self, value=None):
@@ -3707,6 +3168,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -3715,12 +3177,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = mpls_tc()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147501569)
         obj.value = reader.read("!B")[0]
@@ -3731,13 +3189,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("mpls_tc {")
         with q.group():
@@ -3748,7 +3199,9 @@
             q.breakable()
         q.text('}')
 
-class mpls_tc_masked(OXM):
+oxm.subtypes[2147501569] = mpls_tc
+
+class mpls_tc_masked(oxm):
     type_len = 2147501826
 
     def __init__(self, value=None, value_mask=None):
@@ -3760,6 +3213,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -3769,12 +3223,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = mpls_tc_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147501826)
         obj.value = reader.read("!B")[0]
@@ -3787,13 +3237,6 @@
         if self.value_mask != other.value_mask: 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("mpls_tc_masked {")
         with q.group():
@@ -3807,7 +3250,9 @@
             q.breakable()
         q.text('}')
 
-class sctp_dst(OXM):
+oxm.subtypes[2147501826] = mpls_tc_masked
+
+class sctp_dst(oxm):
     type_len = 2147492866
 
     def __init__(self, value=None):
@@ -3815,6 +3260,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -3823,12 +3269,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = sctp_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147492866)
         obj.value = reader.read("!H")[0]
@@ -3839,13 +3281,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("sctp_dst {")
         with q.group():
@@ -3856,7 +3291,9 @@
             q.breakable()
         q.text('}')
 
-class sctp_dst_masked(OXM):
+oxm.subtypes[2147492866] = sctp_dst
+
+class sctp_dst_masked(oxm):
     type_len = 2147493124
 
     def __init__(self, value=None, value_mask=None):
@@ -3868,6 +3305,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -3877,12 +3315,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = sctp_dst_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147493124)
         obj.value = reader.read("!H")[0]
@@ -3895,13 +3329,6 @@
         if self.value_mask != other.value_mask: 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("sctp_dst_masked {")
         with q.group():
@@ -3915,7 +3342,9 @@
             q.breakable()
         q.text('}')
 
-class sctp_src(OXM):
+oxm.subtypes[2147493124] = sctp_dst_masked
+
+class sctp_src(oxm):
     type_len = 2147492354
 
     def __init__(self, value=None):
@@ -3923,6 +3352,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -3931,12 +3361,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = sctp_src()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147492354)
         obj.value = reader.read("!H")[0]
@@ -3947,13 +3373,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("sctp_src {")
         with q.group():
@@ -3964,7 +3383,9 @@
             q.breakable()
         q.text('}')
 
-class sctp_src_masked(OXM):
+oxm.subtypes[2147492354] = sctp_src
+
+class sctp_src_masked(oxm):
     type_len = 2147492612
 
     def __init__(self, value=None, value_mask=None):
@@ -3976,6 +3397,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -3985,12 +3407,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = sctp_src_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147492612)
         obj.value = reader.read("!H")[0]
@@ -4003,13 +3421,6 @@
         if self.value_mask != other.value_mask: 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("sctp_src_masked {")
         with q.group():
@@ -4023,7 +3434,9 @@
             q.breakable()
         q.text('}')
 
-class tcp_dst(OXM):
+oxm.subtypes[2147492612] = sctp_src_masked
+
+class tcp_dst(oxm):
     type_len = 2147490818
 
     def __init__(self, value=None):
@@ -4031,6 +3444,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -4039,12 +3453,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = tcp_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147490818)
         obj.value = reader.read("!H")[0]
@@ -4055,13 +3465,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("tcp_dst {")
         with q.group():
@@ -4072,7 +3475,9 @@
             q.breakable()
         q.text('}')
 
-class tcp_dst_masked(OXM):
+oxm.subtypes[2147490818] = tcp_dst
+
+class tcp_dst_masked(oxm):
     type_len = 2147491076
 
     def __init__(self, value=None, value_mask=None):
@@ -4084,6 +3489,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -4093,12 +3499,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = tcp_dst_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147491076)
         obj.value = reader.read("!H")[0]
@@ -4111,13 +3513,6 @@
         if self.value_mask != other.value_mask: 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("tcp_dst_masked {")
         with q.group():
@@ -4131,7 +3526,9 @@
             q.breakable()
         q.text('}')
 
-class tcp_src(OXM):
+oxm.subtypes[2147491076] = tcp_dst_masked
+
+class tcp_src(oxm):
     type_len = 2147490306
 
     def __init__(self, value=None):
@@ -4139,6 +3536,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -4147,12 +3545,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = tcp_src()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147490306)
         obj.value = reader.read("!H")[0]
@@ -4163,13 +3557,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("tcp_src {")
         with q.group():
@@ -4180,7 +3567,9 @@
             q.breakable()
         q.text('}')
 
-class tcp_src_masked(OXM):
+oxm.subtypes[2147490306] = tcp_src
+
+class tcp_src_masked(oxm):
     type_len = 2147490564
 
     def __init__(self, value=None, value_mask=None):
@@ -4192,6 +3581,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -4201,12 +3591,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = tcp_src_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147490564)
         obj.value = reader.read("!H")[0]
@@ -4219,13 +3605,6 @@
         if self.value_mask != other.value_mask: 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("tcp_src_masked {")
         with q.group():
@@ -4239,7 +3618,9 @@
             q.breakable()
         q.text('}')
 
-class udp_dst(OXM):
+oxm.subtypes[2147490564] = tcp_src_masked
+
+class udp_dst(oxm):
     type_len = 2147491842
 
     def __init__(self, value=None):
@@ -4247,6 +3628,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -4255,12 +3637,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = udp_dst()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147491842)
         obj.value = reader.read("!H")[0]
@@ -4271,13 +3649,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("udp_dst {")
         with q.group():
@@ -4288,7 +3659,9 @@
             q.breakable()
         q.text('}')
 
-class udp_dst_masked(OXM):
+oxm.subtypes[2147491842] = udp_dst
+
+class udp_dst_masked(oxm):
     type_len = 2147492100
 
     def __init__(self, value=None, value_mask=None):
@@ -4300,6 +3673,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -4309,12 +3683,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = udp_dst_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147492100)
         obj.value = reader.read("!H")[0]
@@ -4327,13 +3697,6 @@
         if self.value_mask != other.value_mask: 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("udp_dst_masked {")
         with q.group():
@@ -4347,7 +3710,9 @@
             q.breakable()
         q.text('}')
 
-class udp_src(OXM):
+oxm.subtypes[2147492100] = udp_dst_masked
+
+class udp_src(oxm):
     type_len = 2147491330
 
     def __init__(self, value=None):
@@ -4355,6 +3720,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -4363,12 +3729,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = udp_src()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147491330)
         obj.value = reader.read("!H")[0]
@@ -4379,13 +3741,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("udp_src {")
         with q.group():
@@ -4396,7 +3751,9 @@
             q.breakable()
         q.text('}')
 
-class udp_src_masked(OXM):
+oxm.subtypes[2147491330] = udp_src
+
+class udp_src_masked(oxm):
     type_len = 2147491588
 
     def __init__(self, value=None, value_mask=None):
@@ -4408,6 +3765,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -4417,12 +3775,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = udp_src_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147491588)
         obj.value = reader.read("!H")[0]
@@ -4435,13 +3789,6 @@
         if self.value_mask != other.value_mask: 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("udp_src_masked {")
         with q.group():
@@ -4455,7 +3802,9 @@
             q.breakable()
         q.text('}')
 
-class vlan_pcp(OXM):
+oxm.subtypes[2147491588] = udp_src_masked
+
+class vlan_pcp(oxm):
     type_len = 2147487233
 
     def __init__(self, value=None):
@@ -4463,6 +3812,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -4471,12 +3821,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = vlan_pcp()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147487233)
         obj.value = reader.read("!B")[0]
@@ -4487,13 +3833,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("vlan_pcp {")
         with q.group():
@@ -4504,7 +3843,9 @@
             q.breakable()
         q.text('}')
 
-class vlan_pcp_masked(OXM):
+oxm.subtypes[2147487233] = vlan_pcp
+
+class vlan_pcp_masked(oxm):
     type_len = 2147487490
 
     def __init__(self, value=None, value_mask=None):
@@ -4516,6 +3857,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -4525,12 +3867,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = vlan_pcp_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147487490)
         obj.value = reader.read("!B")[0]
@@ -4543,13 +3881,6 @@
         if self.value_mask != other.value_mask: 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("vlan_pcp_masked {")
         with q.group():
@@ -4563,7 +3894,9 @@
             q.breakable()
         q.text('}')
 
-class vlan_vid(OXM):
+oxm.subtypes[2147487490] = vlan_pcp_masked
+
+class vlan_vid(oxm):
     type_len = 2147486722
 
     def __init__(self, value=None):
@@ -4571,6 +3904,7 @@
             self.value = value
         else:
             self.value = 0
+        return
 
     def pack(self):
         packed = []
@@ -4579,12 +3913,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = vlan_vid()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147486722)
         obj.value = reader.read("!H")[0]
@@ -4595,13 +3925,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("vlan_vid {")
         with q.group():
@@ -4612,7 +3935,9 @@
             q.breakable()
         q.text('}')
 
-class vlan_vid_masked(OXM):
+oxm.subtypes[2147486722] = vlan_vid
+
+class vlan_vid_masked(oxm):
     type_len = 2147486980
 
     def __init__(self, value=None, value_mask=None):
@@ -4624,6 +3949,7 @@
             self.value_mask = value_mask
         else:
             self.value_mask = 0
+        return
 
     def pack(self):
         packed = []
@@ -4633,12 +3959,8 @@
         return ''.join(packed)
 
     @staticmethod
-    def unpack(buf):
+    def unpack(reader):
         obj = vlan_vid_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
         _type_len = reader.read("!L")[0]
         assert(_type_len == 2147486980)
         obj.value = reader.read("!H")[0]
@@ -4651,13 +3973,6 @@
         if self.value_mask != other.value_mask: 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("vlan_vid_masked {")
         with q.group():
@@ -4671,92 +3986,6 @@
             q.breakable()
         q.text('}')
 
+oxm.subtypes[2147486980] = vlan_vid_masked
 
-parsers = {
-    196640 : bsn_in_ports_128.unpack,
-    196896 : bsn_in_ports_128_masked.unpack,
-    197124 : bsn_lag_id.unpack,
-    197380 : bsn_lag_id_masked.unpack,
-    197636 : bsn_vrf.unpack,
-    197892 : bsn_vrf_masked.unpack,
-    198145 : bsn_global_vrf_allowed.unpack,
-    198401 : bsn_global_vrf_allowed_masked.unpack,
-    198660 : bsn_l3_interface_class_id.unpack,
-    198916 : bsn_l3_interface_class_id_masked.unpack,
-    199172 : bsn_l3_src_class_id.unpack,
-    199428 : bsn_l3_src_class_id_masked.unpack,
-    199684 : bsn_l3_dst_class_id.unpack,
-    199940 : bsn_l3_dst_class_id_masked.unpack,
-    2147483652 : in_port.unpack,
-    2147483912 : in_port_masked.unpack,
-    2147484164 : in_phy_port.unpack,
-    2147484424 : in_phy_port_masked.unpack,
-    2147484680 : metadata.unpack,
-    2147484944 : metadata_masked.unpack,
-    2147485190 : eth_dst.unpack,
-    2147485452 : eth_dst_masked.unpack,
-    2147485702 : eth_src.unpack,
-    2147485964 : eth_src_masked.unpack,
-    2147486210 : eth_type.unpack,
-    2147486468 : eth_type_masked.unpack,
-    2147486722 : vlan_vid.unpack,
-    2147486980 : vlan_vid_masked.unpack,
-    2147487233 : vlan_pcp.unpack,
-    2147487490 : vlan_pcp_masked.unpack,
-    2147487745 : ip_dscp.unpack,
-    2147488002 : ip_dscp_masked.unpack,
-    2147488257 : ip_ecn.unpack,
-    2147488514 : ip_ecn_masked.unpack,
-    2147488769 : ip_proto.unpack,
-    2147489026 : ip_proto_masked.unpack,
-    2147489284 : ipv4_src.unpack,
-    2147489544 : ipv4_src_masked.unpack,
-    2147489796 : ipv4_dst.unpack,
-    2147490056 : ipv4_dst_masked.unpack,
-    2147490306 : tcp_src.unpack,
-    2147490564 : tcp_src_masked.unpack,
-    2147490818 : tcp_dst.unpack,
-    2147491076 : tcp_dst_masked.unpack,
-    2147491330 : udp_src.unpack,
-    2147491588 : udp_src_masked.unpack,
-    2147491842 : udp_dst.unpack,
-    2147492100 : udp_dst_masked.unpack,
-    2147492354 : sctp_src.unpack,
-    2147492612 : sctp_src_masked.unpack,
-    2147492866 : sctp_dst.unpack,
-    2147493124 : sctp_dst_masked.unpack,
-    2147493377 : icmpv4_type.unpack,
-    2147493634 : icmpv4_type_masked.unpack,
-    2147493889 : icmpv4_code.unpack,
-    2147494146 : icmpv4_code_masked.unpack,
-    2147494402 : arp_op.unpack,
-    2147494660 : arp_op_masked.unpack,
-    2147494916 : arp_spa.unpack,
-    2147495176 : arp_spa_masked.unpack,
-    2147495428 : arp_tpa.unpack,
-    2147495688 : arp_tpa_masked.unpack,
-    2147495942 : arp_sha.unpack,
-    2147496204 : arp_sha_masked.unpack,
-    2147496454 : arp_tha.unpack,
-    2147496716 : arp_tha_masked.unpack,
-    2147496976 : ipv6_src.unpack,
-    2147497248 : ipv6_src_masked.unpack,
-    2147497488 : ipv6_dst.unpack,
-    2147497760 : ipv6_dst_masked.unpack,
-    2147497988 : ipv6_flabel.unpack,
-    2147498248 : ipv6_flabel_masked.unpack,
-    2147498497 : icmpv6_type.unpack,
-    2147498754 : icmpv6_type_masked.unpack,
-    2147499009 : icmpv6_code.unpack,
-    2147499266 : icmpv6_code_masked.unpack,
-    2147499536 : ipv6_nd_target.unpack,
-    2147499808 : ipv6_nd_target_masked.unpack,
-    2147500038 : ipv6_nd_sll.unpack,
-    2147500300 : ipv6_nd_sll_masked.unpack,
-    2147500550 : ipv6_nd_tll.unpack,
-    2147500812 : ipv6_nd_tll_masked.unpack,
-    2147501060 : mpls_label.unpack,
-    2147501320 : mpls_label_masked.unpack,
-    2147501569 : mpls_tc.unpack,
-    2147501826 : mpls_tc_masked.unpack,
-}
+
diff --git a/src/python/loxi/of13/util.py b/src/python/loxi/of13/util.py
index b908451..5958398 100644
--- a/src/python/loxi/of13/util.py
+++ b/src/python/loxi/of13/util.py
@@ -5,9 +5,16 @@
 # Automatically generated by LOXI from template util.py
 # Do not modify
 
+import struct
 import loxi
 import const
-import struct
+import common
+import action
+import instruction
+import oxm
+import action_id
+import instruction_id
+import meter_band
 
 def pretty_mac(mac):
     return ':'.join(["%02x" % x for x in mac])
@@ -66,9 +73,6 @@
 def unpack_match_bmap(reader):
     return reader.read("!Q")[0]
 
-def pack_list(values):
-    return "".join([x.pack() for x in values])
-
 MASK64 = (1 << 64) - 1
 
 def pack_bitmap_128(value):
@@ -88,3 +92,13 @@
         i += 1
         x >>= 1
     return value
+
+def unpack_list_hello_elem(reader):
+    def deserializer(reader):
+        typ, length, = reader.peek('!HH')
+        reader = reader.slice(length)
+        try:
+            return common.hello_elem.unpack(reader)
+        except loxi.ProtocolError:
+            return None
+    return [x for x in loxi.generic_util.unpack_list(reader, deserializer) if x != None]