import pyloxi @ 39ed7a3
diff --git a/src/python/loxi/of10/action.py b/src/python/loxi/of10/action.py
new file mode 100644
index 0000000..c6129a5
--- /dev/null
+++ b/src/python/loxi/of10/action.py
@@ -0,0 +1,1029 @@
+#
+# Copyright 2012, 2013, Big Switch Networks, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+# Automatically generated by LOXI from template action.py
+# Do not modify
+
+import struct
+import const
+import util
+import loxi
+
+def unpack_list(buf):
+    if len(buf) % 8 != 0: raise loxi.ProtocolError("action list length not a multiple of 8")
+    actions = []
+    offset = 0
+    while offset < len(buf):
+        type, length = struct.unpack_from("!HH", buf, offset)
+        if length == 0: raise loxi.ProtocolError("action length is 0")
+        if length % 8 != 0: raise loxi.ProtocolError("action length not a multiple of 8")
+        if offset + length > len(buf): raise loxi.ProtocolError("action length overruns list length")
+        parser = parsers.get(type)
+        if not parser: raise loxi.ProtocolError("unknown action type %d" % type)
+        actions.append(parser(buffer(buf, offset, length)))
+        offset += length
+    return actions
+
+class Action(object):
+    type = None # override in subclass
+    pass
+
+class bsn_mirror(Action):
+    type = const.OFPAT_VENDOR
+    experimenter = 0x5c16c7
+    subtype = 1
+
+    def __init__(self, dest_port=None, vlan_tag=None, copy_stage=None, pad=None):
+        if dest_port != None:
+            self.dest_port = dest_port
+        else:
+            self.dest_port = 0
+        if vlan_tag != None:
+            self.vlan_tag = vlan_tag
+        else:
+            self.vlan_tag = 0
+        if copy_stage != None:
+            self.copy_stage = copy_stage
+        else:
+            self.copy_stage = 0
+        if pad != None:
+            self.pad = pad
+        else:
+            self.pad = [0,0,0]
+
+    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(struct.pack("!L", self.dest_port))
+        packed.append(struct.pack("!L", self.vlan_tag))
+        packed.append(struct.pack("!B", self.copy_stage))
+        packed.append(struct.pack("!3B", *self.pad))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(buf):
+        obj = bsn_mirror()
+        type = struct.unpack_from('!H', buf, 0)[0]
+        assert(type == const.OFPAT_VENDOR)
+        _length = struct.unpack_from('!H', buf, 2)[0]
+        assert(_length == len(buf))
+        if _length != 24: raise loxi.ProtocolError("bsn_mirror length is %d, should be 24" % _length)
+        experimenter = struct.unpack_from('!L', buf, 4)[0]
+        assert(experimenter == 0x5c16c7)
+        subtype = struct.unpack_from('!L', buf, 8)[0]
+        assert(subtype == 1)
+        obj.dest_port = struct.unpack_from('!L', buf, 12)[0]
+        obj.vlan_tag = struct.unpack_from('!L', buf, 16)[0]
+        obj.copy_stage = struct.unpack_from('!B', buf, 20)[0]
+        obj.pad = list(struct.unpack_from('!3B', buf, 21))
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.type != other.type: return False
+        if self.dest_port != other.dest_port: return False
+        if self.vlan_tag != other.vlan_tag: return False
+        if self.copy_stage != other.copy_stage: return False
+        if self.pad != other.pad: return False
+        return True
+
+    def __ne__(self, 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():
+            with q.indent(2):
+                q.breakable()
+                q.text("dest_port = ");
+                q.text("%#x" % self.dest_port)
+                q.text(","); q.breakable()
+                q.text("vlan_tag = ");
+                q.text("%#x" % self.vlan_tag)
+                q.text(","); q.breakable()
+                q.text("copy_stage = ");
+                q.text("%#x" % self.copy_stage)
+                q.text(","); q.breakable()
+                q.text("pad = ");
+                q.pp(self.pad)
+            q.breakable()
+        q.text('}')
+
+class bsn_set_tunnel_dst(Action):
+    type = const.OFPAT_VENDOR
+    experimenter = 0x5c16c7
+    subtype = 2
+
+    def __init__(self, dst=None):
+        if dst != None:
+            self.dst = dst
+        else:
+            self.dst = 0
+
+    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(struct.pack("!L", self.dst))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(buf):
+        obj = bsn_set_tunnel_dst()
+        type = struct.unpack_from('!H', buf, 0)[0]
+        assert(type == const.OFPAT_VENDOR)
+        _length = struct.unpack_from('!H', buf, 2)[0]
+        assert(_length == len(buf))
+        if _length != 16: raise loxi.ProtocolError("bsn_set_tunnel_dst length is %d, should be 16" % _length)
+        experimenter = struct.unpack_from('!L', buf, 4)[0]
+        assert(experimenter == 0x5c16c7)
+        subtype = struct.unpack_from('!L', buf, 8)[0]
+        assert(subtype == 2)
+        obj.dst = struct.unpack_from('!L', buf, 12)[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.type != other.type: return False
+        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():
+            with q.indent(2):
+                q.breakable()
+                q.text("dst = ");
+                q.text("%#x" % self.dst)
+            q.breakable()
+        q.text('}')
+
+class enqueue(Action):
+    type = const.OFPAT_ENQUEUE
+
+    def __init__(self, port=None, pad=None, queue_id=None):
+        if port != None:
+            self.port = port
+        else:
+            self.port = 0
+        if pad != None:
+            self.pad = pad
+        else:
+            self.pad = [0,0,0,0,0,0]
+        if queue_id != None:
+            self.queue_id = queue_id
+        else:
+            self.queue_id = 0
+
+    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("!H", self.port))
+        packed.append(struct.pack("!6B", *self.pad))
+        packed.append(struct.pack("!L", self.queue_id))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(buf):
+        obj = enqueue()
+        type = struct.unpack_from('!H', buf, 0)[0]
+        assert(type == const.OFPAT_ENQUEUE)
+        _length = struct.unpack_from('!H', buf, 2)[0]
+        assert(_length == len(buf))
+        if _length != 16: raise loxi.ProtocolError("enqueue length is %d, should be 16" % _length)
+        obj.port = struct.unpack_from('!H', buf, 4)[0]
+        obj.pad = list(struct.unpack_from('!6B', buf, 6))
+        obj.queue_id = struct.unpack_from('!L', buf, 12)[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.type != other.type: return False
+        if self.port != other.port: return False
+        if self.pad != other.pad: return False
+        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():
+            with q.indent(2):
+                q.breakable()
+                q.text("port = ");
+                q.text(util.pretty_port(self.port))
+                q.text(","); q.breakable()
+                q.text("pad = ");
+                q.pp(self.pad)
+                q.text(","); q.breakable()
+                q.text("queue_id = ");
+                q.text("%#x" % self.queue_id)
+            q.breakable()
+        q.text('}')
+
+class nicira_dec_ttl(Action):
+    type = const.OFPAT_VENDOR
+    experimenter = 0x2320
+    subtype = 18
+
+    def __init__(self, pad=None, pad2=None):
+        if pad != None:
+            self.pad = pad
+        else:
+            self.pad = 0
+        if pad2 != None:
+            self.pad2 = pad2
+        else:
+            self.pad2 = 0
+
+    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(struct.pack("!H", self.pad))
+        packed.append(struct.pack("!L", self.pad2))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(buf):
+        obj = nicira_dec_ttl()
+        type = struct.unpack_from('!H', buf, 0)[0]
+        assert(type == const.OFPAT_VENDOR)
+        _length = struct.unpack_from('!H', buf, 2)[0]
+        assert(_length == len(buf))
+        if _length != 16: raise loxi.ProtocolError("nicira_dec_ttl length is %d, should be 16" % _length)
+        experimenter = struct.unpack_from('!L', buf, 4)[0]
+        assert(experimenter == 0x2320)
+        subtype = struct.unpack_from('!H', buf, 8)[0]
+        assert(subtype == 18)
+        obj.pad = struct.unpack_from('!H', buf, 10)[0]
+        obj.pad2 = struct.unpack_from('!L', buf, 12)[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.type != other.type: return False
+        if self.pad != other.pad: return False
+        if self.pad2 != other.pad2: return False
+        return True
+
+    def __ne__(self, 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():
+            with q.indent(2):
+                q.breakable()
+                q.text("pad = ");
+                q.text("%#x" % self.pad)
+                q.text(","); q.breakable()
+                q.text("pad2 = ");
+                q.text("%#x" % self.pad2)
+            q.breakable()
+        q.text('}')
+
+class output(Action):
+    type = const.OFPAT_OUTPUT
+
+    def __init__(self, port=None, max_len=None):
+        if port != None:
+            self.port = port
+        else:
+            self.port = 0
+        if max_len != None:
+            self.max_len = max_len
+        else:
+            self.max_len = 0
+
+    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("!H", self.port))
+        packed.append(struct.pack("!H", self.max_len))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(buf):
+        obj = output()
+        type = struct.unpack_from('!H', buf, 0)[0]
+        assert(type == const.OFPAT_OUTPUT)
+        _length = struct.unpack_from('!H', buf, 2)[0]
+        assert(_length == len(buf))
+        if _length != 8: raise loxi.ProtocolError("output length is %d, should be 8" % _length)
+        obj.port = struct.unpack_from('!H', buf, 4)[0]
+        obj.max_len = struct.unpack_from('!H', buf, 6)[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.type != other.type: return False
+        if self.port != other.port: return False
+        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():
+            with q.indent(2):
+                q.breakable()
+                q.text("port = ");
+                q.text(util.pretty_port(self.port))
+                q.text(","); q.breakable()
+                q.text("max_len = ");
+                q.text("%#x" % self.max_len)
+            q.breakable()
+        q.text('}')
+
+class set_dl_dst(Action):
+    type = const.OFPAT_SET_DL_DST
+
+    def __init__(self, dl_addr=None, pad=None):
+        if dl_addr != None:
+            self.dl_addr = dl_addr
+        else:
+            self.dl_addr = [0,0,0,0,0,0]
+        if pad != None:
+            self.pad = pad
+        else:
+            self.pad = [0,0,0,0,0,0]
+
+    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("!6B", *self.dl_addr))
+        packed.append(struct.pack("!6B", *self.pad))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(buf):
+        obj = set_dl_dst()
+        type = struct.unpack_from('!H', buf, 0)[0]
+        assert(type == const.OFPAT_SET_DL_DST)
+        _length = struct.unpack_from('!H', buf, 2)[0]
+        assert(_length == len(buf))
+        if _length != 16: raise loxi.ProtocolError("set_dl_dst length is %d, should be 16" % _length)
+        obj.dl_addr = list(struct.unpack_from('!6B', buf, 4))
+        obj.pad = list(struct.unpack_from('!6B', buf, 10))
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.type != other.type: return False
+        if self.dl_addr != other.dl_addr: return False
+        if self.pad != other.pad: return False
+        return True
+
+    def __ne__(self, 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():
+            with q.indent(2):
+                q.breakable()
+                q.text("dl_addr = ");
+                q.text(util.pretty_mac(self.dl_addr))
+                q.text(","); q.breakable()
+                q.text("pad = ");
+                q.pp(self.pad)
+            q.breakable()
+        q.text('}')
+
+class set_dl_src(Action):
+    type = const.OFPAT_SET_DL_SRC
+
+    def __init__(self, dl_addr=None, pad=None):
+        if dl_addr != None:
+            self.dl_addr = dl_addr
+        else:
+            self.dl_addr = [0,0,0,0,0,0]
+        if pad != None:
+            self.pad = pad
+        else:
+            self.pad = [0,0,0,0,0,0]
+
+    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("!6B", *self.dl_addr))
+        packed.append(struct.pack("!6B", *self.pad))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(buf):
+        obj = set_dl_src()
+        type = struct.unpack_from('!H', buf, 0)[0]
+        assert(type == const.OFPAT_SET_DL_SRC)
+        _length = struct.unpack_from('!H', buf, 2)[0]
+        assert(_length == len(buf))
+        if _length != 16: raise loxi.ProtocolError("set_dl_src length is %d, should be 16" % _length)
+        obj.dl_addr = list(struct.unpack_from('!6B', buf, 4))
+        obj.pad = list(struct.unpack_from('!6B', buf, 10))
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.type != other.type: return False
+        if self.dl_addr != other.dl_addr: return False
+        if self.pad != other.pad: return False
+        return True
+
+    def __ne__(self, 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():
+            with q.indent(2):
+                q.breakable()
+                q.text("dl_addr = ");
+                q.text(util.pretty_mac(self.dl_addr))
+                q.text(","); q.breakable()
+                q.text("pad = ");
+                q.pp(self.pad)
+            q.breakable()
+        q.text('}')
+
+class set_nw_dst(Action):
+    type = const.OFPAT_SET_NW_DST
+
+    def __init__(self, nw_addr=None):
+        if nw_addr != None:
+            self.nw_addr = nw_addr
+        else:
+            self.nw_addr = 0
+
+    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.nw_addr))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(buf):
+        obj = set_nw_dst()
+        type = struct.unpack_from('!H', buf, 0)[0]
+        assert(type == const.OFPAT_SET_NW_DST)
+        _length = struct.unpack_from('!H', buf, 2)[0]
+        assert(_length == len(buf))
+        if _length != 8: raise loxi.ProtocolError("set_nw_dst length is %d, should be 8" % _length)
+        obj.nw_addr = struct.unpack_from('!L', buf, 4)[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.type != other.type: return False
+        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():
+            with q.indent(2):
+                q.breakable()
+                q.text("nw_addr = ");
+                q.text("%#x" % self.nw_addr)
+            q.breakable()
+        q.text('}')
+
+class set_nw_src(Action):
+    type = const.OFPAT_SET_NW_SRC
+
+    def __init__(self, nw_addr=None):
+        if nw_addr != None:
+            self.nw_addr = nw_addr
+        else:
+            self.nw_addr = 0
+
+    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.nw_addr))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(buf):
+        obj = set_nw_src()
+        type = struct.unpack_from('!H', buf, 0)[0]
+        assert(type == const.OFPAT_SET_NW_SRC)
+        _length = struct.unpack_from('!H', buf, 2)[0]
+        assert(_length == len(buf))
+        if _length != 8: raise loxi.ProtocolError("set_nw_src length is %d, should be 8" % _length)
+        obj.nw_addr = struct.unpack_from('!L', buf, 4)[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.type != other.type: return False
+        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():
+            with q.indent(2):
+                q.breakable()
+                q.text("nw_addr = ");
+                q.text("%#x" % self.nw_addr)
+            q.breakable()
+        q.text('}')
+
+class set_nw_tos(Action):
+    type = const.OFPAT_SET_NW_TOS
+
+    def __init__(self, nw_tos=None, pad=None):
+        if nw_tos != None:
+            self.nw_tos = nw_tos
+        else:
+            self.nw_tos = 0
+        if pad != None:
+            self.pad = pad
+        else:
+            self.pad = [0,0,0]
+
+    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("!B", self.nw_tos))
+        packed.append(struct.pack("!3B", *self.pad))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(buf):
+        obj = set_nw_tos()
+        type = struct.unpack_from('!H', buf, 0)[0]
+        assert(type == const.OFPAT_SET_NW_TOS)
+        _length = struct.unpack_from('!H', buf, 2)[0]
+        assert(_length == len(buf))
+        if _length != 8: raise loxi.ProtocolError("set_nw_tos length is %d, should be 8" % _length)
+        obj.nw_tos = struct.unpack_from('!B', buf, 4)[0]
+        obj.pad = list(struct.unpack_from('!3B', buf, 5))
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.type != other.type: return False
+        if self.nw_tos != other.nw_tos: return False
+        if self.pad != other.pad: return False
+        return True
+
+    def __ne__(self, 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():
+            with q.indent(2):
+                q.breakable()
+                q.text("nw_tos = ");
+                q.text("%#x" % self.nw_tos)
+                q.text(","); q.breakable()
+                q.text("pad = ");
+                q.pp(self.pad)
+            q.breakable()
+        q.text('}')
+
+class set_tp_dst(Action):
+    type = const.OFPAT_SET_TP_DST
+
+    def __init__(self, tp_port=None, pad=None):
+        if tp_port != None:
+            self.tp_port = tp_port
+        else:
+            self.tp_port = 0
+        if pad != None:
+            self.pad = pad
+        else:
+            self.pad = [0,0]
+
+    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("!H", self.tp_port))
+        packed.append(struct.pack("!2B", *self.pad))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(buf):
+        obj = set_tp_dst()
+        type = struct.unpack_from('!H', buf, 0)[0]
+        assert(type == const.OFPAT_SET_TP_DST)
+        _length = struct.unpack_from('!H', buf, 2)[0]
+        assert(_length == len(buf))
+        if _length != 8: raise loxi.ProtocolError("set_tp_dst length is %d, should be 8" % _length)
+        obj.tp_port = struct.unpack_from('!H', buf, 4)[0]
+        obj.pad = list(struct.unpack_from('!2B', buf, 6))
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.type != other.type: return False
+        if self.tp_port != other.tp_port: return False
+        if self.pad != other.pad: return False
+        return True
+
+    def __ne__(self, 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():
+            with q.indent(2):
+                q.breakable()
+                q.text("tp_port = ");
+                q.text("%#x" % self.tp_port)
+                q.text(","); q.breakable()
+                q.text("pad = ");
+                q.pp(self.pad)
+            q.breakable()
+        q.text('}')
+
+class set_tp_src(Action):
+    type = const.OFPAT_SET_TP_SRC
+
+    def __init__(self, tp_port=None, pad=None):
+        if tp_port != None:
+            self.tp_port = tp_port
+        else:
+            self.tp_port = 0
+        if pad != None:
+            self.pad = pad
+        else:
+            self.pad = [0,0]
+
+    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("!H", self.tp_port))
+        packed.append(struct.pack("!2B", *self.pad))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(buf):
+        obj = set_tp_src()
+        type = struct.unpack_from('!H', buf, 0)[0]
+        assert(type == const.OFPAT_SET_TP_SRC)
+        _length = struct.unpack_from('!H', buf, 2)[0]
+        assert(_length == len(buf))
+        if _length != 8: raise loxi.ProtocolError("set_tp_src length is %d, should be 8" % _length)
+        obj.tp_port = struct.unpack_from('!H', buf, 4)[0]
+        obj.pad = list(struct.unpack_from('!2B', buf, 6))
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.type != other.type: return False
+        if self.tp_port != other.tp_port: return False
+        if self.pad != other.pad: return False
+        return True
+
+    def __ne__(self, 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():
+            with q.indent(2):
+                q.breakable()
+                q.text("tp_port = ");
+                q.text("%#x" % self.tp_port)
+                q.text(","); q.breakable()
+                q.text("pad = ");
+                q.pp(self.pad)
+            q.breakable()
+        q.text('}')
+
+class set_vlan_pcp(Action):
+    type = const.OFPAT_SET_VLAN_PCP
+
+    def __init__(self, vlan_pcp=None, pad=None):
+        if vlan_pcp != None:
+            self.vlan_pcp = vlan_pcp
+        else:
+            self.vlan_pcp = 0
+        if pad != None:
+            self.pad = pad
+        else:
+            self.pad = [0,0,0]
+
+    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("!B", self.vlan_pcp))
+        packed.append(struct.pack("!3B", *self.pad))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(buf):
+        obj = set_vlan_pcp()
+        type = struct.unpack_from('!H', buf, 0)[0]
+        assert(type == const.OFPAT_SET_VLAN_PCP)
+        _length = struct.unpack_from('!H', buf, 2)[0]
+        assert(_length == len(buf))
+        if _length != 8: raise loxi.ProtocolError("set_vlan_pcp length is %d, should be 8" % _length)
+        obj.vlan_pcp = struct.unpack_from('!B', buf, 4)[0]
+        obj.pad = list(struct.unpack_from('!3B', buf, 5))
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.type != other.type: return False
+        if self.vlan_pcp != other.vlan_pcp: return False
+        if self.pad != other.pad: return False
+        return True
+
+    def __ne__(self, 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():
+            with q.indent(2):
+                q.breakable()
+                q.text("vlan_pcp = ");
+                q.text("%#x" % self.vlan_pcp)
+                q.text(","); q.breakable()
+                q.text("pad = ");
+                q.pp(self.pad)
+            q.breakable()
+        q.text('}')
+
+class set_vlan_vid(Action):
+    type = const.OFPAT_SET_VLAN_VID
+
+    def __init__(self, vlan_vid=None, pad=None):
+        if vlan_vid != None:
+            self.vlan_vid = vlan_vid
+        else:
+            self.vlan_vid = 0
+        if pad != None:
+            self.pad = pad
+        else:
+            self.pad = [0,0]
+
+    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("!H", self.vlan_vid))
+        packed.append(struct.pack("!2B", *self.pad))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(buf):
+        obj = set_vlan_vid()
+        type = struct.unpack_from('!H', buf, 0)[0]
+        assert(type == const.OFPAT_SET_VLAN_VID)
+        _length = struct.unpack_from('!H', buf, 2)[0]
+        assert(_length == len(buf))
+        if _length != 8: raise loxi.ProtocolError("set_vlan_vid length is %d, should be 8" % _length)
+        obj.vlan_vid = struct.unpack_from('!H', buf, 4)[0]
+        obj.pad = list(struct.unpack_from('!2B', buf, 6))
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.type != other.type: return False
+        if self.vlan_vid != other.vlan_vid: return False
+        if self.pad != other.pad: return False
+        return True
+
+    def __ne__(self, 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():
+            with q.indent(2):
+                q.breakable()
+                q.text("vlan_vid = ");
+                q.text("%#x" % self.vlan_vid)
+                q.text(","); q.breakable()
+                q.text("pad = ");
+                q.pp(self.pad)
+            q.breakable()
+        q.text('}')
+
+class strip_vlan(Action):
+    type = const.OFPAT_STRIP_VLAN
+
+    def __init__(self, pad=None):
+        if pad != None:
+            self.pad = pad
+        else:
+            self.pad = [0,0,0,0]
+
+    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("!4B", *self.pad))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(buf):
+        obj = strip_vlan()
+        type = struct.unpack_from('!H', buf, 0)[0]
+        assert(type == const.OFPAT_STRIP_VLAN)
+        _length = struct.unpack_from('!H', buf, 2)[0]
+        assert(_length == len(buf))
+        if _length != 8: raise loxi.ProtocolError("strip_vlan length is %d, should be 8" % _length)
+        obj.pad = list(struct.unpack_from('!4B', buf, 4))
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.type != other.type: return False
+        if self.pad != other.pad: return False
+        return True
+
+    def __ne__(self, 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():
+            with q.indent(2):
+                q.breakable()
+                q.text("pad = ");
+                q.pp(self.pad)
+            q.breakable()
+        q.text('}')
+
+
+def parse_vendor(buf):
+    if len(buf) < 16:
+        raise loxi.ProtocolError("experimenter action too short")
+
+    experimenter, = struct.unpack_from("!L", buf, 4)
+    if experimenter == 0x005c16c7: # Big Switch Networks
+        subtype, = struct.unpack_from("!L", buf, 8)
+    elif experimenter == 0x00002320: # Nicira
+        subtype, = struct.unpack_from("!H", buf, 8)
+    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 BSN experimenter subtype %#x" % subtype)
+
+parsers = {
+    const.OFPAT_ENQUEUE : enqueue.unpack,
+    const.OFPAT_OUTPUT : output.unpack,
+    const.OFPAT_SET_DL_DST : set_dl_dst.unpack,
+    const.OFPAT_SET_DL_SRC : set_dl_src.unpack,
+    const.OFPAT_SET_NW_DST : set_nw_dst.unpack,
+    const.OFPAT_SET_NW_SRC : set_nw_src.unpack,
+    const.OFPAT_SET_NW_TOS : set_nw_tos.unpack,
+    const.OFPAT_SET_TP_DST : set_tp_dst.unpack,
+    const.OFPAT_SET_TP_SRC : set_tp_src.unpack,
+    const.OFPAT_SET_VLAN_PCP : set_vlan_pcp.unpack,
+    const.OFPAT_SET_VLAN_VID : set_vlan_vid.unpack,
+    const.OFPAT_STRIP_VLAN : strip_vlan.unpack,
+    const.OFPAT_VENDOR : parse_vendor,
+}
+
+experimenter_parsers = {
+    0x2320 : {
+        18: nicira_dec_ttl.unpack,
+    },
+    0x5c16c7 : {
+        1: bsn_mirror.unpack,
+        2: bsn_set_tunnel_dst.unpack,
+    },
+}