backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / ofproto / ofproto_v1_4_parser.py
diff --git a/ryu/build/lib.linux-armv7l-2.7/ryu/ofproto/ofproto_v1_4_parser.py b/ryu/build/lib.linux-armv7l-2.7/ryu/ofproto/ofproto_v1_4_parser.py
new file mode 100644 (file)
index 0000000..470e201
--- /dev/null
@@ -0,0 +1,5839 @@
+# Copyright (C) 2012, 2013, 2014 Nippon Telegraph and Telephone Corporation.
+# Copyright (C) 2012, 2013 Isaku Yamahata <yamahata at valinux co jp>
+#
+# 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.
+
+"""
+Decoder/Encoder implementations of OpenFlow 1.4.
+"""
+
+import struct
+import base64
+
+import six
+
+from ryu.lib import addrconv
+from ryu.lib.pack_utils import msg_pack_into
+from ryu.lib.packet import packet
+from ryu import utils
+from ryu.ofproto.ofproto_parser import StringifyMixin, MsgBase, MsgInMsgBase
+from ryu.ofproto import ether
+from ryu.ofproto import nx_actions
+from ryu.ofproto import ofproto_parser
+from ryu.ofproto import ofproto_common
+from ryu.ofproto import ofproto_v1_4 as ofproto
+
+_MSG_PARSERS = {}
+
+
+def _set_msg_type(msg_type):
+    def _set_cls_msg_type(cls):
+        cls.cls_msg_type = msg_type
+        return cls
+    return _set_cls_msg_type
+
+
+def _register_parser(cls):
+    '''class decorator to register msg parser'''
+    assert cls.cls_msg_type is not None
+    assert cls.cls_msg_type not in _MSG_PARSERS
+    _MSG_PARSERS[cls.cls_msg_type] = cls.parser
+    return cls
+
+
+@ofproto_parser.register_msg_parser(ofproto.OFP_VERSION)
+def msg_parser(datapath, version, msg_type, msg_len, xid, buf):
+    parser = _MSG_PARSERS.get(msg_type)
+    return parser(datapath, version, msg_type, msg_len, xid, buf)
+
+
+@_register_parser
+@_set_msg_type(ofproto.OFPT_HELLO)
+class OFPHello(MsgBase):
+    """
+    Hello message
+
+    When connection is started, the hello message is exchanged between a
+    switch and a controller.
+
+    This message is handled by the Ryu framework, so the Ryu application
+    do not need to process this typically.
+
+    ========== =========================================================
+    Attribute  Description
+    ========== =========================================================
+    elements   list of ``OFPHelloElemVersionBitmap`` instance
+    ========== =========================================================
+    """
+
+    def __init__(self, datapath, elements=None):
+        elements = elements if elements else []
+        super(OFPHello, self).__init__(datapath)
+        self.elements = elements
+
+    @classmethod
+    def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+        msg = super(OFPHello, cls).parser(datapath, version, msg_type,
+                                          msg_len, xid, buf)
+
+        offset = ofproto.OFP_HELLO_HEADER_SIZE
+        elems = []
+        while offset < msg.msg_len:
+            type_, length = struct.unpack_from(
+                ofproto.OFP_HELLO_ELEM_HEADER_PACK_STR, msg.buf, offset)
+
+            # better to register Hello Element classes but currently
+            # Only VerisonBitmap is supported so let's be simple.
+
+            if type_ == ofproto.OFPHET_VERSIONBITMAP:
+                elem = OFPHelloElemVersionBitmap.parser(msg.buf, offset)
+                elems.append(elem)
+
+            offset += length
+        msg.elements = elems
+        return msg
+
+
+class OFPHelloElemVersionBitmap(StringifyMixin):
+    """
+    Version bitmap Hello Element
+
+    ========== =========================================================
+    Attribute  Description
+    ========== =========================================================
+    versions   list of versions of OpenFlow protocol a device supports
+    ========== =========================================================
+    """
+
+    def __init__(self, versions, type_=None, length=None):
+        super(OFPHelloElemVersionBitmap, self).__init__()
+        self.type = ofproto.OFPHET_VERSIONBITMAP
+        self.length = None
+        self._bitmaps = None
+        self.versions = versions
+
+    @classmethod
+    def parser(cls, buf, offset):
+        type_, length = struct.unpack_from(
+            ofproto.OFP_HELLO_ELEM_VERSIONBITMAP_HEADER_PACK_STR,
+            buf, offset)
+        assert type_ == ofproto.OFPHET_VERSIONBITMAP
+
+        bitmaps_len = (length -
+                       ofproto.OFP_HELLO_ELEM_VERSIONBITMAP_HEADER_SIZE)
+        offset += ofproto.OFP_HELLO_ELEM_VERSIONBITMAP_HEADER_SIZE
+        bitmaps = []
+        while bitmaps_len >= 4:
+            bitmap = struct.unpack_from('!I', buf, offset)
+            bitmaps.append(bitmap[0])
+            offset += 4
+            bitmaps_len -= 4
+
+        versions = [i * 32 + shift
+                    for i, bitmap in enumerate(bitmaps)
+                    for shift in range(31) if bitmap & (1 << shift)]
+        elem = cls(versions)
+        elem.length = length
+        elem._bitmaps = bitmaps
+        return elem
+
+
+@_register_parser
+@_set_msg_type(ofproto.OFPT_ECHO_REQUEST)
+class OFPEchoRequest(MsgBase):
+    """
+    Echo request message
+
+    This message is handled by the Ryu framework, so the Ryu application
+    do not need to process this typically.
+
+    ========== =========================================================
+    Attribute  Description
+    ========== =========================================================
+    data       An arbitrary length data
+    ========== =========================================================
+
+    Example::
+
+        def send_echo_request(self, datapath, data):
+            ofp = datapath.ofproto
+            ofp_parser = datapath.ofproto_parser
+
+            req = ofp_parser.OFPEchoRequest(datapath, data)
+            datapath.send_msg(req)
+
+        @set_ev_cls(ofp_event.EventOFPEchoRequest,
+                    [HANDSHAKE_DISPATCHER, CONFIG_DISPATCHER, MAIN_DISPATCHER])
+        def echo_request_handler(self, ev):
+            self.logger.debug('OFPEchoRequest received: data=%s',
+                              utils.hex_array(ev.msg.data))
+    """
+
+    def __init__(self, datapath, data=None):
+        super(OFPEchoRequest, self).__init__(datapath)
+        self.data = data
+
+    @classmethod
+    def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+        msg = super(OFPEchoRequest, cls).parser(datapath, version, msg_type,
+                                                msg_len, xid, buf)
+        msg.data = msg.buf[ofproto.OFP_HEADER_SIZE:]
+        return msg
+
+    def _serialize_body(self):
+        if self.data is not None:
+            self.buf += self.data
+
+
+@_register_parser
+@_set_msg_type(ofproto.OFPT_ERROR)
+class OFPErrorMsg(MsgBase):
+    """
+    Error message
+
+    The switch notifies controller of problems by this message.
+
+    ========== =========================================================
+    Attribute  Description
+    ========== =========================================================
+    type       High level type of error
+    code       Details depending on the type
+    data       Variable length data depending on the type and code
+    ========== =========================================================
+
+    ``type`` attribute corresponds to ``type_`` parameter of __init__.
+
+    Types and codes are defined in ``ryu.ofproto.ofproto``.
+
+    ============================= ===========
+    Type                          Code
+    ============================= ===========
+    OFPET_HELLO_FAILED            OFPHFC_*
+    OFPET_BAD_REQUEST             OFPBRC_*
+    OFPET_BAD_ACTION              OFPBAC_*
+    OFPET_BAD_INSTRUCTION         OFPBIC_*
+    OFPET_BAD_MATCH               OFPBMC_*
+    OFPET_FLOW_MOD_FAILED         OFPFMFC_*
+    OFPET_GROUP_MOD_FAILED        OFPGMFC_*
+    OFPET_PORT_MOD_FAILED         OFPPMFC_*
+    OFPET_TABLE_MOD_FAILED        OFPTMFC_*
+    OFPET_QUEUE_OP_FAILED         OFPQOFC_*
+    OFPET_SWITCH_CONFIG_FAILED    OFPSCFC_*
+    OFPET_ROLE_REQUEST_FAILED     OFPRRFC_*
+    OFPET_METER_MOD_FAILED        OFPMMFC_*
+    OFPET_TABLE_FEATURES_FAILED   OFPTFFC_*
+    OFPET_EXPERIMENTER            N/A
+    ============================= ===========
+
+    If ``type == OFPET_EXPERIMENTER``, this message has also the following
+    attributes.
+
+    ============= ======================================================
+    Attribute     Description
+    ============= ======================================================
+    exp_type      Experimenter defined type
+    experimenter  Experimenter ID
+    ============= ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPErrorMsg,
+                    [HANDSHAKE_DISPATCHER, CONFIG_DISPATCHER, MAIN_DISPATCHER])
+        def error_msg_handler(self, ev):
+            msg = ev.msg
+
+            self.logger.debug('OFPErrorMsg received: type=0x%02x code=0x%02x '
+                              'message=%s',
+                              msg.type, msg.code, utils.hex_array(msg.data))
+    """
+
+    def __init__(self, datapath, type_=None, code=None, data=None, **kwargs):
+        super(OFPErrorMsg, self).__init__(datapath)
+        self.type = type_
+        self.code = code
+        if isinstance(data, six.string_types):
+            data = data.encode('ascii')
+        self.data = data
+        if self.type == ofproto.OFPET_EXPERIMENTER:
+            self.exp_type = kwargs.get('exp_type', None)
+            self.experimenter = kwargs.get('experimenter', None)
+
+    @classmethod
+    def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+        type_, = struct.unpack_from('!H', six.binary_type(buf),
+                                    ofproto.OFP_HEADER_SIZE)
+        msg = super(OFPErrorMsg, cls).parser(datapath, version, msg_type,
+                                             msg_len, xid, buf)
+        if type_ == ofproto.OFPET_EXPERIMENTER:
+            (msg.type, msg.exp_type, msg.experimenter,
+             msg.data) = cls.parse_experimenter_body(buf)
+        else:
+            (msg.type, msg.code,
+             msg.data) = cls.parse_body(buf)
+        return msg
+
+    @classmethod
+    def parse_body(cls, buf):
+        type_, code = struct.unpack_from(
+            ofproto.OFP_ERROR_MSG_PACK_STR, buf,
+            ofproto.OFP_HEADER_SIZE)
+        data = buf[ofproto.OFP_ERROR_MSG_SIZE:]
+        return type_, code, data
+
+    @classmethod
+    def parse_experimenter_body(cls, buf):
+        type_, exp_type, experimenter = struct.unpack_from(
+            ofproto.OFP_ERROR_EXPERIMENTER_MSG_PACK_STR, buf,
+            ofproto.OFP_HEADER_SIZE)
+        data = buf[ofproto.OFP_ERROR_EXPERIMENTER_MSG_SIZE:]
+        return type_, exp_type, experimenter, data
+
+    def _serialize_body(self):
+        assert self.data is not None
+        if self.type == ofproto.OFPET_EXPERIMENTER:
+            msg_pack_into(ofproto.OFP_ERROR_EXPERIMENTER_MSG_PACK_STR,
+                          self.buf, ofproto.OFP_HEADER_SIZE,
+                          self.type, self.exp_type, self.experimenter)
+            self.buf += self.data
+        else:
+            msg_pack_into(ofproto.OFP_ERROR_MSG_PACK_STR,
+                          self.buf, ofproto.OFP_HEADER_SIZE,
+                          self.type, self.code)
+            self.buf += self.data
+
+
+# For the backward compatibility
+def OFPErrorExperimenterMsg(datapath, type_=None, exp_type=None,
+                            experimenter=None, data=None):
+    msg = OFPErrorMsg(datapath, data=data)
+    msg.type = ofproto.OFPET_EXPERIMENTER
+    msg.exp_type = exp_type
+    msg.experimenter = experimenter
+    return msg
+
+
+@_register_parser
+@_set_msg_type(ofproto.OFPT_ECHO_REPLY)
+class OFPEchoReply(MsgBase):
+    """
+    Echo reply message
+
+    This message is handled by the Ryu framework, so the Ryu application
+    do not need to process this typically.
+
+    ========== =========================================================
+    Attribute  Description
+    ========== =========================================================
+    data       An arbitrary length data
+    ========== =========================================================
+
+    Example::
+
+        def send_echo_reply(self, datapath, data):
+            ofp_parser = datapath.ofproto_parser
+
+            reply = ofp_parser.OFPEchoReply(datapath, data)
+            datapath.send_msg(reply)
+
+        @set_ev_cls(ofp_event.EventOFPEchoReply,
+                    [HANDSHAKE_DISPATCHER, CONFIG_DISPATCHER, MAIN_DISPATCHER])
+        def echo_reply_handler(self, ev):
+            self.logger.debug('OFPEchoReply received: data=%s',
+                              utils.hex_array(ev.msg.data))
+    """
+
+    def __init__(self, datapath, data=None):
+        super(OFPEchoReply, self).__init__(datapath)
+        self.data = data
+
+    @classmethod
+    def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+        msg = super(OFPEchoReply, cls).parser(datapath, version, msg_type,
+                                              msg_len, xid, buf)
+        msg.data = msg.buf[ofproto.OFP_HEADER_SIZE:]
+        return msg
+
+    def _serialize_body(self):
+        assert self.data is not None
+        self.buf += self.data
+
+
+@_set_msg_type(ofproto.OFPT_FEATURES_REQUEST)
+class OFPFeaturesRequest(MsgBase):
+    """
+    Features request message
+
+    The controller sends a feature request to the switch upon session
+    establishment.
+
+    This message is handled by the Ryu framework, so the Ryu application
+    do not need to process this typically.
+
+    Example::
+
+        def send_features_request(self, datapath):
+            ofp_parser = datapath.ofproto_parser
+
+            req = ofp_parser.OFPFeaturesRequest(datapath)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath):
+        super(OFPFeaturesRequest, self).__init__(datapath)
+
+
+@_register_parser
+@_set_msg_type(ofproto.OFPT_EXPERIMENTER)
+class OFPExperimenter(MsgBase):
+    """
+    Experimenter extension message
+
+    ============= =========================================================
+    Attribute     Description
+    ============= =========================================================
+    experimenter  Experimenter ID
+    exp_type      Experimenter defined
+    data          Experimenter defined arbitrary additional data
+    ============= =========================================================
+    """
+
+    def __init__(self, datapath, experimenter=None, exp_type=None, data=None):
+        super(OFPExperimenter, self).__init__(datapath)
+        self.experimenter = experimenter
+        self.exp_type = exp_type
+        self.data = data
+
+    @classmethod
+    def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+        msg = super(OFPExperimenter, cls).parser(datapath, version,
+                                                 msg_type, msg_len,
+                                                 xid, buf)
+        (msg.experimenter, msg.exp_type) = struct.unpack_from(
+            ofproto.OFP_EXPERIMENTER_HEADER_PACK_STR, msg.buf,
+            ofproto.OFP_HEADER_SIZE)
+        msg.data = msg.buf[ofproto.OFP_EXPERIMENTER_HEADER_SIZE:]
+
+        return msg
+
+    def _serialize_body(self):
+        assert self.data is not None
+        msg_pack_into(ofproto.OFP_EXPERIMENTER_HEADER_PACK_STR,
+                      self.buf, ofproto.OFP_HEADER_SIZE,
+                      self.experimenter, self.exp_type)
+        self.buf += self.data
+
+
+@_register_parser
+@_set_msg_type(ofproto.OFPT_FEATURES_REPLY)
+class OFPSwitchFeatures(MsgBase):
+    """
+    Features reply message
+
+    The switch responds with a features reply message to a features
+    request.
+
+    This message is handled by the Ryu framework, so the Ryu application
+    do not need to process this typically.
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
+        def switch_features_handler(self, ev):
+            msg = ev.msg
+
+            self.logger.debug('OFPSwitchFeatures received: '
+                              'datapath_id=0x%016x n_buffers=%d '
+                              'n_tables=%d auxiliary_id=%d '
+                              'capabilities=0x%08x',
+                              msg.datapath_id, msg.n_buffers, msg.n_tables,
+                              msg.auxiliary_id, msg.capabilities)
+    """
+
+    def __init__(self, datapath, datapath_id=None, n_buffers=None,
+                 n_tables=None, auxiliary_id=None, capabilities=None):
+        super(OFPSwitchFeatures, self).__init__(datapath)
+        self.datapath_id = datapath_id
+        self.n_buffers = n_buffers
+        self.n_tables = n_tables
+        self.auxiliary_id = auxiliary_id
+        self.capabilities = capabilities
+
+    @classmethod
+    def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+        msg = super(OFPSwitchFeatures, cls).parser(datapath, version, msg_type,
+                                                   msg_len, xid, buf)
+        (msg.datapath_id,
+         msg.n_buffers,
+         msg.n_tables,
+         msg.auxiliary_id,
+         msg.capabilities,
+         msg._reserved) = struct.unpack_from(
+            ofproto.OFP_SWITCH_FEATURES_PACK_STR, msg.buf,
+            ofproto.OFP_HEADER_SIZE)
+        return msg
+
+
+@_set_msg_type(ofproto.OFPT_GET_CONFIG_REQUEST)
+class OFPGetConfigRequest(MsgBase):
+    """
+    Get config request message
+
+    The controller sends a get config request to query configuration
+    parameters in the switch.
+
+    Example::
+
+        def send_get_config_request(self, datapath):
+            ofp_parser = datapath.ofproto_parser
+
+            req = ofp_parser.OFPGetConfigRequest(datapath)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath):
+        super(OFPGetConfigRequest, self).__init__(datapath)
+
+
+@_register_parser
+@_set_msg_type(ofproto.OFPT_GET_CONFIG_REPLY)
+class OFPGetConfigReply(MsgBase):
+    """
+    Get config reply message
+
+    The switch responds to a configuration request with a get config reply
+    message.
+
+    ============= =========================================================
+    Attribute     Description
+    ============= =========================================================
+    flags         Bitmap of the following flags.
+
+                  | OFPC_FRAG_NORMAL
+                  | OFPC_FRAG_DROP
+                  | OFPC_FRAG_REASM
+    miss_send_len Max bytes of new flow that datapath should send to the
+                  controller
+    ============= =========================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPGetConfigReply, MAIN_DISPATCHER)
+        def get_config_reply_handler(self, ev):
+            msg = ev.msg
+            dp = msg.datapath
+            ofp = dp.ofproto
+            flags = []
+
+            if msg.flags & ofp.OFPC_FRAG_NORMAL:
+                flags.append('NORMAL')
+            if msg.flags & ofp.OFPC_FRAG_DROP:
+                flags.append('DROP')
+            if msg.flags & ofp.OFPC_FRAG_REASM:
+                flags.append('REASM')
+            self.logger.debug('OFPGetConfigReply received: '
+                              'flags=%s miss_send_len=%d',
+                              ','.join(flags), msg.miss_send_len)
+    """
+
+    def __init__(self, datapath, flags=None, miss_send_len=None):
+        super(OFPGetConfigReply, self).__init__(datapath)
+        self.flags = flags
+        self.miss_send_len = miss_send_len
+
+    @classmethod
+    def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+        msg = super(OFPGetConfigReply, cls).parser(datapath, version, msg_type,
+                                                   msg_len, xid, buf)
+        msg.flags, msg.miss_send_len = struct.unpack_from(
+            ofproto.OFP_SWITCH_CONFIG_PACK_STR, msg.buf,
+            ofproto.OFP_HEADER_SIZE)
+        return msg
+
+
+@_set_msg_type(ofproto.OFPT_SET_CONFIG)
+class OFPSetConfig(MsgBase):
+    """
+    Set config request message
+
+    The controller sends a set config request message to set configuraion
+    parameters.
+
+    ============= =========================================================
+    Attribute     Description
+    ============= =========================================================
+    flags         Bitmap of the following flags.
+
+                  | OFPC_FRAG_NORMAL
+                  | OFPC_FRAG_DROP
+                  | OFPC_FRAG_REASM
+    miss_send_len Max bytes of new flow that datapath should send to the
+                  controller
+    ============= =========================================================
+
+    Example::
+
+        def send_set_config(self, datapath):
+            ofp = datapath.ofproto
+            ofp_parser = datapath.ofproto_parser
+
+            req = ofp_parser.OFPSetConfig(datapath, ofp.OFPC_FRAG_NORMAL, 256)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, flags=0, miss_send_len=0):
+        super(OFPSetConfig, self).__init__(datapath)
+        self.flags = flags
+        self.miss_send_len = miss_send_len
+
+    def _serialize_body(self):
+        assert self.flags is not None
+        assert self.miss_send_len is not None
+        msg_pack_into(ofproto.OFP_SWITCH_CONFIG_PACK_STR,
+                      self.buf, ofproto.OFP_HEADER_SIZE,
+                      self.flags, self.miss_send_len)
+
+
+class OFPMatch(StringifyMixin):
+    """
+    Flow Match Structure
+
+    This class is implementation of the flow match structure having
+    compose/query API.
+
+    You can define the flow match by the keyword arguments.
+    The following arguments are available.
+
+    ================ =============== ==================================
+    Argument         Value           Description
+    ================ =============== ==================================
+    in_port          Integer 32bit   Switch input port
+    in_phy_port      Integer 32bit   Switch physical input port
+    metadata         Integer 64bit   Metadata passed between tables
+    eth_dst          MAC address     Ethernet destination address
+    eth_src          MAC address     Ethernet source address
+    eth_type         Integer 16bit   Ethernet frame type
+    vlan_vid         Integer 16bit   VLAN id
+    vlan_pcp         Integer 8bit    VLAN priority
+    ip_dscp          Integer 8bit    IP DSCP (6 bits in ToS field)
+    ip_ecn           Integer 8bit    IP ECN (2 bits in ToS field)
+    ip_proto         Integer 8bit    IP protocol
+    ipv4_src         IPv4 address    IPv4 source address
+    ipv4_dst         IPv4 address    IPv4 destination address
+    tcp_src          Integer 16bit   TCP source port
+    tcp_dst          Integer 16bit   TCP destination port
+    udp_src          Integer 16bit   UDP source port
+    udp_dst          Integer 16bit   UDP destination port
+    sctp_src         Integer 16bit   SCTP source port
+    sctp_dst         Integer 16bit   SCTP destination port
+    icmpv4_type      Integer 8bit    ICMP type
+    icmpv4_code      Integer 8bit    ICMP code
+    arp_op           Integer 16bit   ARP opcode
+    arp_spa          IPv4 address    ARP source IPv4 address
+    arp_tpa          IPv4 address    ARP target IPv4 address
+    arp_sha          MAC address     ARP source hardware address
+    arp_tha          MAC address     ARP target hardware address
+    ipv6_src         IPv6 address    IPv6 source address
+    ipv6_dst         IPv6 address    IPv6 destination address
+    ipv6_flabel      Integer 32bit   IPv6 Flow Label
+    icmpv6_type      Integer 8bit    ICMPv6 type
+    icmpv6_code      Integer 8bit    ICMPv6 code
+    ipv6_nd_target   IPv6 address    Target address for ND
+    ipv6_nd_sll      MAC address     Source link-layer for ND
+    ipv6_nd_tll      MAC address     Target link-layer for ND
+    mpls_label       Integer 32bit   MPLS label
+    mpls_tc          Integer 8bit    MPLS TC
+    mpls_bos         Integer 8bit    MPLS BoS bit
+    pbb_isid         Integer 24bit   PBB I-SID
+    tunnel_id        Integer 64bit   Logical Port Metadata
+    ipv6_exthdr      Integer 16bit   IPv6 Extension Header pseudo-field
+    pbb_uca          Integer 8bit    PBB UCA header field
+    tcp_flags        Integer 16bit   TCP flags
+                                     (EXT-109 ONF Extension)
+    actset_output    Integer 32bit   Output port from action set metadata
+                                     (EXT-233 ONF Extension)
+    ================ =============== ==================================
+
+    Example::
+
+        >>> # compose
+        >>> match = parser.OFPMatch(
+        ...     in_port=1,
+        ...     eth_type=0x86dd,
+        ...     ipv6_src=('2001:db8:bd05:1d2:288a:1fc0:1:10ee',
+        ...               'ffff:ffff:ffff:ffff::'),
+        ...     ipv6_dst='2001:db8:bd05:1d2:288a:1fc0:1:10ee')
+        >>> # query
+        >>> if 'ipv6_src' in match:
+        ...     print match['ipv6_src']
+        ...
+        ('2001:db8:bd05:1d2:288a:1fc0:1:10ee', 'ffff:ffff:ffff:ffff::')
+
+    .. Note::
+
+        For the list of the supported Nicira experimenter matches,
+        please refer to :ref:`ryu.ofproto.nx_match <nx_match_structures>`.
+
+    .. Note::
+
+        For VLAN id match field, special values are defined in OpenFlow Spec.
+
+        1) Packets with and without a VLAN tag
+
+            - Example::
+
+                match = parser.OFPMatch()
+
+            - Packet Matching
+
+                ====================== =====
+                non-VLAN-tagged        MATCH
+                VLAN-tagged(vlan_id=3) MATCH
+                VLAN-tagged(vlan_id=5) MATCH
+                ====================== =====
+
+        2) Only packets without a VLAN tag
+
+            - Example::
+
+                match = parser.OFPMatch(vlan_vid=0x0000)
+
+            - Packet Matching
+
+                ====================== =====
+                non-VLAN-tagged        MATCH
+                VLAN-tagged(vlan_id=3)   x
+                VLAN-tagged(vlan_id=5)   x
+                ====================== =====
+
+        3) Only packets with a VLAN tag regardless of its value
+
+            - Example::
+
+                match = parser.OFPMatch(vlan_vid=(0x1000, 0x1000))
+
+            - Packet Matching
+
+                ====================== =====
+                non-VLAN-tagged          x
+                VLAN-tagged(vlan_id=3) MATCH
+                VLAN-tagged(vlan_id=5) MATCH
+                ====================== =====
+
+        4) Only packets with VLAN tag and VID equal
+
+            - Example::
+
+                match = parser.OFPMatch(vlan_vid=(0x1000 | 3))
+
+            - Packet Matching
+
+                ====================== =====
+                non-VLAN-tagged          x
+                VLAN-tagged(vlan_id=3) MATCH
+                VLAN-tagged(vlan_id=5)   x
+                ====================== =====
+    """
+
+    def __init__(self, type_=None, length=None, _ordered_fields=None,
+                 **kwargs):
+        super(OFPMatch, self).__init__()
+        self.type = ofproto.OFPMT_OXM
+        self.length = length
+
+        if _ordered_fields is not None:
+            assert not kwargs
+            self._fields2 = _ordered_fields
+        else:
+            kwargs = dict(ofproto.oxm_normalize_user(k, v) for
+                          (k, v) in kwargs.items())
+            fields = [ofproto.oxm_from_user(k, v) for (k, v)
+                      in kwargs.items()]
+            # assumption: sorting by OXM type values makes fields
+            # meet ordering requirements (eg. eth_type before ipv4_src)
+            fields.sort(
+                key=lambda x: x[0][0] if isinstance(x[0], tuple) else x[0])
+            self._fields2 = [ofproto.oxm_to_user(n, v, m) for (n, v, m)
+                             in fields]
+
+    @classmethod
+    def parser(cls, buf, offset):
+        """
+        Returns an object which is generated from a buffer including the
+        expression of the wire protocol of the flow match.
+        """
+        match = OFPMatch()
+        type_, length = struct.unpack_from('!HH', buf, offset)
+
+        match.type = type_
+        match.length = length
+
+        # ofp_match adjustment
+        offset += 4
+        length -= 4
+
+        fields = []
+        while length > 0:
+            n, value, mask, field_len = ofproto.oxm_parse(buf, offset)
+            k, uv = ofproto.oxm_to_user(n, value, mask)
+            fields.append((k, uv))
+            offset += field_len
+            length -= field_len
+        match._fields2 = fields
+        return match
+
+    def serialize(self, buf, offset):
+        """
+        Outputs the expression of the wire protocol of the flow match into
+        the buf.
+        Returns the output length.
+        """
+        fields = [ofproto.oxm_from_user(k, uv) for (k, uv)
+                  in self._fields2]
+
+        hdr_pack_str = '!HH'
+        field_offset = offset + struct.calcsize(hdr_pack_str)
+        for (n, value, mask) in fields:
+            field_offset += ofproto.oxm_serialize(n, value, mask, buf,
+                                                  field_offset)
+
+        length = field_offset - offset
+        msg_pack_into(hdr_pack_str, buf, offset, ofproto.OFPMT_OXM, length)
+        self.length = length
+
+        pad_len = utils.round_up(length, 8) - length
+        msg_pack_into("%dx" % pad_len, buf, field_offset)
+
+        return length + pad_len
+
+    def __getitem__(self, key):
+        return dict(self._fields2)[key]
+
+    def __contains__(self, key):
+        return key in dict(self._fields2)
+
+    def iteritems(self):
+        return iter(dict(self._fields2).items())
+
+    def items(self):
+        return self._fields2
+
+    def get(self, key, default=None):
+        return dict(self._fields2).get(key, default)
+
+    def stringify_attrs(self):
+        yield "oxm_fields", dict(self._fields2)
+
+    def to_jsondict(self):
+        """
+        Returns a dict expressing the flow match.
+        """
+        body = {"oxm_fields": [ofproto.oxm_to_jsondict(k, uv) for k, uv
+                               in self._fields2],
+                "length": self.length,
+                "type": self.type}
+        return {self.__class__.__name__: body}
+
+    @classmethod
+    def from_jsondict(cls, dict_):
+        """
+        Returns an object which is generated from a dict.
+
+        Exception raises:
+        KeyError -- Unknown match field is defined in dict
+        """
+        fields = [ofproto.oxm_from_jsondict(f) for f
+                  in dict_['oxm_fields']]
+        return OFPMatch(_ordered_fields=fields)
+
+
+class OFPPropUnknown(StringifyMixin):
+    def __init__(self, type_=None, length=None, buf=None):
+        self.buf = buf
+
+    @classmethod
+    def parser(cls, buf):
+        return cls(buf=buf)
+
+
+class OFPPropBase(StringifyMixin):
+    _PACK_STR = '!HH'
+    # _TYPES = {} must be an attribute of subclass
+
+    def __init__(self, type_, length=None):
+        self.type = type_
+        self.length = length
+
+    @classmethod
+    def register_type(cls, type_):
+        def _register_type(subcls):
+            cls._TYPES[type_] = subcls
+            return subcls
+        return _register_type
+
+    @classmethod
+    def parse(cls, buf):
+        (type_, length) = struct.unpack_from(cls._PACK_STR, buf, 0)
+        rest = buf[utils.round_up(length, 8):]
+        try:
+            subcls = cls._TYPES[type_]
+        except KeyError:
+            subcls = OFPPropUnknown
+        prop = subcls.parser(buf)
+        prop.type = type_
+        prop.length = length
+        return prop, rest
+
+    @classmethod
+    def get_rest(cls, buf):
+        (type_, length) = struct.unpack_from(cls._PACK_STR, buf, 0)
+        offset = struct.calcsize(cls._PACK_STR)
+        return buf[offset:length]
+
+    def serialize(self):
+        # Body
+        # serialize_body should be implemented by subclass
+        body = bytearray()
+        body += self.serialize_body()
+
+        # fixup
+        self.length = len(body) + struct.calcsize(self._PACK_STR)
+
+        # Header
+        buf = bytearray()
+        msg_pack_into(self._PACK_STR, buf, 0, self.type, self.length)
+        buf += body
+
+        # Pad
+        pad_len = utils.round_up(self.length, 8) - self.length
+        msg_pack_into("%dx" % pad_len, buf, len(buf))
+
+        return buf
+
+
+class OFPPropCommonExperimenter4ByteData(StringifyMixin):
+    _PACK_STR = '!HHII'
+    _EXPERIMENTER_DATA_PACK_STR = '!I'
+    _EXPERIMENTER_DATA_SIZE = 4
+
+    def __init__(self, type_=None, length=None, experimenter=None,
+                 exp_type=None, data=bytearray()):
+        self.type = type_
+        self.length = length
+        self.experimenter = experimenter
+        self.exp_type = exp_type
+        self.data = data
+
+    @classmethod
+    def parser(cls, buf):
+        (type_, length, experimenter, exp_type) = struct.unpack_from(
+            ofproto.OFP_PROP_EXPERIMENTER_PACK_STR, buf, 0)
+
+        rest = buf[ofproto.OFP_PROP_EXPERIMENTER_SIZE:length]
+        data = []
+        while rest:
+            (d,) = struct.unpack_from(
+                cls._EXPERIMENTER_DATA_PACK_STR, rest, 0)
+            data.append(d)
+            rest = rest[cls._EXPERIMENTER_DATA_SIZE:]
+
+        return cls(type_, length, experimenter, exp_type, data)
+
+    def serialize(self):
+        offset = 0
+        bin_data = bytearray()
+        for d in self.data:
+            msg_pack_into(self._EXPERIMENTER_DATA_PACK_STR,
+                          bin_data, offset, d)
+            offset += self._EXPERIMENTER_DATA_SIZE
+
+        # fixup
+        self.length = struct.calcsize(self._PACK_STR)
+        self.length += len(bin_data)
+
+        buf = bytearray()
+        msg_pack_into(self._PACK_STR, buf,
+                      0, self.type, self.length, self.experimenter,
+                      self.exp_type)
+        buf += bin_data
+
+        # Pad
+        pad_len = utils.round_up(self.length, 8) - self.length
+        msg_pack_into("%dx" % pad_len, buf, len(buf))
+
+        return buf
+
+
+class OFPPortDescProp(OFPPropBase):
+    _TYPES = {}
+
+
+@OFPPortDescProp.register_type(ofproto.OFPPDPT_ETHERNET)
+class OFPPortDescPropEthernet(OFPPortDescProp):
+    def __init__(self, type_=None, length=None, curr=None, advertised=None,
+                 supported=None, peer=None, curr_speed=None, max_speed=None):
+        self.type = type_
+        self.length = length
+        self.curr = curr
+        self.advertised = advertised
+        self.supported = supported
+        self.peer = peer
+        self.curr_speed = curr_speed
+        self.max_speed = max_speed
+
+    @classmethod
+    def parser(cls, buf):
+        ether = cls()
+        (ether.type, ether.length, ether.curr,
+         ether.advertised, ether.supported,
+         ether.peer, ether.curr_speed, ether.max_speed) = struct.unpack_from(
+            ofproto.OFP_PORT_DESC_PROP_ETHERNET_PACK_STR, buf, 0)
+        return ether
+
+
+@OFPPortDescProp.register_type(ofproto.OFPPDPT_OPTICAL)
+class OFPPortDescPropOptical(OFPPortDescProp):
+    def __init__(self, type_=None, length=None, supported=None,
+                 tx_min_freq_lmda=None, tx_max_freq_lmda=None,
+                 tx_grid_freq_lmda=None, rx_min_freq_lmda=None,
+                 rx_max_freq_lmda=None, rx_grid_freq_lmda=None,
+                 tx_pwr_min=None, tx_pwr_max=None):
+        self.type = type_
+        self.length = length
+        self.supported = supported
+        self.tx_min_freq_lmda = tx_min_freq_lmda
+        self.tx_max_freq_lmda = tx_max_freq_lmda
+        self.tx_grid_freq_lmda = tx_grid_freq_lmda
+        self.rx_min_freq_lmda = rx_min_freq_lmda
+        self.rx_max_freq_lmda = rx_max_freq_lmda
+        self.rx_grid_freq_lmda = rx_grid_freq_lmda
+        self.tx_pwr_min = tx_pwr_min
+        self.tx_pwr_max = tx_pwr_max
+
+    @classmethod
+    def parser(cls, buf):
+        optical = cls()
+        (optical.type, optical.length, optical.supported,
+         optical.tx_min_freq_lmda, optical.tx_max_freq_lmda,
+         optical.tx_grid_freq_lmda, optical.rx_min_freq_lmda,
+         optical.rx_max_freq_lmda, optical.rx_grid_freq_lmda,
+         optical.tx_pwr_min, optical.tx_pwr_max) = struct.unpack_from(
+            ofproto.OFP_PORT_DESC_PROP_OPTICAL_PACK_STR, buf, 0)
+        return optical
+
+
+@OFPPortDescProp.register_type(ofproto.OFPPDPT_EXPERIMENTER)
+class OFPPortDescPropExperimenter(OFPPropCommonExperimenter4ByteData):
+    pass
+
+
+class OFPTableModProp(OFPPropBase):
+    _TYPES = {}
+
+
+@OFPTableModProp.register_type(ofproto.OFPTMPT_EVICTION)
+class OFPTableModPropEviction(OFPTableModProp):
+    def __init__(self, type_=None, length=None, flags=None):
+        self.type = type_
+        self.length = length
+        self.flags = flags
+
+    @classmethod
+    def parser(cls, buf):
+        eviction = cls()
+        (eviction.type, eviction.length, eviction.flags) = struct.unpack_from(
+            ofproto.OFP_TABLE_MOD_PROP_EVICTION_PACK_STR, buf, 0)
+        return eviction
+
+    def serialize(self):
+        # fixup
+        self.length = ofproto.OFP_TABLE_MOD_PROP_EVICTION_SIZE
+
+        buf = bytearray()
+        msg_pack_into(ofproto.OFP_TABLE_MOD_PROP_EVICTION_PACK_STR, buf, 0,
+                      self.type, self.length, self.flags)
+        return buf
+
+
+@OFPTableModProp.register_type(ofproto.OFPTMPT_VACANCY)
+class OFPTableModPropVacancy(OFPTableModProp):
+    def __init__(self, type_=None, length=None, vacancy_down=None,
+                 vacancy_up=None, vacancy=None):
+        self.type = type_
+        self.length = length
+        self.vacancy_down = vacancy_down
+        self.vacancy_up = vacancy_up
+        self.vacancy = vacancy
+
+    @classmethod
+    def parser(cls, buf):
+        vacancy = cls()
+        (vacancy.type, vacancy.length, vacancy.vacancy_down,
+         vacancy.vacancy_up, vacancy.vacancy) = struct.unpack_from(
+            ofproto.OFP_TABLE_MOD_PROP_VACANCY_PACK_STR, buf, 0)
+        return vacancy
+
+    def serialize(self):
+        # fixup
+        self.length = ofproto.OFP_TABLE_MOD_PROP_VACANCY_SIZE
+
+        buf = bytearray()
+        msg_pack_into(ofproto.OFP_TABLE_MOD_PROP_VACANCY_PACK_STR, buf, 0,
+                      self.type, self.length, self.vacancy_down,
+                      self.vacancy_up, self.vacancy)
+        return buf
+
+
+@OFPTableModProp.register_type(ofproto.OFPTMPT_EXPERIMENTER)
+class OFPTableModPropExperimenter(OFPPropCommonExperimenter4ByteData):
+    pass
+
+
+class OFPQueueDescProp(OFPPropBase):
+    _TYPES = {}
+
+
+@OFPQueueDescProp.register_type(ofproto.OFPQDPT_MIN_RATE)
+class OFPQueueDescPropMinRate(OFPQueueDescProp):
+    def __init__(self, type_=None, length=None, rate=None):
+        self.type = type_
+        self.length = length
+        self.rate = rate
+
+    @classmethod
+    def parser(cls, buf):
+        minrate = cls()
+        (minrate.type, minrate.length, minrate.rate) = struct.unpack_from(
+            ofproto.OFP_QUEUE_DESC_PROP_MIN_RATE_PACK_STR, buf, 0)
+        return minrate
+
+
+@OFPQueueDescProp.register_type(ofproto.OFPQDPT_MAX_RATE)
+class OFPQueueDescPropMaxRate(OFPQueueDescProp):
+    def __init__(self, type_=None, length=None, rate=None):
+        self.type = type_
+        self.length = length
+        self.rate = rate
+
+    @classmethod
+    def parser(cls, buf):
+        maxrate = cls()
+        (maxrate.type, maxrate.length, maxrate.rate) = struct.unpack_from(
+            ofproto.OFP_QUEUE_DESC_PROP_MAX_RATE_PACK_STR, buf, 0)
+        return maxrate
+
+
+@OFPQueueDescProp.register_type(ofproto.OFPQDPT_EXPERIMENTER)
+class OFPQueueDescPropExperimenter(OFPPropCommonExperimenter4ByteData):
+    pass
+
+
+class OFPRoleProp(OFPPropBase):
+    _TYPES = {}
+
+
+@OFPRoleProp.register_type(ofproto.OFPRPT_EXPERIMENTER)
+class OFPRolePropExperimenter(OFPPropCommonExperimenter4ByteData):
+    pass
+
+
+class OFPBundleProp(OFPPropBase):
+    _TYPES = {}
+
+
+@OFPBundleProp.register_type(ofproto.OFPRPT_EXPERIMENTER)
+class OFPBundlePropExperimenter(OFPPropCommonExperimenter4ByteData):
+    pass
+
+
+@_register_parser
+@_set_msg_type(ofproto.OFPT_PACKET_IN)
+class OFPPacketIn(MsgBase):
+    """
+    Packet-In message
+
+    The switch sends the packet that received to the controller by this
+    message.
+
+    ============= =========================================================
+    Attribute     Description
+    ============= =========================================================
+    buffer_id     ID assigned by datapath
+    total_len     Full length of frame
+    reason        Reason packet is being sent.
+
+                  | OFPR_TABLE_MISS
+                  | OFPR_APPLY_ACTION
+                  | OFPR_INVALID_TTL
+                  | OFPR_ACTION_SET
+                  | OFPR_GROUP
+                  | OFPR_PACKET_OUT
+    table_id      ID of the table that was looked up
+    cookie        Cookie of the flow entry that was looked up
+    match         Instance of ``OFPMatch``
+    data          Ethernet frame
+    ============= =========================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
+        def packet_in_handler(self, ev):
+            msg = ev.msg
+            dp = msg.datapath
+            ofp = dp.ofproto
+
+            if msg.reason == ofp.TABLE_MISS:
+                reason = 'TABLE MISS'
+            elif msg.reason == ofp.OFPR_APPLY_ACTION:
+                reason = 'APPLY ACTION'
+            elif msg.reason == ofp.OFPR_INVALID_TTL:
+                reason = 'INVALID TTL'
+            elif msg.reason == ofp.OFPR_ACTION_SET:
+                reason = 'ACTION SET'
+            elif msg.reason == ofp.OFPR_GROUP:
+                reason = 'GROUP'
+            elif msg.reason == ofp.OFPR_PACKET_OUT:
+                reason = 'PACKET OUT'
+            else:
+                reason = 'unknown'
+
+            self.logger.debug('OFPPacketIn received: '
+                              'buffer_id=%x total_len=%d reason=%s '
+                              'table_id=%d cookie=%d match=%s data=%s',
+                              msg.buffer_id, msg.total_len, reason,
+                              msg.table_id, msg.cookie, msg.match,
+                              utils.hex_array(msg.data))
+    """
+
+    def __init__(self, datapath, buffer_id=None, total_len=None, reason=None,
+                 table_id=None, cookie=None, match=None, data=None):
+        super(OFPPacketIn, self).__init__(datapath)
+        self.buffer_id = buffer_id
+        self.total_len = total_len
+        self.reason = reason
+        self.table_id = table_id
+        self.cookie = cookie
+        self.match = match
+        self.data = data
+
+    @classmethod
+    def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+        msg = super(OFPPacketIn, cls).parser(datapath, version, msg_type,
+                                             msg_len, xid, buf)
+        (msg.buffer_id, msg.total_len, msg.reason,
+         msg.table_id, msg.cookie) = struct.unpack_from(
+            ofproto.OFP_PACKET_IN_PACK_STR,
+            msg.buf, ofproto.OFP_HEADER_SIZE)
+
+        msg.match = OFPMatch.parser(msg.buf, ofproto.OFP_PACKET_IN_SIZE -
+                                    ofproto.OFP_MATCH_SIZE)
+
+        match_len = utils.round_up(msg.match.length, 8)
+        msg.data = msg.buf[(ofproto.OFP_PACKET_IN_SIZE -
+                            ofproto.OFP_MATCH_SIZE + match_len + 2):]
+
+        if msg.total_len < len(msg.data):
+            # discard padding for 8-byte alignment of OFP packet
+            msg.data = msg.data[:msg.total_len]
+
+        return msg
+
+
+@_register_parser
+@_set_msg_type(ofproto.OFPT_FLOW_REMOVED)
+class OFPFlowRemoved(MsgBase):
+    """
+    Flow removed message
+
+    When flow entries time out or are deleted, the switch notifies controller
+    with this message.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    cookie           Opaque controller-issued identifier
+    priority         Priority level of flow entry
+    reason           One of the following values.
+
+                     | OFPRR_IDLE_TIMEOUT
+                     | OFPRR_HARD_TIMEOUT
+                     | OFPRR_DELETE
+                     | OFPRR_GROUP_DELETE
+                     | OFPRR_METER_DELETE
+                     | OFPRR_EVICTION
+    table_id         ID of the table
+    duration_sec     Time flow was alive in seconds
+    duration_nsec    Time flow was alive in nanoseconds beyond duration_sec
+    idle_timeout     Idle timeout from original flow mod
+    hard_timeout     Hard timeout from original flow mod
+    packet_count     Number of packets that was associated with the flow
+    byte_count       Number of bytes that was associated with the flow
+    match            Instance of ``OFPMatch``
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPFlowRemoved, MAIN_DISPATCHER)
+        def flow_removed_handler(self, ev):
+            msg = ev.msg
+            dp = msg.datapath
+            ofp = dp.ofproto
+
+            if msg.reason == ofp.OFPRR_IDLE_TIMEOUT:
+                reason = 'IDLE TIMEOUT'
+            elif msg.reason == ofp.OFPRR_HARD_TIMEOUT:
+                reason = 'HARD TIMEOUT'
+            elif msg.reason == ofp.OFPRR_DELETE:
+                reason = 'DELETE'
+            elif msg.reason == ofp.OFPRR_GROUP_DELETE:
+                reason = 'GROUP DELETE'
+            else:
+                reason = 'unknown'
+
+            self.logger.debug('OFPFlowRemoved received: '
+                              'cookie=%d priority=%d reason=%s table_id=%d '
+                              'duration_sec=%d duration_nsec=%d '
+                              'idle_timeout=%d hard_timeout=%d '
+                              'packet_count=%d byte_count=%d match.fields=%s',
+                              msg.cookie, msg.priority, reason, msg.table_id,
+                              msg.duration_sec, msg.duration_nsec,
+                              msg.idle_timeout, msg.hard_timeout,
+                              msg.packet_count, msg.byte_count, msg.match)
+    """
+
+    def __init__(self, datapath, 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):
+        super(OFPFlowRemoved, self).__init__(datapath)
+        self.cookie = cookie
+        self.priority = priority
+        self.reason = reason
+        self.table_id = table_id
+        self.duration_sec = duration_sec
+        self.duration_nsec = duration_nsec
+        self.idle_timeout = idle_timeout
+        self.hard_timeout = hard_timeout
+        self.packet_count = packet_count
+        self.byte_count = byte_count
+        self.match = match
+
+    @classmethod
+    def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+        msg = super(OFPFlowRemoved, cls).parser(datapath, version, msg_type,
+                                                msg_len, xid, buf)
+
+        (msg.cookie, msg.priority, msg.reason,
+         msg.table_id, msg.duration_sec, msg.duration_nsec,
+         msg.idle_timeout, msg.hard_timeout, msg.packet_count,
+         msg.byte_count) = struct.unpack_from(
+            ofproto.OFP_FLOW_REMOVED_PACK_STR0,
+            msg.buf, ofproto.OFP_HEADER_SIZE)
+
+        offset = (ofproto.OFP_FLOW_REMOVED_SIZE - ofproto.OFP_MATCH_SIZE)
+
+        msg.match = OFPMatch.parser(msg.buf, offset)
+
+        return msg
+
+
+class OFPPort(StringifyMixin):
+
+    """
+    Description of a port
+
+    ========== =========================================================
+    Attribute  Description
+    ========== =========================================================
+    port_no    Port number and it uniquely identifies a port within
+               a switch.
+    length     Length of ofp_port (excluding padding).
+    hw_addr    MAC address for the port.
+    name       Null-terminated string containing a human-readable name
+               for the interface.
+    config     Bitmap of port configration flags.
+
+               | OFPPC_PORT_DOWN
+               | OFPPC_NO_RECV
+               | OFPPC_NO_FWD
+               | OFPPC_NO_PACKET_IN
+    state      Bitmap of port state flags.
+
+               | OFPPS_LINK_DOWN
+               | OFPPS_BLOCKED
+               | OFPPS_LIVE
+    properties List of ``OFPPortDescProp`` subclass instance
+    ========== =========================================================
+    """
+
+    _TYPE = {
+        'ascii': [
+            'hw_addr',
+        ],
+        'utf-8': [
+            # OF spec is unclear about the encoding of name.
+            # we assumes UTF-8, which is used by OVS.
+            'name',
+        ]
+    }
+
+    def __init__(self, port_no=None, length=None, hw_addr=None, name=None,
+                 config=None, state=None, properties=None):
+        super(OFPPort, self).__init__()
+        self.port_no = port_no
+        self.length = length
+        self.hw_addr = hw_addr
+        self.name = name
+        self.config = config
+        self.state = state
+        self.properties = properties
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (port_no, length, hw_addr, name, config, state) = struct.unpack_from(
+            ofproto.OFP_PORT_PACK_STR, buf, offset)
+        hw_addr = addrconv.mac.bin_to_text(hw_addr)
+        name = name.rstrip(b'\0')
+        props = []
+        rest = buf[offset + ofproto.OFP_PORT_SIZE:offset + length]
+        while rest:
+            p, rest = OFPPortDescProp.parse(rest)
+            props.append(p)
+        ofpport = cls(port_no, length, hw_addr, name, config, state, props)
+        return ofpport
+
+
+class OFPTableDesc(StringifyMixin):
+    def __init__(self, length=None, table_id=None, config=None,
+                 properties=None):
+        super(OFPTableDesc, self).__init__()
+        self.table_id = table_id
+        self.length = length
+        self.config = config
+        self.properties = properties
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (length, table_id, config) = struct.unpack_from(
+            ofproto.OFP_TABLE_DESC_PACK_STR, buf, offset)
+        props = []
+        rest = buf[offset + ofproto.OFP_TABLE_DESC_SIZE:offset + length]
+        while rest:
+            p, rest = OFPTableModProp.parse(rest)
+            props.append(p)
+        ofptabledesc = cls(length, table_id, config, props)
+        return ofptabledesc
+
+
+class OFPQueueDesc(StringifyMixin):
+    def __init__(self, port_no=None, queue_id=None, len_=None,
+                 properties=None):
+        super(OFPQueueDesc, self).__init__()
+        self.port_no = port_no
+        self.queue_id = queue_id
+        self.len = len_
+        self.properties = properties
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (port_no, queue_id, len_) = struct.unpack_from(
+            ofproto.OFP_QUEUE_DESC_PACK_STR, buf, offset)
+        props = []
+        rest = buf[offset + ofproto.OFP_QUEUE_DESC_SIZE:offset + len_]
+        while rest:
+            p, rest = OFPQueueDescProp.parse(rest)
+            props.append(p)
+        ofpqueuedesc = cls(port_no, queue_id, len_, props)
+        return ofpqueuedesc
+
+
+def _set_stats_type(stats_type, stats_body_cls):
+    def _set_cls_stats_type(cls):
+        cls.cls_stats_type = stats_type
+        cls.cls_stats_body_cls = stats_body_cls
+        return cls
+    return _set_cls_stats_type
+
+
+@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
+class OFPMultipartRequest(MsgBase):
+    def __init__(self, datapath, flags):
+        super(OFPMultipartRequest, self).__init__(datapath)
+        self.type = self.__class__.cls_stats_type
+        self.flags = flags
+
+    def _serialize_stats_body(self):
+        pass
+
+    def _serialize_body(self):
+        msg_pack_into(ofproto.OFP_MULTIPART_REQUEST_PACK_STR,
+                      self.buf, ofproto.OFP_HEADER_SIZE,
+                      self.type, self.flags)
+        self._serialize_stats_body()
+
+
+@_register_parser
+@_set_msg_type(ofproto.OFPT_METER_MOD)
+class OFPMeterMod(MsgBase):
+    """
+    Meter modification message
+
+    The controller sends this message to modify the meter.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    command          One of the following values.
+
+                     | OFPMC_ADD
+                     | OFPMC_MODIFY
+                     | OFPMC_DELETE
+    flags            Bitmap of the following flags.
+
+                     | OFPMF_KBPS
+                     | OFPMF_PKTPS
+                     | OFPMF_BURST
+                     | OFPMF_STATS
+    meter_id         Meter instance
+    bands            list of the following class instance.
+
+                     | OFPMeterBandDrop
+                     | OFPMeterBandDscpRemark
+                     | OFPMeterBandExperimenter
+    ================ ======================================================
+    """
+
+    def __init__(self, datapath, command=ofproto.OFPMC_ADD,
+                 flags=ofproto.OFPMF_KBPS, meter_id=1, bands=None):
+        bands = bands if bands else []
+        super(OFPMeterMod, self).__init__(datapath)
+        self.command = command
+        self.flags = flags
+        self.meter_id = meter_id
+        self.bands = bands
+
+    @classmethod
+    def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+        msg = super(OFPMeterMod, cls).parser(
+            datapath, version, msg_type, msg_len, xid, buf)
+
+        (msg.command, msg.flags, msg.meter_id) = struct.unpack_from(
+            ofproto.OFP_METER_MOD_PACK_STR, buf, ofproto.OFP_HEADER_SIZE)
+        offset = ofproto.OFP_METER_MOD_SIZE
+
+        msg.bands = []
+        while offset < msg.msg_len:
+            band = OFPMeterBandHeader.parser(buf, offset)
+            msg.bands.append(band)
+            offset += band.len
+
+        return msg
+
+    def _serialize_body(self):
+        msg_pack_into(ofproto.OFP_METER_MOD_PACK_STR, self.buf,
+                      ofproto.OFP_HEADER_SIZE,
+                      self.command, self.flags, self.meter_id)
+
+        offset = ofproto.OFP_METER_MOD_SIZE
+        for b in self.bands:
+            b.serialize(self.buf, offset)
+            offset += b.len
+
+
+@_set_msg_type(ofproto.OFPT_TABLE_MOD)
+class OFPTableMod(MsgBase):
+    """
+    Flow table configuration message
+
+    The controller sends this message to configure table state.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    table_id         ID of the table (OFPTT_ALL indicates all tables)
+    config           Bitmap of configuration flags.
+
+                     | OFPTC_EVICTION
+                     | OFPTC_VACANCY_EVENTS
+    properties       List of ``OFPTableModProp`` subclass instance
+    ================ ======================================================
+
+    Example::
+
+        def send_table_mod(self, datapath):
+            ofp = datapath.ofproto
+            ofp_parser = datapath.ofproto_parser
+
+            req = ofp_parser.OFPTableMod(datapath, 1, 3)
+            flags = ofp.OFPTC_VACANCY_EVENTS
+            properties = [ofp_parser.OFPTableModPropEviction(flags)]
+            req = ofp_parser.OFPTableMod(datapath, 1, 3, properties)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, table_id, config, properties):
+        super(OFPTableMod, self).__init__(datapath)
+        self.table_id = table_id
+        self.config = config
+        self.properties = properties
+
+    def _serialize_body(self):
+        props_buf = bytearray()
+        for p in self.properties:
+            props_buf += p.serialize()
+
+        msg_pack_into(ofproto.OFP_TABLE_MOD_PACK_STR, self.buf,
+                      ofproto.OFP_HEADER_SIZE,
+                      self.table_id, self.config)
+
+        self.buf += props_buf
+
+
+@_register_parser
+@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
+class OFPMultipartReply(MsgBase):
+    _STATS_MSG_TYPES = {}
+
+    @staticmethod
+    def register_stats_type(body_single_struct=False):
+        def _register_stats_type(cls):
+            assert cls.cls_stats_type is not None
+            assert cls.cls_stats_type not in OFPMultipartReply._STATS_MSG_TYPES
+            assert cls.cls_stats_body_cls is not None
+            cls.cls_body_single_struct = body_single_struct
+            OFPMultipartReply._STATS_MSG_TYPES[cls.cls_stats_type] = cls
+            return cls
+        return _register_stats_type
+
+    def __init__(self, datapath, body=None, flags=None):
+        super(OFPMultipartReply, self).__init__(datapath)
+        self.body = body
+        self.flags = flags
+
+    @classmethod
+    def parser_stats_body(cls, buf, msg_len, offset):
+        body_cls = cls.cls_stats_body_cls
+        body = []
+        while offset < msg_len:
+            entry = body_cls.parser(buf, offset)
+            body.append(entry)
+            offset += entry.length
+
+        if cls.cls_body_single_struct:
+            return body[0]
+        return body
+
+    @classmethod
+    def parser_stats(cls, datapath, version, msg_type, msg_len, xid, buf):
+        msg = MsgBase.parser.__func__(
+            cls, datapath, version, msg_type, msg_len, xid, buf)
+        msg.body = msg.parser_stats_body(msg.buf, msg.msg_len,
+                                         ofproto.OFP_MULTIPART_REPLY_SIZE)
+        return msg
+
+    @classmethod
+    def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+        type_, flags = struct.unpack_from(
+            ofproto.OFP_MULTIPART_REPLY_PACK_STR, six.binary_type(buf),
+            ofproto.OFP_HEADER_SIZE)
+        stats_type_cls = cls._STATS_MSG_TYPES.get(type_)
+        msg = super(OFPMultipartReply, stats_type_cls).parser(
+            datapath, version, msg_type, msg_len, xid, buf)
+        msg.type = type_
+        msg.flags = flags
+
+        offset = ofproto.OFP_MULTIPART_REPLY_SIZE
+        body = []
+        while offset < msg_len:
+            b = stats_type_cls.cls_stats_body_cls.parser(msg.buf, offset)
+            body.append(b)
+            offset += b.length if hasattr(b, 'length') else b.len
+
+        if stats_type_cls.cls_body_single_struct:
+            msg.body = body[0]
+        else:
+            msg.body = body
+        return msg
+
+
+class OFPDescStats(ofproto_parser.namedtuple('OFPDescStats', (
+        'mfr_desc', 'hw_desc', 'sw_desc', 'serial_num', 'dp_desc'))):
+
+    _TYPE = {
+        'ascii': [
+            'mfr_desc',
+            'hw_desc',
+            'sw_desc',
+            'serial_num',
+            'dp_desc',
+        ]
+    }
+
+    @classmethod
+    def parser(cls, buf, offset):
+        desc = struct.unpack_from(ofproto.OFP_DESC_PACK_STR,
+                                  buf, offset)
+        desc = list(desc)
+        desc = [x.rstrip(b'\0') for x in desc]
+        stats = cls(*desc)
+        stats.length = ofproto.OFP_DESC_SIZE
+        return stats
+
+
+@_set_stats_type(ofproto.OFPMP_DESC, OFPDescStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
+class OFPDescStatsRequest(OFPMultipartRequest):
+    """
+    Description statistics request message
+
+    The controller uses this message to query description of the switch.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    flags            Zero or ``OFPMPF_REQ_MORE``
+    ================ ======================================================
+
+    Example::
+
+        def send_desc_stats_request(self, datapath):
+            ofp_parser = datapath.ofproto_parser
+
+            req = ofp_parser.OFPDescStatsRequest(datapath, 0)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, flags=0, type_=None):
+        super(OFPDescStatsRequest, self).__init__(datapath, flags)
+
+
+@OFPMultipartReply.register_stats_type(body_single_struct=True)
+@_set_stats_type(ofproto.OFPMP_DESC, OFPDescStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
+class OFPDescStatsReply(OFPMultipartReply):
+    """
+    Description statistics reply message
+
+    The switch responds with this message to a description statistics
+    request.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    body             Instance of ``OFPDescStats``
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPDescStatsReply, MAIN_DISPATCHER)
+        def desc_stats_reply_handler(self, ev):
+            body = ev.msg.body
+
+            self.logger.debug('DescStats: mfr_desc=%s hw_desc=%s sw_desc=%s '
+                              'serial_num=%s dp_desc=%s',
+                              body.mfr_desc, body.hw_desc, body.sw_desc,
+                              body.serial_num, body.dp_desc)
+    """
+
+    def __init__(self, datapath, type_=None, **kwargs):
+        super(OFPDescStatsReply, self).__init__(datapath, **kwargs)
+
+
+class OFPTableFeaturesStats(StringifyMixin):
+
+    _TYPE = {
+        'utf-8': [
+            # OF spec is unclear about the encoding of name.
+            # we assumes UTF-8.
+            'name',
+        ]
+    }
+
+    def __init__(self, table_id=None, name=None, metadata_match=None,
+                 metadata_write=None, config=None, max_entries=None,
+                 properties=None, length=None):
+        super(OFPTableFeaturesStats, self).__init__()
+        self.length = None
+        self.table_id = table_id
+        self.name = name
+        self.metadata_match = metadata_match
+        self.metadata_write = metadata_write
+        self.config = config
+        self.max_entries = max_entries
+        self.properties = properties
+
+    @classmethod
+    def parser(cls, buf, offset):
+        table_features = cls()
+        (table_features.length, table_features.table_id,
+         name, table_features.metadata_match,
+         table_features.metadata_write, table_features.config,
+         table_features.max_entries
+         ) = struct.unpack_from(ofproto.OFP_TABLE_FEATURES_PACK_STR,
+                                buf, offset)
+        table_features.name = name.rstrip(b'\0')
+
+        props = []
+        rest = buf[offset + ofproto.OFP_TABLE_FEATURES_SIZE:
+                   offset + table_features.length]
+        while rest:
+            p, rest = OFPTableFeatureProp.parse(rest)
+            props.append(p)
+        table_features.properties = props
+
+        return table_features
+
+    def serialize(self):
+        # fixup
+        bin_props = bytearray()
+        for p in self.properties:
+            bin_props += p.serialize()
+        self.length = ofproto.OFP_TABLE_FEATURES_SIZE + len(bin_props)
+
+        buf = bytearray()
+        msg_pack_into(ofproto.OFP_TABLE_FEATURES_PACK_STR, buf, 0,
+                      self.length, self.table_id, self.name,
+                      self.metadata_match, self.metadata_write,
+                      self.config, self.max_entries)
+        return buf + bin_props
+
+
+class OFPTableFeatureProp(OFPPropBase):
+    _TYPES = {}
+
+
+class OFPInstructionId(StringifyMixin):
+    _PACK_STR = '!HH'  # type, len
+
+    def __init__(self, type_, len_=None):
+        self.type = type_
+        self.len = len_
+        # XXX experimenter
+
+    @classmethod
+    def parse(cls, buf):
+        (type_, len_,) = struct.unpack_from(cls._PACK_STR,
+                                            six.binary_type(buf), 0)
+        rest = buf[len_:]
+        return cls(type_=type_, len_=len_), rest
+
+    def serialize(self):
+        # fixup
+        self.len = struct.calcsize(self._PACK_STR)
+
+        buf = bytearray()
+        msg_pack_into(self._PACK_STR, buf, 0, self.type, self.len)
+        return buf
+
+
+@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_INSTRUCTIONS)
+@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_INSTRUCTIONS_MISS)
+class OFPTableFeaturePropInstructions(OFPTableFeatureProp):
+    def __init__(self, type_=None, length=None, instruction_ids=None):
+        instruction_ids = instruction_ids if instruction_ids else []
+        super(OFPTableFeaturePropInstructions, self).__init__(type_, length)
+        self.instruction_ids = instruction_ids
+
+    @classmethod
+    def parser(cls, buf):
+        rest = cls.get_rest(buf)
+        ids = []
+        while rest:
+            i, rest = OFPInstructionId.parse(rest)
+            ids.append(i)
+        return cls(instruction_ids=ids)
+
+    def serialize_body(self):
+        bin_ids = bytearray()
+        for i in self.instruction_ids:
+            bin_ids += i.serialize()
+
+        return bin_ids
+
+
+# Implementation note: While OpenFlow 1.3.2 shares the same ofp_action_header
+# for flow_mod and table_features, we have separate classes.  We named this
+# class to match with OpenFlow 1.4's name.  (ofp_action_id)
+class OFPActionId(StringifyMixin):
+    _PACK_STR = '!HH'  # type, len
+
+    def __init__(self, type_, len_=None):
+        self.type = type_
+        self.len = len_
+        # XXX experimenter
+
+    @classmethod
+    def parse(cls, buf):
+        (type_, len_,) = struct.unpack_from(cls._PACK_STR,
+                                            six.binary_type(buf), 0)
+        rest = buf[len_:]
+        return cls(type_=type_, len_=len_), rest
+
+    def serialize(self):
+        # fixup
+        self.len = struct.calcsize(self._PACK_STR)
+
+        buf = bytearray()
+        msg_pack_into(self._PACK_STR, buf, 0, self.type, self.len)
+        return buf
+
+
+@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_ACTIONS)
+@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_ACTIONS_MISS)
+@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_ACTIONS)
+@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_ACTIONS_MISS)
+class OFPTableFeaturePropActions(OFPTableFeatureProp):
+    def __init__(self, type_=None, length=None, action_ids=None):
+        action_ids = action_ids if action_ids else []
+        super(OFPTableFeaturePropActions, self).__init__(type_, length)
+        self.action_ids = action_ids
+
+    @classmethod
+    def parser(cls, buf):
+        rest = cls.get_rest(buf)
+        ids = []
+        while rest:
+            i, rest = OFPActionId.parse(rest)
+            ids.append(i)
+        return cls(action_ids=ids)
+
+    def serialize_body(self):
+        bin_ids = bytearray()
+        for i in self.action_ids:
+            bin_ids += i.serialize()
+        return bin_ids
+
+
+@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_NEXT_TABLES)
+@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_NEXT_TABLES_MISS)
+@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_TABLE_SYNC_FROM)
+class OFPTableFeaturePropNextTables(OFPTableFeatureProp):
+    _TABLE_ID_PACK_STR = '!B'
+
+    def __init__(self, type_=None, length=None, table_ids=None):
+        table_ids = table_ids if table_ids else []
+        super(OFPTableFeaturePropNextTables, self).__init__(type_, length)
+        self.table_ids = table_ids
+
+    @classmethod
+    def parser(cls, buf):
+        rest = cls.get_rest(buf)
+        ids = []
+        while rest:
+            (i,) = struct.unpack_from(cls._TABLE_ID_PACK_STR,
+                                      six.binary_type(rest), 0)
+            rest = rest[struct.calcsize(cls._TABLE_ID_PACK_STR):]
+            ids.append(i)
+        return cls(table_ids=ids)
+
+    def serialize_body(self):
+        bin_ids = bytearray()
+        for i in self.table_ids:
+            bin_id = bytearray()
+            msg_pack_into(self._TABLE_ID_PACK_STR, bin_id, 0, i)
+            bin_ids += bin_id
+        return bin_ids
+
+
+# Implementation note: OFPOxmId is specific to this implementation.
+# It does not have a corresponding structure in the specification.
+# (the specification uses plain uint32_t for non-experimenter OXMs
+# and uint64_t for experimenter OXMs.)
+#
+# i have taken a look at some of software switch implementations
+# but they all look broken or incomplete.  according to the spec,
+# oxm_hasmask should be 1 if a switch supports masking for the type.
+# the right value for oxm_length is not clear from the spec.
+# update: OpenFlow 1.3.3 "clarified" that oxm_length here is the payload
+# length.  it's still unclear if it should be doubled for hasmask or not,
+# though.
+#   ofsoftswitch13
+#     oxm_hasmask  always 0
+#     oxm_length   same as ofp_match etc (as without mask)
+#   linc/of_protocol
+#     oxm_hasmask  always 0
+#     oxm_length   always 0
+#   ovs:
+#     seems in flux as of writing this [20141003]
+class OFPOxmId(StringifyMixin):
+    _PACK_STR = '!I'  # oxm header
+    _EXPERIMENTER_ID_PACK_STR = '!I'
+
+    _TYPE = {
+        'ascii': [
+            'type',
+        ],
+    }
+
+    def __init__(self, type_, hasmask=False, length=None):
+        self.type = type_
+        self.hasmask = hasmask
+        self.length = length
+
+    @classmethod
+    def parse(cls, buf):
+        (oxm,) = struct.unpack_from(cls._PACK_STR, six.binary_type(buf), 0)
+        # oxm (32 bit) == class (16) | field (7) | hasmask (1) | length (8)
+        # in case of experimenter OXMs, another 32 bit value
+        # (experimenter id) follows.
+        (type_, _v) = ofproto.oxm_to_user(oxm >> (1 + 8), None, None)
+        rest = buf[struct.calcsize(cls._PACK_STR):]
+        hasmask = ofproto.oxm_tlv_header_extract_hasmask(oxm)
+        length = oxm & 0xff  # XXX see the comment on OFPOxmId
+        class_ = oxm >> (7 + 1 + 8)
+        if class_ == ofproto.OFPXMC_EXPERIMENTER:
+            (exp_id,) = struct.unpack_from(cls._EXPERIMENTER_ID_PACK_STR,
+                                           six.binary_type(rest), 0)
+            rest = rest[struct.calcsize(cls._EXPERIMENTER_ID_PACK_STR):]
+            subcls = OFPExperimenterOxmId
+            return subcls(type_=type_, exp_id=exp_id, hasmask=hasmask,
+                          length=length), rest
+        else:
+            return cls(type_=type_, hasmask=hasmask, length=length), rest
+
+    def serialize(self):
+        # fixup
+        self.length = 0  # XXX see the comment on OFPOxmId
+
+        (n, _v, _m) = ofproto.oxm_from_user(self.type, None)
+        oxm = (n << (1 + 8)) | (self.hasmask << 8) | self.length
+        buf = bytearray()
+        msg_pack_into(self._PACK_STR, buf, 0, oxm)
+        assert n >> 7 != ofproto.OFPXMC_EXPERIMENTER
+        return buf
+
+
+class OFPExperimenterOxmId(OFPOxmId):
+    def __init__(self, type_, exp_id, hasmask=False, length=None):
+        super(OFPExperimenterOxmId, self).__init__(type_=type_,
+                                                   hasmask=hasmask,
+                                                   length=length)
+        self.exp_id = exp_id
+
+    def serialize(self):
+        buf = super(OFPExperimenterOxmId, self).serialize()
+        msg_pack_into(self._EXPERIMENTER_ID_PACK_STR, buf,
+                      struct.calcsize(self._PACK_STR), self.exp_id)
+
+
+@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_MATCH)
+@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WILDCARDS)
+@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_SETFIELD)
+@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_SETFIELD_MISS)
+@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_SETFIELD)
+@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_SETFIELD_MISS)
+class OFPTableFeaturePropOxm(OFPTableFeatureProp):
+    def __init__(self, type_=None, length=None, oxm_ids=None):
+        oxm_ids = oxm_ids if oxm_ids else []
+        super(OFPTableFeaturePropOxm, self).__init__(type_, length)
+        self.oxm_ids = oxm_ids
+
+    @classmethod
+    def parser(cls, buf):
+        rest = cls.get_rest(buf)
+        ids = []
+        while rest:
+            i, rest = OFPOxmId.parse(rest)
+            ids.append(i)
+        return cls(oxm_ids=ids)
+
+    def serialize_body(self):
+        bin_ids = bytearray()
+        for i in self.oxm_ids:
+            bin_ids += i.serialize()
+        return bin_ids
+
+
+@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_EXPERIMENTER)
+@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_EXPERIMENTER_MISS)
+class OFPTableFeaturePropExperimenter(OFPPropCommonExperimenter4ByteData):
+    pass
+
+
+@_set_stats_type(ofproto.OFPMP_TABLE_FEATURES, OFPTableFeaturesStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
+class OFPTableFeaturesStatsRequest(OFPMultipartRequest):
+    """
+    Table features statistics request message
+
+    The controller uses this message to query table features.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    body             List of ``OFPTableFeaturesStats`` instances.
+                     The default is [].
+    ================ ======================================================
+    """
+
+    def __init__(self, datapath, flags=0, body=None, type_=None):
+        body = body if body else []
+        super(OFPTableFeaturesStatsRequest, self).__init__(datapath, flags)
+        self.body = body
+
+    def _serialize_stats_body(self):
+        bin_body = bytearray()
+        for p in self.body:
+            bin_body += p.serialize()
+        self.buf += bin_body
+
+
+@OFPMultipartReply.register_stats_type()
+@_set_stats_type(ofproto.OFPMP_TABLE_FEATURES, OFPTableFeaturesStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
+class OFPTableFeaturesStatsReply(OFPMultipartReply):
+    """
+    Table features statistics reply message
+
+    The switch responds with this message to a table features statistics
+    request.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    body             List of ``OFPTableFeaturesStats`` instance
+    ================ ======================================================
+    """
+
+    def __init__(self, datapath, type_=None, **kwargs):
+        super(OFPTableFeaturesStatsReply, self).__init__(datapath, **kwargs)
+
+
+@_set_stats_type(ofproto.OFPMP_PORT_DESC, OFPPort)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
+class OFPPortDescStatsRequest(OFPMultipartRequest):
+    """
+    Port description request message
+
+    The controller uses this message to query description of all the ports.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    flags            Zero or ``OFPMPF_REQ_MORE``
+    ================ ======================================================
+
+    Example::
+
+        def send_port_desc_stats_request(self, datapath):
+            ofp_parser = datapath.ofproto_parser
+
+            req = ofp_parser.OFPPortDescStatsRequest(datapath, 0)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, flags=0, type_=None):
+        super(OFPPortDescStatsRequest, self).__init__(datapath, flags)
+
+
+@OFPMultipartReply.register_stats_type()
+@_set_stats_type(ofproto.OFPMP_PORT_DESC, OFPPort)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
+class OFPPortDescStatsReply(OFPMultipartReply):
+    """
+    Port description reply message
+
+    The switch responds with this message to a port description request.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    body             List of ``OFPPort`` instance
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPPortDescStatsReply, MAIN_DISPATCHER)
+        def port_desc_stats_reply_handler(self, ev):
+            ports = []
+            for p in ev.msg.body:
+                ports.append('port_no=%d hw_addr=%s name=%s config=0x%08x '
+                             'state=0x%08x properties=%s' %
+                             (p.port_no, p.hw_addr,
+                              p.name, p.config, p.state, repr(p.properties)))
+            self.logger.debug('OFPPortDescStatsReply received: %s', ports)
+    """
+
+    def __init__(self, datapath, type_=None, **kwargs):
+        super(OFPPortDescStatsReply, self).__init__(datapath, **kwargs)
+
+
+@_set_stats_type(ofproto.OFPMP_TABLE_DESC, OFPTableDesc)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
+class OFPTableDescStatsRequest(OFPMultipartRequest):
+    """
+    Table description request message
+
+    The controller uses this message to query description of all the tables.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    flags            Zero or ``OFPMPF_REQ_MORE``
+    ================ ======================================================
+
+    Example::
+
+        def send_table_desc_stats_request(self, datapath):
+            ofp_parser = datapath.ofproto_parser
+
+            req = ofp_parser.OFPTableDescStatsRequest(datapath, 0)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, flags=0, type_=None):
+        super(OFPTableDescStatsRequest, self).__init__(datapath, flags)
+
+
+@OFPMultipartReply.register_stats_type()
+@_set_stats_type(ofproto.OFPMP_TABLE_DESC, OFPTableDesc)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
+class OFPTableDescStatsReply(OFPMultipartReply):
+    """
+    Table description reply message
+
+    The switch responds with this message to a table description request.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    body             List of ``OFPTableDesc`` instance
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPTableDescStatsReply, MAIN_DISPATCHER)
+        def table_desc_stats_reply_handler(self, ev):
+            tables = []
+            for p in ev.msg.body:
+                tables.append('table_id=%d config=0x%08x properties=%s' %
+                             (p.table_id, p.config, repr(p.properties)))
+            self.logger.debug('OFPTableDescStatsReply received: %s', tables)
+    """
+
+    def __init__(self, datapath, type_=None, **kwargs):
+        super(OFPTableDescStatsReply, self).__init__(datapath, **kwargs)
+
+
+@_set_stats_type(ofproto.OFPMP_QUEUE_DESC, OFPQueueDesc)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
+class OFPQueueDescStatsRequest(OFPMultipartRequest):
+    """
+    Queue description request message
+
+    The controller uses this message to query description of all the queues.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    flags            Zero or ``OFPMPF_REQ_MORE``
+    port_no          Port number to read (OFPP_ANY for all ports)
+    queue_id         ID of queue to read (OFPQ_ALL for all queues)
+    ================ ======================================================
+
+    Example::
+
+        def send_queue_desc_stats_request(self, datapath):
+            ofp = datapath.ofproto
+            ofp_parser = datapath.ofproto_parser
+            req = ofp_parser.OFPQueueDescStatsRequest(datapath, 0,
+                                                      ofp.OFPP_ANY,
+                                                      ofp.OFPQ_ALL)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, flags=0, port_no=ofproto.OFPP_ANY,
+                 queue_id=ofproto.OFPQ_ALL, type_=None):
+        super(OFPQueueDescStatsRequest, self).__init__(datapath, flags)
+        self.port_no = port_no
+        self.queue_id = queue_id
+
+    def _serialize_stats_body(self):
+        msg_pack_into(ofproto.OFP_QUEUE_DESC_REQUEST_PACK_STR,
+                      self.buf,
+                      ofproto.OFP_MULTIPART_REQUEST_SIZE,
+                      self.port_no, self.queue_id)
+
+
+@OFPMultipartReply.register_stats_type()
+@_set_stats_type(ofproto.OFPMP_QUEUE_DESC, OFPQueueDesc)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
+class OFPQueueDescStatsReply(OFPMultipartReply):
+    """
+    Queue description reply message
+
+    The switch responds with this message to a queue description request.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    body             List of ``OFPQueueDesc`` instance
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPQueueDescStatsReply, MAIN_DISPATCHER)
+        def queue_desc_stats_reply_handler(self, ev):
+            queues = []
+            for q in ev.msg.body:
+                queues.append('port_no=%d queue_id=0x%08x properties=%s' %
+                             (q.port_no, q.queue_id, repr(q.properties)))
+            self.logger.debug('OFPQueueDescStatsReply received: %s', queues)
+    """
+
+    def __init__(self, datapath, type_=None, **kwargs):
+        super(OFPQueueDescStatsReply, self).__init__(datapath, **kwargs)
+
+
+class OFPQueueStatsProp(OFPPropBase):
+    _TYPES = {}
+
+
+@OFPQueueStatsProp.register_type(ofproto.OFPQSPT_EXPERIMENTER)
+class OFPQueueStatsPropExperimenter(OFPPropCommonExperimenter4ByteData):
+    pass
+
+
+class OFPQueueStats(StringifyMixin):
+    def __init__(self, length=None, port_no=None, queue_id=None,
+                 tx_bytes=None, tx_packets=None, tx_errors=None,
+                 duration_sec=None, duration_nsec=None, properties=None):
+        super(OFPQueueStats, self).__init__()
+        self.length = length
+        self.port_no = port_no
+        self.queue_id = queue_id
+        self.tx_bytes = tx_bytes
+        self.tx_packets = tx_packets
+        self.tx_errors = tx_errors
+        self.duration_sec = duration_sec
+        self.duration_nsec = duration_nsec
+        self.properties = properties
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (length, port_no, queue_id, tx_bytes, tx_packets, tx_errors,
+         duration_sec, duration_nsec) = struct.unpack_from(
+            ofproto.OFP_QUEUE_STATS_PACK_STR, buf, offset)
+        props = []
+        rest = buf[offset + ofproto.OFP_QUEUE_STATS_SIZE:offset + length]
+        while rest:
+            p, rest = OFPQueueStatsProp.parse(rest)
+            props.append(p)
+        stats = cls(length, port_no, queue_id, tx_bytes, tx_packets, tx_errors,
+                    duration_sec, duration_nsec, props)
+        return stats
+
+
+@_set_stats_type(ofproto.OFPMP_QUEUE_STATS, OFPQueueStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
+class OFPQueueStatsRequest(OFPMultipartRequest):
+    """
+    Queue statistics request message
+
+    The controller uses this message to query queue statictics.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    flags            Zero or ``OFPMPF_REQ_MORE``
+    port_no          Port number to read
+    queue_id         ID of queue to read
+    ================ ======================================================
+
+    Example::
+
+        def send_queue_stats_request(self, datapath):
+            ofp = datapath.ofproto
+            ofp_parser = datapath.ofproto_parser
+
+            req = ofp_parser.OFPQueueStatsRequest(datapath, 0, ofp.OFPP_ANY,
+                                                  ofp.OFPQ_ALL)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, flags=0, port_no=ofproto.OFPP_ANY,
+                 queue_id=ofproto.OFPQ_ALL, type_=None):
+        super(OFPQueueStatsRequest, self).__init__(datapath, flags)
+        self.port_no = port_no
+        self.queue_id = queue_id
+
+    def _serialize_stats_body(self):
+        msg_pack_into(ofproto.OFP_QUEUE_STATS_REQUEST_PACK_STR,
+                      self.buf,
+                      ofproto.OFP_MULTIPART_REQUEST_SIZE,
+                      self.port_no, self.queue_id)
+
+
+@OFPMultipartReply.register_stats_type()
+@_set_stats_type(ofproto.OFPMP_QUEUE_STATS, OFPQueueStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
+class OFPQueueStatsReply(OFPMultipartReply):
+    """
+    Queue statistics reply message
+
+    The switch responds with this message to an aggregate flow statistics
+    request.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    body             List of ``OFPQueueStats`` instance
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPQueueStatsReply, MAIN_DISPATCHER)
+        def queue_stats_reply_handler(self, ev):
+            queues = []
+            for stat in ev.msg.body:
+                queues.append('port_no=%d queue_id=%d '
+                              'tx_bytes=%d tx_packets=%d tx_errors=%d '
+                              'duration_sec=%d duration_nsec=%d'
+                              'properties=%s' %
+                              (stat.port_no, stat.queue_id,
+                               stat.tx_bytes, stat.tx_packets, stat.tx_errors,
+                               stat.duration_sec, stat.duration_nsec,
+                               repr(stat.properties)))
+            self.logger.debug('QueueStats: %s', queues)
+    """
+
+    def __init__(self, datapath, type_=None, **kwargs):
+        super(OFPQueueStatsReply, self).__init__(datapath, **kwargs)
+
+
+class OFPBucketCounter(StringifyMixin):
+    def __init__(self, packet_count, byte_count):
+        super(OFPBucketCounter, self).__init__()
+        self.packet_count = packet_count
+        self.byte_count = byte_count
+
+    @classmethod
+    def parser(cls, buf, offset):
+        packet_count, byte_count = struct.unpack_from(
+            ofproto.OFP_BUCKET_COUNTER_PACK_STR, buf, offset)
+        return cls(packet_count, byte_count)
+
+
+class OFPGroupStats(StringifyMixin):
+    def __init__(self, length=None, group_id=None, ref_count=None,
+                 packet_count=None, byte_count=None, duration_sec=None,
+                 duration_nsec=None, bucket_stats=None):
+        super(OFPGroupStats, self).__init__()
+        self.length = length
+        self.group_id = group_id
+        self.ref_count = ref_count
+        self.packet_count = packet_count
+        self.byte_count = byte_count
+        self.duration_sec = duration_sec
+        self.duration_nsec = duration_nsec
+        self.bucket_stats = bucket_stats
+
+    @classmethod
+    def parser(cls, buf, offset):
+        group = struct.unpack_from(ofproto.OFP_GROUP_STATS_PACK_STR,
+                                   buf, offset)
+        group_stats = cls(*group)
+
+        group_stats.bucket_stats = []
+        total_len = group_stats.length + offset
+        offset += ofproto.OFP_GROUP_STATS_SIZE
+        while total_len > offset:
+            b = OFPBucketCounter.parser(buf, offset)
+            group_stats.bucket_stats.append(b)
+            offset += ofproto.OFP_BUCKET_COUNTER_SIZE
+
+        return group_stats
+
+
+@_set_stats_type(ofproto.OFPMP_GROUP, OFPGroupStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
+class OFPGroupStatsRequest(OFPMultipartRequest):
+    """
+    Group statistics request message
+
+    The controller uses this message to query statistics of one or more
+    groups.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    flags            Zero or ``OFPMPF_REQ_MORE``
+    group_id         ID of group to read (OFPG_ALL to all groups)
+    ================ ======================================================
+
+    Example::
+
+        def send_group_stats_request(self, datapath):
+            ofp = datapath.ofproto
+            ofp_parser = datapath.ofproto_parser
+
+            req = ofp_parser.OFPGroupStatsRequest(datapath, 0, ofp.OFPG_ALL)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, flags=0, group_id=ofproto.OFPG_ALL,
+                 type_=None):
+        super(OFPGroupStatsRequest, self).__init__(datapath, flags)
+        self.group_id = group_id
+
+    def _serialize_stats_body(self):
+        msg_pack_into(ofproto.OFP_GROUP_STATS_REQUEST_PACK_STR,
+                      self.buf,
+                      ofproto.OFP_MULTIPART_REQUEST_SIZE,
+                      self.group_id)
+
+
+@OFPMultipartReply.register_stats_type()
+@_set_stats_type(ofproto.OFPMP_GROUP, OFPGroupStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
+class OFPGroupStatsReply(OFPMultipartReply):
+    """
+    Group statistics reply message
+
+    The switch responds with this message to a group statistics request.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    body             List of ``OFPGroupStats`` instance
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPGroupStatsReply, MAIN_DISPATCHER)
+        def group_stats_reply_handler(self, ev):
+            groups = []
+            for stat in ev.msg.body:
+                groups.append('length=%d group_id=%d '
+                              'ref_count=%d packet_count=%d byte_count=%d '
+                              'duration_sec=%d duration_nsec=%d' %
+                              (stat.length, stat.group_id,
+                               stat.ref_count, stat.packet_count,
+                               stat.byte_count, stat.duration_sec,
+                               stat.duration_nsec))
+            self.logger.debug('GroupStats: %s', groups)
+    """
+
+    def __init__(self, datapath, type_=None, **kwargs):
+        super(OFPGroupStatsReply, self).__init__(datapath, **kwargs)
+
+
+class OFPGroupDescStats(StringifyMixin):
+    def __init__(self, type_=None, group_id=None, buckets=None, length=None):
+        super(OFPGroupDescStats, self).__init__()
+        self.type = type_
+        self.group_id = group_id
+        self.buckets = buckets
+
+    @classmethod
+    def parser(cls, buf, offset):
+        stats = cls()
+
+        (stats.length, stats.type, stats.group_id) = struct.unpack_from(
+            ofproto.OFP_GROUP_DESC_STATS_PACK_STR, buf, offset)
+        offset += ofproto.OFP_GROUP_DESC_STATS_SIZE
+
+        stats.buckets = []
+        length = ofproto.OFP_GROUP_DESC_STATS_SIZE
+        while length < stats.length:
+            bucket = OFPBucket.parser(buf, offset)
+            stats.buckets.append(bucket)
+
+            offset += bucket.len
+            length += bucket.len
+
+        return stats
+
+
+@_set_stats_type(ofproto.OFPMP_GROUP_DESC, OFPGroupDescStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
+class OFPGroupDescStatsRequest(OFPMultipartRequest):
+    """
+    Group description request message
+
+    The controller uses this message to list the set of groups on a switch.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    flags            Zero or ``OFPMPF_REQ_MORE``
+    ================ ======================================================
+
+    Example::
+
+        def send_group_desc_stats_request(self, datapath):
+            ofp = datapath.ofproto
+            ofp_parser = datapath.ofproto_parser
+
+            req = ofp_parser.OFPGroupDescStatsRequest(datapath, 0)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, flags=0, type_=None):
+        super(OFPGroupDescStatsRequest, self).__init__(datapath, flags)
+
+
+@OFPMultipartReply.register_stats_type()
+@_set_stats_type(ofproto.OFPMP_GROUP_DESC, OFPGroupDescStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
+class OFPGroupDescStatsReply(OFPMultipartReply):
+    """
+    Group description reply message
+
+    The switch responds with this message to a group description request.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    body             List of ``OFPGroupDescStats`` instance
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPGroupDescStatsReply, MAIN_DISPATCHER)
+        def group_desc_stats_reply_handler(self, ev):
+            descs = []
+            for stat in ev.msg.body:
+                descs.append('length=%d type=%d group_id=%d '
+                             'buckets=%s' %
+                             (stat.length, stat.type, stat.group_id,
+                              stat.bucket))
+            self.logger.debug('GroupDescStats: %s', descs)
+    """
+
+    def __init__(self, datapath, type_=None, **kwargs):
+        super(OFPGroupDescStatsReply, self).__init__(datapath, **kwargs)
+
+
+class OFPGroupFeaturesStats(ofproto_parser.namedtuple('OFPGroupFeaturesStats',
+                                                      ('types', 'capabilities', 'max_groups',
+                                                       'actions'))):
+    @classmethod
+    def parser(cls, buf, offset):
+        group_features = struct.unpack_from(
+            ofproto.OFP_GROUP_FEATURES_PACK_STR, buf, offset)
+        types = group_features[0]
+        capabilities = group_features[1]
+        max_groups = list(group_features[2:6])
+        actions = list(group_features[6:10])
+        stats = cls(types, capabilities, max_groups, actions)
+        stats.length = ofproto.OFP_GROUP_FEATURES_SIZE
+        return stats
+
+
+@_set_stats_type(ofproto.OFPMP_GROUP_FEATURES, OFPGroupFeaturesStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
+class OFPGroupFeaturesStatsRequest(OFPMultipartRequest):
+    """
+    Group features request message
+
+    The controller uses this message to list the capabilities of groups on
+    a switch.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    flags            Zero or ``OFPMPF_REQ_MORE``
+    ================ ======================================================
+
+    Example::
+
+        def send_group_features_stats_request(self, datapath):
+            ofp_parser = datapath.ofproto_parser
+
+            req = ofp_parser.OFPGroupFeaturesStatsRequest(datapath, 0)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, flags=0, type_=None):
+        super(OFPGroupFeaturesStatsRequest, self).__init__(datapath, flags)
+
+
+@OFPMultipartReply.register_stats_type(body_single_struct=True)
+@_set_stats_type(ofproto.OFPMP_GROUP_FEATURES, OFPGroupFeaturesStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
+class OFPGroupFeaturesStatsReply(OFPMultipartReply):
+    """
+    Group features reply message
+
+    The switch responds with this message to a group features request.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    body             Instance of ``OFPGroupFeaturesStats``
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPGroupFeaturesStatsReply, MAIN_DISPATCHER)
+        def group_features_stats_reply_handler(self, ev):
+            body = ev.msg.body
+
+            self.logger.debug('GroupFeaturesStats: types=%d '
+                              'capabilities=0x%08x max_groups=%s '
+                              'actions=%s',
+                              body.types, body.capabilities,
+                              body.max_groups, body.actions)
+    """
+
+    def __init__(self, datapath, type_=None, **kwargs):
+        super(OFPGroupFeaturesStatsReply, self).__init__(datapath, **kwargs)
+
+
+class OFPMeterBandStats(StringifyMixin):
+    def __init__(self, packet_band_count, byte_band_count):
+        super(OFPMeterBandStats, self).__init__()
+        self.packet_band_count = packet_band_count
+        self.byte_band_count = byte_band_count
+
+    @classmethod
+    def parser(cls, buf, offset):
+        band_stats = struct.unpack_from(
+            ofproto.OFP_METER_BAND_STATS_PACK_STR, buf, offset)
+        return cls(*band_stats)
+
+
+class OFPMeterStats(StringifyMixin):
+    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, len_=None):
+        super(OFPMeterStats, self).__init__()
+        self.meter_id = meter_id
+        self.len = 0
+        self.flow_count = flow_count
+        self.packet_in_count = packet_in_count
+        self.byte_in_count = byte_in_count
+        self.duration_sec = duration_sec
+        self.duration_nsec = duration_nsec
+        self.band_stats = band_stats
+
+    @classmethod
+    def parser(cls, buf, offset):
+        meter_stats = cls()
+
+        (meter_stats.meter_id, meter_stats.len,
+         meter_stats.flow_count, meter_stats.packet_in_count,
+         meter_stats.byte_in_count, meter_stats.duration_sec,
+         meter_stats.duration_nsec) = struct.unpack_from(
+            ofproto.OFP_METER_STATS_PACK_STR, buf, offset)
+        offset += ofproto.OFP_METER_STATS_SIZE
+
+        meter_stats.band_stats = []
+        length = ofproto.OFP_METER_STATS_SIZE
+        while length < meter_stats.len:
+            band_stats = OFPMeterBandStats.parser(buf, offset)
+            meter_stats.band_stats.append(band_stats)
+            offset += ofproto.OFP_METER_BAND_STATS_SIZE
+            length += ofproto.OFP_METER_BAND_STATS_SIZE
+
+        return meter_stats
+
+
+@_set_stats_type(ofproto.OFPMP_METER, OFPMeterStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
+class OFPMeterStatsRequest(OFPMultipartRequest):
+    """
+    Meter statistics request message
+
+    The controller uses this message to query statistics for one or more
+    meters.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    flags            Zero or ``OFPMPF_REQ_MORE``
+    meter_id         ID of meter to read (OFPM_ALL to all meters)
+    ================ ======================================================
+
+    Example::
+
+        def send_meter_stats_request(self, datapath):
+            ofp = datapath.ofproto
+            ofp_parser = datapath.ofproto_parser
+
+            req = ofp_parser.OFPMeterStatsRequest(datapath, 0, ofp.OFPM_ALL)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, flags=0, meter_id=ofproto.OFPM_ALL,
+                 type_=None):
+        super(OFPMeterStatsRequest, self).__init__(datapath, flags)
+        self.meter_id = meter_id
+
+    def _serialize_stats_body(self):
+        msg_pack_into(ofproto.OFP_METER_MULTIPART_REQUEST_PACK_STR,
+                      self.buf,
+                      ofproto.OFP_MULTIPART_REQUEST_SIZE,
+                      self.meter_id)
+
+
+@OFPMultipartReply.register_stats_type()
+@_set_stats_type(ofproto.OFPMP_METER, OFPMeterStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
+class OFPMeterStatsReply(OFPMultipartReply):
+    """
+    Meter statistics reply message
+
+    The switch responds with this message to a meter statistics request.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    body             List of ``OFPMeterStats`` instance
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPMeterStatsReply, MAIN_DISPATCHER)
+        def meter_stats_reply_handler(self, ev):
+            meters = []
+            for stat in ev.msg.body:
+                meters.append('meter_id=0x%08x len=%d flow_count=%d '
+                              'packet_in_count=%d byte_in_count=%d '
+                              'duration_sec=%d duration_nsec=%d '
+                              'band_stats=%s' %
+                              (stat.meter_id, stat.len, stat.flow_count,
+                               stat.packet_in_count, stat.byte_in_count,
+                               stat.duration_sec, stat.duration_nsec,
+                               stat.band_stats))
+            self.logger.debug('MeterStats: %s', meters)
+    """
+
+    def __init__(self, datapath, type_=None, **kwargs):
+        super(OFPMeterStatsReply, self).__init__(datapath, **kwargs)
+
+
+class OFPMeterBand(StringifyMixin):
+    def __init__(self, type_, len_):
+        super(OFPMeterBand, self).__init__()
+        self.type = type_
+        self.len = len_
+
+
+class OFPMeterBandHeader(OFPMeterBand):
+    _METER_BAND = {}
+
+    @staticmethod
+    def register_meter_band_type(type_, len_):
+        def _register_meter_band_type(cls):
+            OFPMeterBandHeader._METER_BAND[type_] = cls
+            cls.cls_meter_band_type = type_
+            cls.cls_meter_band_len = len_
+            return cls
+        return _register_meter_band_type
+
+    def __init__(self):
+        cls = self.__class__
+        super(OFPMeterBandHeader, self).__init__(cls.cls_meter_band_type,
+                                                 cls.cls_meter_band_len)
+
+    @classmethod
+    def parser(cls, buf, offset):
+        type_, len_, _rate, _burst_size = struct.unpack_from(
+            ofproto.OFP_METER_BAND_HEADER_PACK_STR, buf, offset)
+        cls_ = cls._METER_BAND[type_]
+        assert cls_.cls_meter_band_len == len_
+        return cls_.parser(buf, offset)
+
+
+@OFPMeterBandHeader.register_meter_band_type(
+    ofproto.OFPMBT_DROP, ofproto.OFP_METER_BAND_DROP_SIZE)
+class OFPMeterBandDrop(OFPMeterBandHeader):
+    def __init__(self, rate=0, burst_size=0, type_=None, len_=None):
+        super(OFPMeterBandDrop, self).__init__()
+        self.rate = rate
+        self.burst_size = burst_size
+
+    def serialize(self, buf, offset):
+        msg_pack_into(ofproto.OFP_METER_BAND_DROP_PACK_STR, buf, offset,
+                      self.type, self.len, self.rate, self.burst_size)
+
+    @classmethod
+    def parser(cls, buf, offset):
+        type_, len_, rate, burst_size = struct.unpack_from(
+            ofproto.OFP_METER_BAND_DROP_PACK_STR, buf, offset)
+        assert cls.cls_meter_band_type == type_
+        assert cls.cls_meter_band_len == len_
+        return cls(rate, burst_size)
+
+
+@OFPMeterBandHeader.register_meter_band_type(
+    ofproto.OFPMBT_DSCP_REMARK,
+    ofproto.OFP_METER_BAND_DSCP_REMARK_SIZE)
+class OFPMeterBandDscpRemark(OFPMeterBandHeader):
+    def __init__(self, rate=0, burst_size=0, prec_level=0,
+                 type_=None, len_=None):
+        super(OFPMeterBandDscpRemark, self).__init__()
+        self.rate = rate
+        self.burst_size = burst_size
+        self.prec_level = prec_level
+
+    def serialize(self, buf, offset):
+        msg_pack_into(ofproto.OFP_METER_BAND_DSCP_REMARK_PACK_STR, buf,
+                      offset, self.type, self.len, self.rate,
+                      self.burst_size, self.prec_level)
+
+    @classmethod
+    def parser(cls, buf, offset):
+        type_, len_, rate, burst_size, prec_level = struct.unpack_from(
+            ofproto.OFP_METER_BAND_DSCP_REMARK_PACK_STR, buf, offset)
+        assert cls.cls_meter_band_type == type_
+        assert cls.cls_meter_band_len == len_
+        return cls(rate, burst_size, prec_level)
+
+
+@OFPMeterBandHeader.register_meter_band_type(
+    ofproto.OFPMBT_EXPERIMENTER,
+    ofproto.OFP_METER_BAND_EXPERIMENTER_SIZE)
+class OFPMeterBandExperimenter(OFPMeterBandHeader):
+    def __init__(self, rate=0, burst_size=0, experimenter=None,
+                 type_=None, len_=None):
+        super(OFPMeterBandExperimenter, self).__init__()
+        self.rate = rate
+        self.burst_size = burst_size
+        self.experimenter = experimenter
+
+    def serialize(self, buf, offset):
+        msg_pack_into(ofproto.OFP_METER_BAND_EXPERIMENTER_PACK_STR, buf,
+                      offset, self.type, self.len, self.rate,
+                      self.burst_size, self.experimenter)
+
+    @classmethod
+    def parser(cls, buf, offset):
+        type_, len_, rate, burst_size, experimenter = struct.unpack_from(
+            ofproto.OFP_METER_BAND_EXPERIMENTER_PACK_STR, buf, offset)
+        assert cls.cls_meter_band_type == type_
+        assert cls.cls_meter_band_len == len_
+        return cls(rate, burst_size, experimenter)
+
+
+class OFPMeterConfigStats(StringifyMixin):
+    def __init__(self, flags=None, meter_id=None, bands=None, length=None):
+        super(OFPMeterConfigStats, self).__init__()
+        self.length = None
+        self.flags = flags
+        self.meter_id = meter_id
+        self.bands = bands
+
+    @classmethod
+    def parser(cls, buf, offset):
+        meter_config = cls()
+
+        (meter_config.length, meter_config.flags,
+         meter_config.meter_id) = struct.unpack_from(
+            ofproto.OFP_METER_CONFIG_PACK_STR, buf, offset)
+        offset += ofproto.OFP_METER_CONFIG_SIZE
+
+        meter_config.bands = []
+        length = ofproto.OFP_METER_CONFIG_SIZE
+        while length < meter_config.length:
+            band = OFPMeterBandHeader.parser(buf, offset)
+            meter_config.bands.append(band)
+            offset += band.len
+            length += band.len
+
+        return meter_config
+
+
+@_set_stats_type(ofproto.OFPMP_METER_CONFIG, OFPMeterConfigStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
+class OFPMeterConfigStatsRequest(OFPMultipartRequest):
+    """
+    Meter configuration statistics request message
+
+    The controller uses this message to query configuration for one or more
+    meters.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    flags            Zero or ``OFPMPF_REQ_MORE``
+    meter_id         ID of meter to read (OFPM_ALL to all meters)
+    ================ ======================================================
+
+    Example::
+
+        def send_meter_config_stats_request(self, datapath):
+            ofp = datapath.ofproto
+            ofp_parser = datapath.ofproto_parser
+
+            req = ofp_parser.OFPMeterConfigStatsRequest(datapath, 0,
+                                                        ofp.OFPM_ALL)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, flags=0, meter_id=ofproto.OFPM_ALL,
+                 type_=None):
+        super(OFPMeterConfigStatsRequest, self).__init__(datapath, flags)
+        self.meter_id = meter_id
+
+    def _serialize_stats_body(self):
+        msg_pack_into(ofproto.OFP_METER_MULTIPART_REQUEST_PACK_STR,
+                      self.buf,
+                      ofproto.OFP_MULTIPART_REQUEST_SIZE,
+                      self.meter_id)
+
+
+@OFPMultipartReply.register_stats_type()
+@_set_stats_type(ofproto.OFPMP_METER_CONFIG, OFPMeterConfigStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
+class OFPMeterConfigStatsReply(OFPMultipartReply):
+    """
+    Meter configuration statistics reply message
+
+    The switch responds with this message to a meter configuration
+    statistics request.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    body             List of ``OFPMeterConfigStats`` instance
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPMeterConfigStatsReply, MAIN_DISPATCHER)
+        def meter_config_stats_reply_handler(self, ev):
+            configs = []
+            for stat in ev.msg.body:
+                configs.append('length=%d flags=0x%04x meter_id=0x%08x '
+                               'bands=%s' %
+                               (stat.length, stat.flags, stat.meter_id,
+                                stat.bands))
+            self.logger.debug('MeterConfigStats: %s', configs)
+    """
+
+    def __init__(self, datapath, type_=None, **kwargs):
+        super(OFPMeterConfigStatsReply, self).__init__(datapath, **kwargs)
+
+
+class OFPMeterFeaturesStats(ofproto_parser.namedtuple('OFPMeterFeaturesStats',
+                                                      ('max_meter', 'band_types', 'capabilities',
+                                                       'max_bands', 'max_color'))):
+    @classmethod
+    def parser(cls, buf, offset):
+        meter_features = struct.unpack_from(
+            ofproto.OFP_METER_FEATURES_PACK_STR, buf, offset)
+        stats = cls(*meter_features)
+        stats.length = ofproto.OFP_METER_FEATURES_SIZE
+        return stats
+
+
+@_set_stats_type(ofproto.OFPMP_METER_FEATURES, OFPMeterFeaturesStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
+class OFPMeterFeaturesStatsRequest(OFPMultipartRequest):
+    """
+    Meter features statistics request message
+
+    The controller uses this message to query the set of features of the
+    metering subsystem.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    flags            Zero or ``OFPMPF_REQ_MORE``
+    ================ ======================================================
+
+    Example::
+
+        def send_meter_features_stats_request(self, datapath):
+            ofp_parser = datapath.ofproto_parser
+
+            req = ofp_parser.OFPMeterFeaturesStatsRequest(datapath, 0)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, flags=0, type_=None):
+        super(OFPMeterFeaturesStatsRequest, self).__init__(datapath, flags)
+
+
+@OFPMultipartReply.register_stats_type()
+@_set_stats_type(ofproto.OFPMP_METER_FEATURES, OFPMeterFeaturesStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
+class OFPMeterFeaturesStatsReply(OFPMultipartReply):
+    """
+    Meter features statistics reply message
+
+    The switch responds with this message to a meter features statistics
+    request.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    body             List of ``OFPMeterFeaturesStats`` instance
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPMeterFeaturesStatsReply, MAIN_DISPATCHER)
+        def meter_features_stats_reply_handler(self, ev):
+            features = []
+            for stat in ev.msg.body:
+                features.append('max_meter=%d band_types=0x%08x '
+                                'capabilities=0x%08x max_bands=%d '
+                                'max_color=%d' %
+                                (stat.max_meter, stat.band_types,
+                                 stat.capabilities, stat.max_bands,
+                                 stat.max_color))
+            self.logger.debug('MeterFeaturesStats: %s', features)
+    """
+
+    def __init__(self, datapath, type_=None, **kwargs):
+        super(OFPMeterFeaturesStatsReply, self).__init__(datapath, **kwargs)
+
+
+class OFPFlowUpdate(StringifyMixin):
+    def __init__(self, length, event):
+        super(OFPFlowUpdate, self).__init__()
+        self.length = length
+        self.event = event
+
+
+class OFPFlowUpdateHeader(OFPFlowUpdate):
+    _EVENT = {}
+
+    @staticmethod
+    def register_flow_update_event(event, length):
+        def _register_flow_update_event(cls):
+            OFPFlowUpdateHeader._EVENT[event] = cls
+            cls.cls_flow_update_event = event
+            cls.cls_flow_update_length = length
+            return cls
+        return _register_flow_update_event
+
+    def __init__(self, length=None, event=None):
+        cls = self.__class__
+        super(OFPFlowUpdateHeader, self).__init__(length,
+                                                  cls.cls_flow_update_event)
+        self.length = length
+
+    @classmethod
+    def parser(cls, buf, offset):
+        length, event = struct.unpack_from(
+            ofproto.OFP_FLOW_UPDATE_HEADER_PACK_STR, buf, offset)
+        cls_ = cls._EVENT[event]
+        return cls_.parser(buf, offset)
+
+
+@OFPFlowUpdateHeader.register_flow_update_event(
+    ofproto.OFPFME_INITIAL, ofproto.OFP_FLOW_UPDATE_FULL_SIZE)
+@OFPFlowUpdateHeader.register_flow_update_event(
+    ofproto.OFPFME_ADDED, ofproto.OFP_FLOW_UPDATE_FULL_SIZE)
+@OFPFlowUpdateHeader.register_flow_update_event(
+    ofproto.OFPFME_REMOVED, ofproto.OFP_FLOW_UPDATE_FULL_SIZE)
+@OFPFlowUpdateHeader.register_flow_update_event(
+    ofproto.OFPFME_MODIFIED, ofproto.OFP_FLOW_UPDATE_FULL_SIZE)
+class OFPFlowUpdateFull(OFPFlowUpdateHeader):
+    def __init__(self, length=None, event=None, table_id=None, reason=None,
+                 idle_timeout=None, hard_timeout=None, priority=None,
+                 cookie=None, match=None, instructions=None):
+        instructions = instructions if instructions else []
+        super(OFPFlowUpdateFull, self).__init__(length, event)
+        self.table_id = table_id
+        self.reason = reason
+        self.idle_timeout = idle_timeout
+        self.hard_timeout = hard_timeout
+        self.priority = priority
+        self.cookie = cookie
+        self.match = match
+        assert (event != ofproto.OFPFME_REMOVED or len(instructions) == 0)
+        for i in instructions:
+            assert isinstance(i, OFPInstruction)
+        self.instructions = instructions
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (length, event, table_id, reason, idle_timeout, hard_timeout, priority,
+         cookie) = struct.unpack_from(ofproto.OFP_FLOW_UPDATE_FULL_0_PACK_STR,
+                                      buf, offset)
+        offset += ofproto.OFP_FLOW_UPDATE_FULL_0_SIZE
+        assert cls.cls_flow_update_length <= length
+        assert cls.cls_flow_update_event == event
+
+        match = OFPMatch.parser(buf, offset)
+        match_length = utils.round_up(match.length, 8)
+        offset += match_length
+
+        inst_length = (length - ofproto.OFP_FLOW_UPDATE_FULL_0_SIZE -
+                       match_length)
+        instructions = []
+        while inst_length > 0:
+            inst = OFPInstruction.parser(buf, offset)
+            instructions.append(inst)
+            offset += inst.len
+            inst_length -= inst.len
+
+        return cls(length, event, table_id, reason, idle_timeout,
+                   hard_timeout, priority, cookie, match, instructions)
+
+
+@OFPFlowUpdateHeader.register_flow_update_event(
+    ofproto.OFPFME_ABBREV, ofproto.OFP_FLOW_UPDATE_ABBREV_SIZE)
+class OFPFlowUpdateAbbrev(OFPFlowUpdateHeader):
+    def __init__(self, length=None, event=None, xid=None):
+        super(OFPFlowUpdateAbbrev, self).__init__(length, event)
+        self.xid = xid
+
+    @classmethod
+    def parser(cls, buf, offset):
+        length, event, xid = struct.unpack_from(
+            ofproto.OFP_FLOW_UPDATE_ABBREV_PACK_STR, buf, offset)
+        assert cls.cls_flow_update_length == length
+        assert cls.cls_flow_update_event == event
+
+        return cls(length, event, xid)
+
+
+@OFPFlowUpdateHeader.register_flow_update_event(
+    ofproto.OFPFME_PAUSED, ofproto.OFP_FLOW_UPDATE_PAUSED_SIZE)
+@OFPFlowUpdateHeader.register_flow_update_event(
+    ofproto.OFPFME_RESUMED, ofproto.OFP_FLOW_UPDATE_PAUSED_SIZE)
+class OFPFlowUpdatePaused(OFPFlowUpdateHeader):
+    @classmethod
+    def parser(cls, buf, offset):
+        length, event = struct.unpack_from(
+            ofproto.OFP_FLOW_UPDATE_PAUSED_PACK_STR, buf, offset)
+        assert cls.cls_flow_update_length == length
+        assert cls.cls_flow_update_event == event
+
+        return cls(length, event)
+
+
+class OFPFlowMonitorRequestBase(OFPMultipartRequest):
+    def __init__(self, datapath, flags, monitor_id, out_port, out_group,
+                 monitor_flags, table_id, command, match):
+        super(OFPFlowMonitorRequestBase, self).__init__(datapath, flags)
+        self.monitor_id = monitor_id
+        self.out_port = out_port
+        self.out_group = out_group
+        self.monitor_flags = monitor_flags
+        self.table_id = table_id
+        self.command = command
+        self.match = match
+
+    def _serialize_stats_body(self):
+        offset = ofproto.OFP_MULTIPART_REQUEST_SIZE
+        msg_pack_into(ofproto.OFP_FLOW_MONITOR_REQUEST_0_PACK_STR, self.buf,
+                      offset, self.monitor_id, self.out_port, self.out_group,
+                      self.monitor_flags, self.table_id, self.command)
+
+        offset += ofproto.OFP_FLOW_MONITOR_REQUEST_0_SIZE
+        self.match.serialize(self.buf, offset)
+
+
+@_set_stats_type(ofproto.OFPMP_FLOW_MONITOR, OFPFlowUpdateHeader)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
+class OFPFlowMonitorRequest(OFPFlowMonitorRequestBase):
+    """
+    Flow monitor request message
+
+    The controller uses this message to query flow monitors.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    flags            Zero or ``OFPMPF_REQ_MORE``
+    monitor_id       Controller-assigned ID for this monitor
+    out_port         Require matching entries to include this as an output
+                     port
+    out_group        Require matching entries to include this as an output
+                     group
+    monitor_flags    Bitmap of the following flags.
+
+                     | OFPFMF_INITIAL
+                     | OFPFMF_ADD
+                     | OFPFMF_REMOVED
+                     | OFPFMF_MODIFY
+                     | OFPFMF_INSTRUCTIONS
+                     | OFPFMF_NO_ABBREV
+                     | OFPFMF_ONLY_OWN
+    table_id         ID of table to monitor
+    command          One of the following values.
+
+                     | OFPFMC_ADD
+                     | OFPFMC_MODIFY
+                     | OFPFMC_DELETE
+    match            Instance of ``OFPMatch``
+    ================ ======================================================
+
+    Example::
+
+        def send_flow_monitor_request(self, datapath):
+            ofp = datapath.ofproto
+            ofp_parser = datapath.ofproto_parser
+
+            monitor_flags = [ofp.OFPFMF_INITIAL, ofp.OFPFMF_ONLY_OWN]
+            match = ofp_parser.OFPMatch(in_port=1)
+            req = ofp_parser.OFPFlowMonitorRequest(datapath, 0, 10000,
+                                                   ofp.OFPP_ANY, ofp.OFPG_ANY,
+                                                   monitor_flags,
+                                                   ofp.OFPTT_ALL,
+                                                   ofp.OFPFMC_ADD, match)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, flags=0, monitor_id=0,
+                 out_port=ofproto.OFPP_ANY, out_group=ofproto.OFPG_ANY,
+                 monitor_flags=0, table_id=ofproto.OFPTT_ALL,
+                 command=ofproto.OFPFMC_ADD, match=None, type_=None):
+        if match is None:
+            match = OFPMatch()
+        super(OFPFlowMonitorRequest, self).__init__(datapath, flags,
+                                                    monitor_id, out_port,
+                                                    out_group, monitor_flags,
+                                                    table_id, command, match)
+
+
+@OFPMultipartReply.register_stats_type()
+@_set_stats_type(ofproto.OFPMP_FLOW_MONITOR, OFPFlowUpdateHeader)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
+class OFPFlowMonitorReply(OFPMultipartReply):
+    """
+    Flow monitor reply message
+
+    The switch responds with this message to a flow monitor request.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    body             List of list of the following class instance.
+
+                     | OFPFlowMonitorFull
+                     | OFPFlowMonitorAbbrev
+                     | OFPFlowMonitorPaused
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPFlowMonitorReply, MAIN_DISPATCHER)
+        def flow_monitor_reply_handler(self, ev):
+            msg = ev.msg
+            dp = msg.datapath
+            ofp = dp.ofproto
+            flow_updates = []
+
+            for update in msg.body:
+                update_str = 'length=%d event=%d' %
+                             (update.length, update.event)
+                if (update.event == ofp.OFPFME_INITIAL or
+                    update.event == ofp.OFPFME_ADDED or
+                    update.event == ofp.OFPFME_REMOVED or
+                    update.event == ofp.OFPFME_MODIFIED):
+                    update_str += 'table_id=%d reason=%d idle_timeout=%d '
+                                  'hard_timeout=%d priority=%d cookie=%d '
+                                  'match=%d instructions=%s' %
+                                  (update.table_id, update.reason,
+                                   update.idle_timeout, update.hard_timeout,
+                                   update.priority, update.cookie,
+                                   update.match, update.instructions)
+                elif update.event == ofp.OFPFME_ABBREV:
+                    update_str += 'xid=%d' % (update.xid)
+                flow_updates.append(update_str)
+            self.logger.debug('FlowUpdates: %s', flow_updates)
+    """
+
+    def __init__(self, datapath, type_=None, **kwargs):
+        super(OFPFlowMonitorReply, self).__init__(datapath, **kwargs)
+
+
+class OFPExperimenterMultipart(ofproto_parser.namedtuple(
+                               'OFPExperimenterMultipart',
+                               ('experimenter', 'exp_type', 'data'))):
+    """
+    The body of OFPExperimenterStatsReply multipart messages.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    experimenter     Experimenter ID
+    exp_type         Experimenter defined
+    data             Experimenter defined additional data
+    ================ ======================================================
+    """
+
+    @classmethod
+    def parser(cls, buf, offset):
+        args = struct.unpack_from(
+            ofproto.OFP_EXPERIMENTER_MULTIPART_HEADER_PACK_STR, buf,
+            offset)
+        args = list(args)
+        args.append(buf[offset +
+                        ofproto.OFP_EXPERIMENTER_MULTIPART_HEADER_SIZE:])
+        stats = cls(*args)
+        stats.length = ofproto.OFP_METER_FEATURES_SIZE
+        return stats
+
+    def serialize(self):
+        buf = bytearray()
+        msg_pack_into(ofproto.OFP_EXPERIMENTER_MULTIPART_HEADER_PACK_STR,
+                      buf, 0,
+                      self.experimenter, self.exp_type)
+        return buf + self.data
+
+
+class OFPExperimenterStatsRequestBase(OFPMultipartRequest):
+    def __init__(self, datapath, flags,
+                 experimenter, exp_type,
+                 type_=None):
+        super(OFPExperimenterStatsRequestBase, self).__init__(datapath, flags)
+        self.experimenter = experimenter
+        self.exp_type = exp_type
+
+
+@_set_stats_type(ofproto.OFPMP_EXPERIMENTER, OFPExperimenterMultipart)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
+class OFPExperimenterStatsRequest(OFPExperimenterStatsRequestBase):
+    """
+    Experimenter multipart request message
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    flags            Zero or ``OFPMPF_REQ_MORE``
+    experimenter     Experimenter ID
+    exp_type         Experimenter defined
+    data             Experimenter defined additional data
+    ================ ======================================================
+    """
+
+    def __init__(self, datapath, flags,
+                 experimenter, exp_type, data,
+                 type_=None):
+        super(OFPExperimenterStatsRequest, self).__init__(datapath, flags,
+                                                          experimenter,
+                                                          exp_type, type_)
+        self.data = data
+
+    def _serialize_stats_body(self):
+        body = OFPExperimenterMultipart(experimenter=self.experimenter,
+                                        exp_type=self.exp_type,
+                                        data=self.data)
+        self.buf += body.serialize()
+
+
+@OFPMultipartReply.register_stats_type(body_single_struct=True)
+@_set_stats_type(ofproto.OFPMP_EXPERIMENTER, OFPExperimenterMultipart)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
+class OFPExperimenterStatsReply(OFPMultipartReply):
+    """
+    Experimenter multipart reply message
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    body             An ``OFPExperimenterMultipart`` instance
+    ================ ======================================================
+    """
+
+    def __init__(self, datapath, type_=None, **kwargs):
+        super(OFPExperimenterStatsReply, self).__init__(datapath, **kwargs)
+
+
+class OFPFlowStats(StringifyMixin):
+    def __init__(self, table_id=None, duration_sec=None, duration_nsec=None,
+                 priority=None, idle_timeout=None, hard_timeout=None,
+                 flags=None, importance=None, cookie=None, packet_count=None,
+                 byte_count=None, match=None, instructions=None,
+                 length=None):
+        super(OFPFlowStats, self).__init__()
+        self.table_id = table_id
+        self.duration_sec = duration_sec
+        self.duration_nsec = duration_nsec
+        self.priority = priority
+        self.idle_timeout = idle_timeout
+        self.hard_timeout = hard_timeout
+        self.flags = flags
+        self.importance = importance
+        self.cookie = cookie
+        self.packet_count = packet_count
+        self.byte_count = byte_count
+        self.match = match
+        self.instructions = instructions
+        self.length = length
+
+    @classmethod
+    def parser(cls, buf, offset):
+        flow_stats = cls()
+
+        (flow_stats.length, flow_stats.table_id,
+         flow_stats.duration_sec, flow_stats.duration_nsec,
+         flow_stats.priority, flow_stats.idle_timeout,
+         flow_stats.hard_timeout, flow_stats.flags,
+         flow_stats.importance, flow_stats.cookie,
+         flow_stats.packet_count,
+         flow_stats.byte_count) = struct.unpack_from(
+            ofproto.OFP_FLOW_STATS_0_PACK_STR, buf, offset)
+        offset += ofproto.OFP_FLOW_STATS_0_SIZE
+
+        flow_stats.match = OFPMatch.parser(buf, offset)
+        match_length = utils.round_up(flow_stats.match.length, 8)
+        inst_length = (flow_stats.length - (ofproto.OFP_FLOW_STATS_SIZE -
+                                            ofproto.OFP_MATCH_SIZE +
+                                            match_length))
+        offset += match_length
+        instructions = []
+        while inst_length > 0:
+            inst = OFPInstruction.parser(buf, offset)
+            instructions.append(inst)
+            offset += inst.len
+            inst_length -= inst.len
+
+        flow_stats.instructions = instructions
+        return flow_stats
+
+
+class OFPFlowStatsRequestBase(OFPMultipartRequest):
+    def __init__(self, datapath, flags, table_id, out_port, out_group,
+                 cookie, cookie_mask, match):
+        super(OFPFlowStatsRequestBase, self).__init__(datapath, flags)
+        self.table_id = table_id
+        self.out_port = out_port
+        self.out_group = out_group
+        self.cookie = cookie
+        self.cookie_mask = cookie_mask
+        self.match = match
+
+    def _serialize_stats_body(self):
+        offset = ofproto.OFP_MULTIPART_REQUEST_SIZE
+        msg_pack_into(ofproto.OFP_FLOW_STATS_REQUEST_0_PACK_STR,
+                      self.buf, offset, self.table_id, self.out_port,
+                      self.out_group, self.cookie, self.cookie_mask)
+
+        offset += ofproto.OFP_FLOW_STATS_REQUEST_0_SIZE
+        self.match.serialize(self.buf, offset)
+
+
+@_set_stats_type(ofproto.OFPMP_FLOW, OFPFlowStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
+class OFPFlowStatsRequest(OFPFlowStatsRequestBase):
+    """
+    Individual flow statistics request message
+
+    The controller uses this message to query individual flow statistics.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    flags            Zero or ``OFPMPF_REQ_MORE``
+    table_id         ID of table to read
+    out_port         Require matching entries to include this as an output
+                     port
+    out_group        Require matching entries to include this as an output
+                     group
+    cookie           Require matching entries to contain this cookie value
+    cookie_mask      Mask used to restrict the cookie bits that must match
+    match            Instance of ``OFPMatch``
+    ================ ======================================================
+
+    Example::
+
+        def send_flow_stats_request(self, datapath):
+            ofp = datapath.ofproto
+            ofp_parser = datapath.ofproto_parser
+
+            cookie = cookie_mask = 0
+            match = ofp_parser.OFPMatch(in_port=1)
+            req = ofp_parser.OFPFlowStatsRequest(datapath, 0,
+                                                 ofp.OFPTT_ALL,
+                                                 ofp.OFPP_ANY, ofp.OFPG_ANY,
+                                                 cookie, cookie_mask,
+                                                 match)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, flags=0, table_id=ofproto.OFPTT_ALL,
+                 out_port=ofproto.OFPP_ANY,
+                 out_group=ofproto.OFPG_ANY,
+                 cookie=0, cookie_mask=0, match=None, type_=None):
+        if match is None:
+            match = OFPMatch()
+        super(OFPFlowStatsRequest, self).__init__(datapath, flags, table_id,
+                                                  out_port, out_group,
+                                                  cookie, cookie_mask, match)
+
+
+@OFPMultipartReply.register_stats_type()
+@_set_stats_type(ofproto.OFPMP_FLOW, OFPFlowStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
+class OFPFlowStatsReply(OFPMultipartReply):
+    """
+    Individual flow statistics reply message
+
+    The switch responds with this message to an individual flow statistics
+    request.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    body             List of ``OFPFlowStats`` instance
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
+        def flow_stats_reply_handler(self, ev):
+            flows = []
+            for stat in ev.msg.body:
+                flows.append('table_id=%s '
+                             'duration_sec=%d duration_nsec=%d '
+                             'priority=%d '
+                             'idle_timeout=%d hard_timeout=%d flags=0x%04x '
+                             'importance=%d cookie=%d packet_count=%d '
+                             'byte_count=%d match=%s instructions=%s' %
+                             (stat.table_id,
+                              stat.duration_sec, stat.duration_nsec,
+                              stat.priority,
+                              stat.idle_timeout, stat.hard_timeout,
+                              stat.flags, stat.importance,
+                              stat.cookie, stat.packet_count, stat.byte_count,
+                              stat.match, stat.instructions))
+            self.logger.debug('FlowStats: %s', flows)
+    """
+
+    def __init__(self, datapath, type_=None, **kwargs):
+        super(OFPFlowStatsReply, self).__init__(datapath, **kwargs)
+
+
+class OFPAggregateStats(ofproto_parser.namedtuple('OFPAggregateStats', (
+        'packet_count', 'byte_count', 'flow_count'))):
+    @classmethod
+    def parser(cls, buf, offset):
+        agg = struct.unpack_from(
+            ofproto.OFP_AGGREGATE_STATS_REPLY_PACK_STR, buf, offset)
+        stats = cls(*agg)
+        stats.length = ofproto.OFP_AGGREGATE_STATS_REPLY_SIZE
+        return stats
+
+
+@_set_stats_type(ofproto.OFPMP_AGGREGATE, OFPAggregateStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
+class OFPAggregateStatsRequest(OFPFlowStatsRequestBase):
+    """
+    Aggregate flow statistics request message
+
+    The controller uses this message to query aggregate flow statictics.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    flags            Zero or ``OFPMPF_REQ_MORE``
+    table_id         ID of table to read
+    out_port         Require matching entries to include this as an output
+                     port
+    out_group        Require matching entries to include this as an output
+                     group
+    cookie           Require matching entries to contain this cookie value
+    cookie_mask      Mask used to restrict the cookie bits that must match
+    match            Instance of ``OFPMatch``
+    ================ ======================================================
+
+    Example::
+
+        def send_aggregate_stats_request(self, datapath):
+            ofp = datapath.ofproto
+            ofp_parser = datapath.ofproto_parser
+
+            cookie = cookie_mask = 0
+            match = ofp_parser.OFPMatch(in_port=1)
+            req = ofp_parser.OFPAggregateStatsRequest(datapath, 0,
+                                                      ofp.OFPTT_ALL,
+                                                      ofp.OFPP_ANY,
+                                                      ofp.OFPG_ANY,
+                                                      cookie, cookie_mask,
+                                                      match)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, flags, table_id, out_port, out_group,
+                 cookie, cookie_mask, match, type_=None):
+        super(OFPAggregateStatsRequest, self).__init__(datapath,
+                                                       flags,
+                                                       table_id,
+                                                       out_port,
+                                                       out_group,
+                                                       cookie,
+                                                       cookie_mask,
+                                                       match)
+
+
+@OFPMultipartReply.register_stats_type(body_single_struct=True)
+@_set_stats_type(ofproto.OFPMP_AGGREGATE, OFPAggregateStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
+class OFPAggregateStatsReply(OFPMultipartReply):
+    """
+    Aggregate flow statistics reply message
+
+    The switch responds with this message to an aggregate flow statistics
+    request.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    body             Instance of ``OFPAggregateStats``
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPAggregateStatsReply, MAIN_DISPATCHER)
+        def aggregate_stats_reply_handler(self, ev):
+            body = ev.msg.body
+
+            self.logger.debug('AggregateStats: packet_count=%d byte_count=%d '
+                              'flow_count=%d',
+                              body.packet_count, body.byte_count,
+                              body.flow_count)
+    """
+
+    def __init__(self, datapath, type_=None, **kwargs):
+        super(OFPAggregateStatsReply, self).__init__(datapath, **kwargs)
+
+
+class OFPTableStats(ofproto_parser.namedtuple('OFPTableStats', (
+        'table_id', 'active_count', 'lookup_count',
+        'matched_count'))):
+    @classmethod
+    def parser(cls, buf, offset):
+        tbl = struct.unpack_from(ofproto.OFP_TABLE_STATS_PACK_STR,
+                                 buf, offset)
+        stats = cls(*tbl)
+        stats.length = ofproto.OFP_TABLE_STATS_SIZE
+        return stats
+
+
+@_set_stats_type(ofproto.OFPMP_TABLE, OFPTableStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
+class OFPTableStatsRequest(OFPMultipartRequest):
+    """
+    Table statistics request message
+
+    The controller uses this message to query flow table statictics.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    flags            Zero or ``OFPMPF_REQ_MORE``
+    ================ ======================================================
+
+    Example::
+
+        def send_table_stats_request(self, datapath):
+            ofp_parser = datapath.ofproto_parser
+
+            req = ofp_parser.OFPTableStatsRequest(datapath, 0)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, flags, type_=None):
+        super(OFPTableStatsRequest, self).__init__(datapath, flags)
+
+
+@OFPMultipartReply.register_stats_type()
+@_set_stats_type(ofproto.OFPMP_TABLE, OFPTableStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
+class OFPTableStatsReply(OFPMultipartReply):
+    """
+    Table statistics reply message
+
+    The switch responds with this message to a table statistics request.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    body             List of ``OFPTableStats`` instance
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPTableStatsReply, MAIN_DISPATCHER)
+        def table_stats_reply_handler(self, ev):
+            tables = []
+            for stat in ev.msg.body:
+                tables.append('table_id=%d active_count=%d lookup_count=%d '
+                              ' matched_count=%d' %
+                              (stat.table_id, stat.active_count,
+                               stat.lookup_count, stat.matched_count))
+            self.logger.debug('TableStats: %s', tables)
+    """
+
+    def __init__(self, datapath, type_=None, **kwargs):
+        super(OFPTableStatsReply, self).__init__(datapath, **kwargs)
+
+
+class OFPPortStatsProp(OFPPropBase):
+    _TYPES = {}
+
+
+@OFPPortStatsProp.register_type(ofproto.OFPPSPT_ETHERNET)
+class OFPPortStatsPropEthernet(OFPPortStatsProp):
+    def __init__(self, type_=None, length=None, rx_frame_err=None,
+                 rx_over_err=None, rx_crc_err=None, collisions=None):
+        self.type = type_
+        self.length = length
+        self.rx_frame_err = rx_frame_err
+        self.rx_over_err = rx_over_err
+        self.rx_crc_err = rx_crc_err
+        self.collisions = collisions
+
+    @classmethod
+    def parser(cls, buf):
+        ether = cls()
+        (ether.type, ether.length, ether.rx_frame_err, ether.rx_over_err,
+         ether.rx_crc_err, ether.collisions) = struct.unpack_from(
+            ofproto.OFP_PORT_STATS_PROP_ETHERNET_PACK_STR, buf, 0)
+        return ether
+
+
+@OFPPortStatsProp.register_type(ofproto.OFPPSPT_OPTICAL)
+class OFPPortStatsPropOptical(OFPPortStatsProp):
+    def __init__(self, type_=None, length=None, flags=None,
+                 tx_freq_lmda=None, tx_offset=None, tx_grid_span=None,
+                 rx_freq_lmda=None, rx_offset=None, rx_grid_span=None,
+                 tx_pwr=None, rx_pwr=None, bias_current=None,
+                 temperature=None):
+        self.type = type_
+        self.length = length
+        self.flags = flags
+        self.tx_freq_lmda = tx_freq_lmda
+        self.tx_offset = tx_offset
+        self.tx_grid_span = tx_grid_span
+        self.rx_freq_lmda = rx_freq_lmda
+        self.rx_offset = rx_offset
+        self.rx_grid_span = rx_grid_span
+        self.tx_pwr = tx_pwr
+        self.rx_pwr = rx_pwr
+        self.bias_current = bias_current
+        self.temperature = temperature
+
+    @classmethod
+    def parser(cls, buf):
+        optical = cls()
+        (optical.type, optical.length, optical.flags,
+         optical.tx_freq_lmda, optical.tx_offset, optical.tx_grid_span,
+         optical.rx_freq_lmda, optical.rx_offset, optical.rx_grid_span,
+         optical.tx_pwr, optical.rx_pwr, optical.bias_current,
+         optical.temperature) = struct.unpack_from(
+            ofproto.OFP_PORT_STATS_PROP_OPTICAL_PACK_STR, buf, 0)
+        return optical
+
+
+@OFPPortStatsProp.register_type(ofproto.OFPPSPT_EXPERIMENTER)
+class OFPPortStatsPropExperimenter(OFPPropCommonExperimenter4ByteData):
+    pass
+
+
+class OFPPortStats(StringifyMixin):
+    def __init__(self, length=None, port_no=None, duration_sec=None,
+                 duration_nsec=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,
+                 properties=None):
+        super(OFPPortStats, self).__init__()
+        self.length = length
+        self.port_no = port_no
+        self.duration_sec = duration_sec
+        self.duration_nsec = duration_nsec
+        self.rx_packets = rx_packets
+        self.tx_packets = tx_packets
+        self.rx_bytes = rx_bytes
+        self.tx_bytes = tx_bytes
+        self.rx_dropped = rx_dropped
+        self.tx_dropped = tx_dropped
+        self.rx_errors = rx_errors
+        self.tx_errors = tx_errors
+        self.properties = properties
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (length, port_no, duration_sec, duration_nsec, rx_packets,
+         tx_packets, rx_bytes, tx_bytes, rx_dropped, tx_dropped,
+         rx_errors, tx_errors) = struct.unpack_from(
+            ofproto.OFP_PORT_STATS_PACK_STR, buf, offset)
+        props = []
+        rest = buf[offset + ofproto.OFP_PORT_STATS_SIZE:offset + length]
+        while rest:
+            p, rest = OFPPortStatsProp.parse(rest)
+            props.append(p)
+        stats = cls(length, port_no, duration_sec, duration_nsec, rx_packets,
+                    tx_packets, rx_bytes, tx_bytes, rx_dropped, tx_dropped,
+                    rx_errors, tx_errors, props)
+        return stats
+
+
+@_set_stats_type(ofproto.OFPMP_PORT_STATS, OFPPortStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
+class OFPPortStatsRequest(OFPMultipartRequest):
+    """
+    Port statistics request message
+
+    The controller uses this message to query information about ports
+    statistics.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    flags            Zero or ``OFPMPF_REQ_MORE``
+    port_no          Port number to read (OFPP_ANY to all ports)
+    ================ ======================================================
+
+    Example::
+
+        def send_port_stats_request(self, datapath):
+            ofp = datapath.ofproto
+            ofp_parser = datapath.ofproto_parser
+
+            req = ofp_parser.OFPPortStatsRequest(datapath, 0, ofp.OFPP_ANY)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, flags, port_no, type_=None):
+        super(OFPPortStatsRequest, self).__init__(datapath, flags)
+        self.port_no = port_no
+
+    def _serialize_stats_body(self):
+        msg_pack_into(ofproto.OFP_PORT_STATS_REQUEST_PACK_STR,
+                      self.buf,
+                      ofproto.OFP_MULTIPART_REQUEST_SIZE,
+                      self.port_no)
+
+
+@OFPMultipartReply.register_stats_type()
+@_set_stats_type(ofproto.OFPMP_PORT_STATS, OFPPortStats)
+@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
+class OFPPortStatsReply(OFPMultipartReply):
+    """
+    Port statistics reply message
+
+    The switch responds with this message to a port statistics request.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    body             List of ``OFPPortStats`` instance
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER)
+        def port_stats_reply_handler(self, ev):
+            ports = []
+            for stat in ev.msg.body:
+                ports.append(stat.length, stat.port_no,
+                             stat.duration_sec, stat.duration_nsec,
+                             stat.rx_packets, stat.tx_packets,
+                             stat.rx_bytes, stat.tx_bytes,
+                             stat.rx_dropped, stat.tx_dropped,
+                             stat.rx_errors, stat.tx_errors,
+                             repr(stat.properties))
+            self.logger.debug('PortStats: %s', ports)
+    """
+
+    def __init__(self, datapath, type_=None, **kwargs):
+        super(OFPPortStatsReply, self).__init__(datapath, **kwargs)
+
+
+@_set_msg_type(ofproto.OFPT_BARRIER_REQUEST)
+class OFPBarrierRequest(MsgBase):
+    """
+    Barrier request message
+
+    The controller sends this message to ensure message dependencies have
+    been met or receive notifications for completed operations.
+
+    Example::
+
+        def send_barrier_request(self, datapath):
+            ofp_parser = datapath.ofproto_parser
+
+            req = ofp_parser.OFPBarrierRequest(datapath)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath):
+        super(OFPBarrierRequest, self).__init__(datapath)
+
+
+@_register_parser
+@_set_msg_type(ofproto.OFPT_BARRIER_REPLY)
+class OFPBarrierReply(MsgBase):
+    """
+    Barrier reply message
+
+    The switch responds with this message to a barrier request.
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPBarrierReply, MAIN_DISPATCHER)
+        def barrier_reply_handler(self, ev):
+            self.logger.debug('OFPBarrierReply received')
+    """
+
+    def __init__(self, datapath):
+        super(OFPBarrierReply, self).__init__(datapath)
+
+
+@_register_parser
+@_set_msg_type(ofproto.OFPT_PORT_STATUS)
+class OFPPortStatus(MsgBase):
+    """
+    Port status message
+
+    The switch notifies controller of change of ports.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    reason           One of the following values.
+
+                     | OFPPR_ADD
+                     | OFPPR_DELETE
+                     | OFPPR_MODIFY
+    desc             instance of ``OFPPort``
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPPortStatus, MAIN_DISPATCHER)
+        def port_status_handler(self, ev):
+            msg = ev.msg
+            dp = msg.datapath
+            ofp = dp.ofproto
+
+            if msg.reason == ofp.OFPPR_ADD:
+                reason = 'ADD'
+            elif msg.reason == ofp.OFPPR_DELETE:
+                reason = 'DELETE'
+            elif msg.reason == ofp.OFPPR_MODIFY:
+                reason = 'MODIFY'
+            else:
+                reason = 'unknown'
+
+            self.logger.debug('OFPPortStatus received: reason=%s desc=%s',
+                              reason, msg.desc)
+    """
+
+    def __init__(self, datapath, reason=None, desc=None):
+        super(OFPPortStatus, self).__init__(datapath)
+        self.reason = reason
+        self.desc = desc
+
+    @classmethod
+    def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+        msg = super(OFPPortStatus, cls).parser(datapath, version, msg_type,
+                                               msg_len, xid, buf)
+        msg.reason = struct.unpack_from(
+            ofproto.OFP_PORT_STATUS_PACK_STR, msg.buf,
+            ofproto.OFP_HEADER_SIZE)[0]
+        msg.desc = OFPPort.parser(msg.buf, ofproto.OFP_PORT_STATUS_DESC_OFFSET)
+        return msg
+
+
+@_register_parser
+@_set_msg_type(ofproto.OFPT_ROLE_STATUS)
+class OFPRoleStatus(MsgBase):
+    """
+    Role status message
+
+    The switch notifies controller of change of role.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    role             One of the following values.
+
+                     | OFPCR_ROLE_NOCHANGE
+                     | OFPCR_ROLE_EQUAL
+                     | OFPCR_ROLE_MASTER
+    reason           One of the following values.
+
+                     | OFPCRR_MASTER_REQUEST
+                     | OFPCRR_CONFIG
+                     | OFPCRR_EXPERIMENTER
+    generation_id    Master Election Generation ID
+    properties       List of ``OFPRoleProp`` subclass instance
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPRoleStatus, MAIN_DISPATCHER)
+        def role_status_handler(self, ev):
+            msg = ev.msg
+            dp = msg.datapath
+            ofp = dp.ofproto
+
+            if msg.role == ofp.OFPCR_ROLE_NOCHANGE:
+                role = 'ROLE NOCHANGE'
+            elif msg.role == ofp.OFPCR_ROLE_EQUAL:
+                role = 'ROLE EQUAL'
+            elif msg.role == ofp.OFPCR_ROLE_MASTER:
+                role = 'ROLE MASTER'
+            else:
+                role = 'unknown'
+
+            if msg.reason == ofp.OFPCRR_MASTER_REQUEST:
+                reason = 'MASTER REQUEST'
+            elif msg.reason == ofp.OFPCRR_CONFIG:
+                reason = 'CONFIG'
+            elif msg.reason == ofp.OFPCRR_EXPERIMENTER:
+                reason = 'EXPERIMENTER'
+            else:
+                reason = 'unknown'
+
+            self.logger.debug('OFPRoleStatus received: role=%s reason=%s '
+                              'generation_id=%d properties=%s', role, reason,
+                              msg.generation_id, repr(msg.properties))
+    """
+
+    def __init__(self, datapath, role=None, reason=None,
+                 generation_id=None, properties=None):
+        super(OFPRoleStatus, self).__init__(datapath)
+        self.role = role
+        self.reason = reason
+        self.generation_id = generation_id
+        self.properties = properties
+
+    @classmethod
+    def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+        msg = super(OFPRoleStatus, cls).parser(datapath, version, msg_type,
+                                               msg_len, xid, buf)
+        (msg.role, msg.reason, msg.generation_id) = struct.unpack_from(
+            ofproto.OFP_ROLE_STATUS_PACK_STR, msg.buf,
+            ofproto.OFP_HEADER_SIZE)
+
+        msg.properties = []
+        rest = msg.buf[ofproto.OFP_ROLE_STATUS_SIZE:]
+        while rest:
+            p, rest = OFPRoleProp.parse(rest)
+            msg.properties.append(p)
+
+        return msg
+
+
+@_register_parser
+@_set_msg_type(ofproto.OFPT_TABLE_STATUS)
+class OFPTableStatus(MsgBase):
+    """
+    Table status message
+
+    The switch notifies controller of change of table status.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    reason           One of the following values.
+
+                     | OFPTR_VACANCY_DOWN
+                     | OFPTR_VACANCY_UP
+    table            ``OFPTableDesc`` instance
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPTableStatus, MAIN_DISPATCHER)
+        def table(self, ev):
+            msg = ev.msg
+            dp = msg.datapath
+            ofp = dp.ofproto
+
+            if msg.reason == ofp.OFPTR_VACANCY_DOWN:
+                reason = 'VACANCY_DOWN'
+            elif msg.reason == ofp.OFPTR_VACANCY_UP:
+                reason = 'VACANCY_UP'
+            else:
+                reason = 'unknown'
+
+            self.logger.debug('OFPTableStatus received: reason=%s '
+                              'table_id=%d config=0x%08x properties=%s',
+                              reason, msg.table.table_id, msg.table.config,
+                              repr(msg.table.properties))
+    """
+
+    def __init__(self, datapath, reason=None, table=None):
+        super(OFPTableStatus, self).__init__(datapath)
+        self.reason = reason
+        self.table = table
+
+    @classmethod
+    def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+        msg = super(OFPTableStatus, cls).parser(datapath, version, msg_type,
+                                                msg_len, xid, buf)
+        (msg.reason,) = struct.unpack_from(ofproto.OFP_TABLE_STATUS_0_PACK_STR,
+                                           msg.buf, ofproto.OFP_HEADER_SIZE)
+
+        msg.table = OFPTableDesc.parser(msg.buf,
+                                        ofproto.OFP_TABLE_STATUS_0_SIZE)
+
+        return msg
+
+
+@_register_parser
+@_set_msg_type(ofproto.OFPT_REQUESTFORWARD)
+class OFPRequestForward(MsgInMsgBase):
+    """
+    Forwarded request message
+
+    The swtich forwards request messages from one controller to other
+    controllers.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    request          ``OFPGroupMod`` or ``OFPMeterMod`` instance
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPRequestForward, MAIN_DISPATCHER)
+        def request_forward_handler(self, ev):
+            msg = ev.msg
+            dp = msg.datapath
+            ofp = dp.ofproto
+
+            if msg.request.msg_type == ofp.OFPT_GROUP_MOD:
+                self.logger.debug(
+                    'OFPRequestForward received: request=OFPGroupMod('
+                    'command=%d, type=%d, group_id=%d, buckets=%s)',
+                    msg.request.command, msg.request.type,
+                    msg.request.group_id, msg.request.buckets)
+            elif msg.request.msg_type == ofp.OFPT_METER_MOD:
+                self.logger.debug(
+                    'OFPRequestForward received: request=OFPMeterMod('
+                    'command=%d, flags=%d, meter_id=%d, bands=%s)',
+                    msg.request.command, msg.request.flags,
+                    msg.request.meter_id, msg.request.bands)
+            else:
+                self.logger.debug(
+                    'OFPRequestForward received: request=Unknown')
+    """
+
+    def __init__(self, datapath, request=None):
+        super(OFPRequestForward, self).__init__(datapath)
+        self.request = request
+
+    @classmethod
+    def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+        msg = super(OFPRequestForward, cls).parser(
+            datapath, version, msg_type, msg_len, xid, buf)
+        req_buf = buf[ofproto.OFP_HEADER_SIZE:]
+        (_ver, _type, _len, _xid) = ofproto_parser.header(req_buf)
+        msg.request = ofproto_parser.msg(
+            datapath, _ver, _type, _len, _xid, req_buf)
+        return msg
+
+    def _serialize_body(self):
+        assert isinstance(self.request, (OFPGroupMod, OFPMeterMod))
+        self.request.serialize()
+        self.buf += self.request.buf
+
+
+@_set_msg_type(ofproto.OFPT_PACKET_OUT)
+class OFPPacketOut(MsgBase):
+    """
+    Packet-Out message
+
+    The controller uses this message to send a packet out throught the
+    switch.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    buffer_id        ID assigned by datapath (OFP_NO_BUFFER if none)
+    in_port          Packet's input port or ``OFPP_CONTROLLER``
+    actions          list of OpenFlow action class
+    data             Packet data of a binary type value or
+                     an instances of packet.Packet.
+    ================ ======================================================
+
+    Example::
+
+        def send_packet_out(self, datapath, buffer_id, in_port):
+            ofp = datapath.ofproto
+            ofp_parser = datapath.ofproto_parser
+
+            actions = [ofp_parser.OFPActionOutput(ofp.OFPP_FLOOD, 0)]
+            req = ofp_parser.OFPPacketOut(datapath, buffer_id,
+                                          in_port, actions)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, buffer_id=None, in_port=None, actions=None,
+                 data=None, actions_len=None):
+        assert in_port is not None
+
+        super(OFPPacketOut, self).__init__(datapath)
+        self.buffer_id = buffer_id
+        self.in_port = in_port
+        self.actions_len = 0
+        self.actions = actions
+        self.data = data
+
+    def _serialize_body(self):
+        self.actions_len = 0
+        offset = ofproto.OFP_PACKET_OUT_SIZE
+        for a in self.actions:
+            a.serialize(self.buf, offset)
+            offset += a.len
+            self.actions_len += a.len
+
+        if self.data is not None:
+            assert self.buffer_id == 0xffffffff
+            if isinstance(self.data, packet.Packet):
+                self.data.serialize()
+                self.buf += self.data.data
+            else:
+                self.buf += self.data
+
+        msg_pack_into(ofproto.OFP_PACKET_OUT_PACK_STR,
+                      self.buf, ofproto.OFP_HEADER_SIZE,
+                      self.buffer_id, self.in_port, self.actions_len)
+
+    @classmethod
+    def from_jsondict(cls, dict_, decode_string=base64.b64decode,
+                      **additional_args):
+        if isinstance(dict_['data'], dict):
+            data = dict_.pop('data')
+            ins = super(OFPPacketOut, cls).from_jsondict(dict_,
+                                                         decode_string,
+                                                         **additional_args)
+            ins.data = packet.Packet.from_jsondict(data['Packet'])
+            dict_['data'] = data
+        else:
+            ins = super(OFPPacketOut, cls).from_jsondict(dict_,
+                                                         decode_string,
+                                                         **additional_args)
+
+        return ins
+
+
+@_register_parser
+@_set_msg_type(ofproto.OFPT_FLOW_MOD)
+class OFPFlowMod(MsgBase):
+    """
+    Modify Flow entry message
+
+    The controller sends this message to modify the flow table.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    cookie           Opaque controller-issued identifier
+    cookie_mask      Mask used to restrict the cookie bits that must match
+                     when the command is ``OPFFC_MODIFY*`` or
+                     ``OFPFC_DELETE*``
+    table_id         ID of the table to put the flow in
+    command          One of the following values.
+
+                     | OFPFC_ADD
+                     | OFPFC_MODIFY
+                     | OFPFC_MODIFY_STRICT
+                     | OFPFC_DELETE
+                     | OFPFC_DELETE_STRICT
+    idle_timeout     Idle time before discarding (seconds)
+    hard_timeout     Max time before discarding (seconds)
+    priority         Priority level of flow entry
+    buffer_id        Buffered packet to apply to (or OFP_NO_BUFFER)
+    out_port         For ``OFPFC_DELETE*`` commands, require matching
+                     entries to include this as an output port
+    out_group        For ``OFPFC_DELETE*`` commands, require matching
+                     entries to include this as an output group
+    flags            Bitmap of the following flags.
+
+                     | OFPFF_SEND_FLOW_REM
+                     | OFPFF_CHECK_OVERLAP
+                     | OFPFF_RESET_COUNTS
+                     | OFPFF_NO_PKT_COUNTS
+                     | OFPFF_NO_BYT_COUNTS
+    importance       Eviction precedence
+    match            Instance of ``OFPMatch``
+    instructions     list of ``OFPInstruction*`` instance
+    ================ ======================================================
+
+    Example::
+
+        def send_flow_mod(self, datapath):
+            ofp = datapath.ofproto
+            ofp_parser = datapath.ofproto_parser
+
+            cookie = cookie_mask = 0
+            table_id = 0
+            idle_timeout = hard_timeout = 0
+            priority = 32768
+            buffer_id = ofp.OFP_NO_BUFFER
+            importance = 0
+            match = ofp_parser.OFPMatch(in_port=1, eth_dst='ff:ff:ff:ff:ff:ff')
+            actions = [ofp_parser.OFPActionOutput(ofp.OFPP_NORMAL, 0)]
+            inst = [ofp_parser.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS,
+                                                     actions)]
+            req = ofp_parser.OFPFlowMod(datapath, cookie, cookie_mask,
+                                        table_id, ofp.OFPFC_ADD,
+                                        idle_timeout, hard_timeout,
+                                        priority, buffer_id,
+                                        ofp.OFPP_ANY, ofp.OFPG_ANY,
+                                        ofp.OFPFF_SEND_FLOW_REM,
+                                        importance,
+                                        match, inst)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, cookie=0, cookie_mask=0, table_id=0,
+                 command=ofproto.OFPFC_ADD,
+                 idle_timeout=0, hard_timeout=0,
+                 priority=ofproto.OFP_DEFAULT_PRIORITY,
+                 buffer_id=ofproto.OFP_NO_BUFFER,
+                 out_port=0, out_group=0, flags=0, importance=0,
+                 match=None,
+                 instructions=None):
+        instructions = instructions if instructions else []
+        super(OFPFlowMod, self).__init__(datapath)
+        self.cookie = cookie
+        self.cookie_mask = cookie_mask
+        self.table_id = table_id
+        self.command = command
+        self.idle_timeout = idle_timeout
+        self.hard_timeout = hard_timeout
+        self.priority = priority
+        self.buffer_id = buffer_id
+        self.out_port = out_port
+        self.out_group = out_group
+        self.flags = flags
+        self.importance = importance
+        if match is None:
+            match = OFPMatch()
+        assert isinstance(match, OFPMatch)
+        self.match = match
+        for i in instructions:
+            assert isinstance(i, OFPInstruction)
+        self.instructions = instructions
+
+    def _serialize_body(self):
+        msg_pack_into(ofproto.OFP_FLOW_MOD_PACK_STR0, self.buf,
+                      ofproto.OFP_HEADER_SIZE,
+                      self.cookie, self.cookie_mask, self.table_id,
+                      self.command, self.idle_timeout, self.hard_timeout,
+                      self.priority, self.buffer_id, self.out_port,
+                      self.out_group, self.flags, self.importance)
+
+        offset = (ofproto.OFP_FLOW_MOD_SIZE -
+                  ofproto.OFP_MATCH_SIZE)
+
+        match_len = self.match.serialize(self.buf, offset)
+        offset += match_len
+
+        for inst in self.instructions:
+            inst.serialize(self.buf, offset)
+            offset += inst.len
+
+    @classmethod
+    def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+        msg = super(OFPFlowMod, cls).parser(
+            datapath, version, msg_type, msg_len, xid, buf)
+
+        (msg.cookie, msg.cookie_mask, msg.table_id,
+         msg.command, msg.idle_timeout, msg.hard_timeout,
+         msg.priority, msg.buffer_id, msg.out_port,
+         msg.out_group, msg.flags, msg.importance) = struct.unpack_from(
+            ofproto.OFP_FLOW_MOD_PACK_STR0, msg.buf,
+            ofproto.OFP_HEADER_SIZE)
+        offset = ofproto.OFP_FLOW_MOD_SIZE - ofproto.OFP_HEADER_SIZE
+
+        msg.match = OFPMatch.parser(buf, offset)
+        offset += utils.round_up(msg.match.length, 8)
+
+        instructions = []
+        while offset < msg_len:
+            i = OFPInstruction.parser(buf, offset)
+            instructions.append(i)
+            offset += i.len
+        msg.instructions = instructions
+
+        return msg
+
+
+class OFPInstruction(StringifyMixin):
+    _INSTRUCTION_TYPES = {}
+
+    @staticmethod
+    def register_instruction_type(types):
+        def _register_instruction_type(cls):
+            for type_ in types:
+                OFPInstruction._INSTRUCTION_TYPES[type_] = cls
+            return cls
+        return _register_instruction_type
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (type_, len_) = struct.unpack_from('!HH', buf, offset)
+        cls_ = cls._INSTRUCTION_TYPES.get(type_)
+        return cls_.parser(buf, offset)
+
+
+@OFPInstruction.register_instruction_type([ofproto.OFPIT_GOTO_TABLE])
+class OFPInstructionGotoTable(OFPInstruction):
+    """
+    Goto table instruction
+
+    This instruction indicates the next table in the processing pipeline.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    table_id         Next table
+    ================ ======================================================
+    """
+
+    def __init__(self, table_id, type_=None, len_=None):
+        super(OFPInstructionGotoTable, self).__init__()
+        self.type = ofproto.OFPIT_GOTO_TABLE
+        self.len = ofproto.OFP_INSTRUCTION_GOTO_TABLE_SIZE
+        self.table_id = table_id
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (type_, len_, table_id) = struct.unpack_from(
+            ofproto.OFP_INSTRUCTION_GOTO_TABLE_PACK_STR,
+            buf, offset)
+        return cls(table_id)
+
+    def serialize(self, buf, offset):
+        msg_pack_into(ofproto.OFP_INSTRUCTION_GOTO_TABLE_PACK_STR,
+                      buf, offset, self.type, self.len, self.table_id)
+
+
+@OFPInstruction.register_instruction_type([ofproto.OFPIT_WRITE_METADATA])
+class OFPInstructionWriteMetadata(OFPInstruction):
+    """
+    Write metadata instruction
+
+    This instruction writes the masked metadata value into the metadata field.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    metadata         Metadata value to write
+    metadata_mask    Metadata write bitmask
+    ================ ======================================================
+    """
+
+    def __init__(self, metadata, metadata_mask, type_=None, len_=None):
+        super(OFPInstructionWriteMetadata, self).__init__()
+        self.type = ofproto.OFPIT_WRITE_METADATA
+        self.len = ofproto.OFP_INSTRUCTION_WRITE_METADATA_SIZE
+        self.metadata = metadata
+        self.metadata_mask = metadata_mask
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (type_, len_, metadata, metadata_mask) = struct.unpack_from(
+            ofproto.OFP_INSTRUCTION_WRITE_METADATA_PACK_STR,
+            buf, offset)
+        return cls(metadata, metadata_mask)
+
+    def serialize(self, buf, offset):
+        msg_pack_into(ofproto.OFP_INSTRUCTION_WRITE_METADATA_PACK_STR,
+                      buf, offset, self.type, self.len, self.metadata,
+                      self.metadata_mask)
+
+
+@OFPInstruction.register_instruction_type([ofproto.OFPIT_WRITE_ACTIONS,
+                                           ofproto.OFPIT_APPLY_ACTIONS,
+                                           ofproto.OFPIT_CLEAR_ACTIONS])
+class OFPInstructionActions(OFPInstruction):
+    """
+    Actions instruction
+
+    This instruction writes/applies/clears the actions.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    type             One of following values.
+
+                     | OFPIT_WRITE_ACTIONS
+                     | OFPIT_APPLY_ACTIONS
+                     | OFPIT_CLEAR_ACTIONS
+    actions          list of OpenFlow action class
+    ================ ======================================================
+
+    ``type`` attribute corresponds to ``type_`` parameter of __init__.
+    """
+
+    def __init__(self, type_, actions=None, len_=None):
+        super(OFPInstructionActions, self).__init__()
+        self.type = type_
+        for a in actions:
+            assert isinstance(a, OFPAction)
+        self.actions = actions
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (type_, len_) = struct.unpack_from(
+            ofproto.OFP_INSTRUCTION_ACTIONS_PACK_STR,
+            buf, offset)
+
+        offset += ofproto.OFP_INSTRUCTION_ACTIONS_SIZE
+        actions = []
+        actions_len = len_ - ofproto.OFP_INSTRUCTION_ACTIONS_SIZE
+        while actions_len > 0:
+            a = OFPAction.parser(buf, offset)
+            actions.append(a)
+            actions_len -= a.len
+            offset += a.len
+
+        inst = cls(type_, actions)
+        inst.len = len_
+        return inst
+
+    def serialize(self, buf, offset):
+        action_offset = offset + ofproto.OFP_INSTRUCTION_ACTIONS_SIZE
+        if self.actions:
+            for a in self.actions:
+                a.serialize(buf, action_offset)
+                action_offset += a.len
+
+        self.len = action_offset - offset
+        pad_len = utils.round_up(self.len, 8) - self.len
+        msg_pack_into("%dx" % pad_len, buf, action_offset)
+        self.len += pad_len
+
+        msg_pack_into(ofproto.OFP_INSTRUCTION_ACTIONS_PACK_STR,
+                      buf, offset, self.type, self.len)
+
+
+@OFPInstruction.register_instruction_type([ofproto.OFPIT_METER])
+class OFPInstructionMeter(OFPInstruction):
+    """
+    Meter instruction
+
+    This instruction applies the meter.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    meter_id         Meter instance
+    ================ ======================================================
+    """
+
+    def __init__(self, meter_id=1, type_=None, len_=None):
+        super(OFPInstructionMeter, self).__init__()
+        self.type = ofproto.OFPIT_METER
+        self.len = ofproto.OFP_INSTRUCTION_METER_SIZE
+        self.meter_id = meter_id
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (type_, len_, meter_id) = struct.unpack_from(
+            ofproto.OFP_INSTRUCTION_METER_PACK_STR,
+            buf, offset)
+        return cls(meter_id)
+
+    def serialize(self, buf, offset):
+        msg_pack_into(ofproto.OFP_INSTRUCTION_METER_PACK_STR,
+                      buf, offset, self.type, self.len, self.meter_id)
+
+
+class OFPActionHeader(StringifyMixin):
+    def __init__(self, type_, len_):
+        self.type = type_
+        self.len = len_
+
+    def serialize(self, buf, offset):
+        msg_pack_into(ofproto.OFP_ACTION_HEADER_PACK_STR,
+                      buf, offset, self.type, self.len)
+
+
+class OFPAction(OFPActionHeader):
+    _ACTION_TYPES = {}
+
+    @staticmethod
+    def register_action_type(type_, len_):
+        def _register_action_type(cls):
+            cls.cls_action_type = type_
+            cls.cls_action_len = len_
+            OFPAction._ACTION_TYPES[cls.cls_action_type] = cls
+            return cls
+        return _register_action_type
+
+    def __init__(self):
+        cls = self.__class__
+        super(OFPAction, self).__init__(cls.cls_action_type,
+                                        cls.cls_action_len)
+
+    @classmethod
+    def parser(cls, buf, offset):
+        type_, len_ = struct.unpack_from(
+            ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
+        cls_ = cls._ACTION_TYPES.get(type_)
+        assert cls_ is not None
+        return cls_.parser(buf, offset)
+
+
+@OFPAction.register_action_type(ofproto.OFPAT_OUTPUT,
+                                ofproto.OFP_ACTION_OUTPUT_SIZE)
+class OFPActionOutput(OFPAction):
+    """
+    Output action
+
+    This action indicates output a packet to the switch port.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    port             Output port
+    max_len          Max length to send to controller
+    ================ ======================================================
+    """
+
+    def __init__(self, port, max_len=ofproto.OFPCML_MAX,
+                 type_=None, len_=None):
+        super(OFPActionOutput, self).__init__()
+        self.port = port
+        self.max_len = max_len
+
+    @classmethod
+    def parser(cls, buf, offset):
+        type_, len_, port, max_len = struct.unpack_from(
+            ofproto.OFP_ACTION_OUTPUT_PACK_STR, buf, offset)
+        return cls(port, max_len)
+
+    def serialize(self, buf, offset):
+        msg_pack_into(ofproto.OFP_ACTION_OUTPUT_PACK_STR, buf,
+                      offset, self.type, self.len, self.port, self.max_len)
+
+
+@OFPAction.register_action_type(ofproto.OFPAT_GROUP,
+                                ofproto.OFP_ACTION_GROUP_SIZE)
+class OFPActionGroup(OFPAction):
+    """
+    Group action
+
+    This action indicates the group used to process the packet.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    group_id         Group identifier
+    ================ ======================================================
+    """
+
+    def __init__(self, group_id=0, type_=None, len_=None):
+        super(OFPActionGroup, self).__init__()
+        self.group_id = group_id
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (type_, len_, group_id) = struct.unpack_from(
+            ofproto.OFP_ACTION_GROUP_PACK_STR, buf, offset)
+        return cls(group_id)
+
+    def serialize(self, buf, offset):
+        msg_pack_into(ofproto.OFP_ACTION_GROUP_PACK_STR, buf,
+                      offset, self.type, self.len, self.group_id)
+
+
+@OFPAction.register_action_type(ofproto.OFPAT_SET_QUEUE,
+                                ofproto.OFP_ACTION_SET_QUEUE_SIZE)
+class OFPActionSetQueue(OFPAction):
+    """
+    Set queue action
+
+    This action sets the queue id that will be used to map a flow to an
+    already-configured queue on a port.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    queue_id         Queue ID for the packets
+    ================ ======================================================
+    """
+
+    def __init__(self, queue_id, type_=None, len_=None):
+        super(OFPActionSetQueue, self).__init__()
+        self.queue_id = queue_id
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (type_, len_, queue_id) = struct.unpack_from(
+            ofproto.OFP_ACTION_SET_QUEUE_PACK_STR, buf, offset)
+        return cls(queue_id)
+
+    def serialize(self, buf, offset):
+        msg_pack_into(ofproto.OFP_ACTION_SET_QUEUE_PACK_STR, buf,
+                      offset, self.type, self.len, self.queue_id)
+
+
+@OFPAction.register_action_type(ofproto.OFPAT_SET_MPLS_TTL,
+                                ofproto.OFP_ACTION_MPLS_TTL_SIZE)
+class OFPActionSetMplsTtl(OFPAction):
+    """
+    Set MPLS TTL action
+
+    This action sets the MPLS TTL.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    mpls_ttl         MPLS TTL
+    ================ ======================================================
+    """
+
+    def __init__(self, mpls_ttl, type_=None, len_=None):
+        super(OFPActionSetMplsTtl, self).__init__()
+        self.mpls_ttl = mpls_ttl
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (type_, len_, mpls_ttl) = struct.unpack_from(
+            ofproto.OFP_ACTION_MPLS_TTL_PACK_STR, buf, offset)
+        return cls(mpls_ttl)
+
+    def serialize(self, buf, offset):
+        msg_pack_into(ofproto.OFP_ACTION_MPLS_TTL_PACK_STR, buf,
+                      offset, self.type, self.len, self.mpls_ttl)
+
+
+@OFPAction.register_action_type(ofproto.OFPAT_DEC_MPLS_TTL,
+                                ofproto.OFP_ACTION_HEADER_SIZE)
+class OFPActionDecMplsTtl(OFPAction):
+    """
+    Decrement MPLS TTL action
+
+    This action decrements the MPLS TTL.
+    """
+
+    def __init__(self, type_=None, len_=None):
+        super(OFPActionDecMplsTtl, self).__init__()
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (type_, len_) = struct.unpack_from(
+            ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
+        return cls()
+
+
+@OFPAction.register_action_type(ofproto.OFPAT_SET_NW_TTL,
+                                ofproto.OFP_ACTION_NW_TTL_SIZE)
+class OFPActionSetNwTtl(OFPAction):
+    """
+    Set IP TTL action
+
+    This action sets the IP TTL.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    nw_ttl           IP TTL
+    ================ ======================================================
+    """
+
+    def __init__(self, nw_ttl, type_=None, len_=None):
+        super(OFPActionSetNwTtl, self).__init__()
+        self.nw_ttl = nw_ttl
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (type_, len_, nw_ttl) = struct.unpack_from(
+            ofproto.OFP_ACTION_NW_TTL_PACK_STR, buf, offset)
+        return cls(nw_ttl)
+
+    def serialize(self, buf, offset):
+        msg_pack_into(ofproto.OFP_ACTION_NW_TTL_PACK_STR, buf, offset,
+                      self.type, self.len, self.nw_ttl)
+
+
+@OFPAction.register_action_type(ofproto.OFPAT_DEC_NW_TTL,
+                                ofproto.OFP_ACTION_HEADER_SIZE)
+class OFPActionDecNwTtl(OFPAction):
+    """
+    Decrement IP TTL action
+
+    This action decrements the IP TTL.
+    """
+
+    def __init__(self, type_=None, len_=None):
+        super(OFPActionDecNwTtl, self).__init__()
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (type_, len_) = struct.unpack_from(
+            ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
+        return cls()
+
+
+@OFPAction.register_action_type(ofproto.OFPAT_COPY_TTL_OUT,
+                                ofproto.OFP_ACTION_HEADER_SIZE)
+class OFPActionCopyTtlOut(OFPAction):
+    """
+    Copy TTL Out action
+
+    This action copies the TTL from the next-to-outermost header with TTL to
+    the outermost header with TTL.
+    """
+
+    def __init__(self, type_=None, len_=None):
+        super(OFPActionCopyTtlOut, self).__init__()
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (type_, len_) = struct.unpack_from(
+            ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
+        return cls()
+
+
+@OFPAction.register_action_type(ofproto.OFPAT_COPY_TTL_IN,
+                                ofproto.OFP_ACTION_HEADER_SIZE)
+class OFPActionCopyTtlIn(OFPAction):
+    """
+    Copy TTL In action
+
+    This action copies the TTL from the outermost header with TTL to the
+    next-to-outermost header with TTL.
+    """
+
+    def __init__(self, type_=None, len_=None):
+        super(OFPActionCopyTtlIn, self).__init__()
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (type_, len_) = struct.unpack_from(
+            ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
+        return cls()
+
+
+@OFPAction.register_action_type(ofproto.OFPAT_PUSH_VLAN,
+                                ofproto.OFP_ACTION_PUSH_SIZE)
+class OFPActionPushVlan(OFPAction):
+    """
+    Push VLAN action
+
+    This action pushes a new VLAN tag to the packet.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    ethertype        Ether type.  The default is 802.1Q. (0x8100)
+    ================ ======================================================
+    """
+
+    def __init__(self, ethertype=ether.ETH_TYPE_8021Q, type_=None, len_=None):
+        super(OFPActionPushVlan, self).__init__()
+        self.ethertype = ethertype
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (type_, len_, ethertype) = struct.unpack_from(
+            ofproto.OFP_ACTION_PUSH_PACK_STR, buf, offset)
+        return cls(ethertype)
+
+    def serialize(self, buf, offset):
+        msg_pack_into(ofproto.OFP_ACTION_PUSH_PACK_STR, buf, offset,
+                      self.type, self.len, self.ethertype)
+
+
+@OFPAction.register_action_type(ofproto.OFPAT_PUSH_MPLS,
+                                ofproto.OFP_ACTION_PUSH_SIZE)
+class OFPActionPushMpls(OFPAction):
+    """
+    Push MPLS action
+
+    This action pushes a new MPLS header to the packet.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    ethertype        Ether type
+    ================ ======================================================
+    """
+
+    def __init__(self, ethertype=ether.ETH_TYPE_MPLS, type_=None, len_=None):
+        super(OFPActionPushMpls, self).__init__()
+        self.ethertype = ethertype
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (type_, len_, ethertype) = struct.unpack_from(
+            ofproto.OFP_ACTION_PUSH_PACK_STR, buf, offset)
+        return cls(ethertype)
+
+    def serialize(self, buf, offset):
+        msg_pack_into(ofproto.OFP_ACTION_PUSH_PACK_STR, buf, offset,
+                      self.type, self.len, self.ethertype)
+
+
+@OFPAction.register_action_type(ofproto.OFPAT_POP_VLAN,
+                                ofproto.OFP_ACTION_HEADER_SIZE)
+class OFPActionPopVlan(OFPAction):
+    """
+    Pop VLAN action
+
+    This action pops the outermost VLAN tag from the packet.
+    """
+
+    def __init__(self, type_=None, len_=None):
+        super(OFPActionPopVlan, self).__init__()
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (type_, len_) = struct.unpack_from(
+            ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
+        return cls()
+
+
+@OFPAction.register_action_type(ofproto.OFPAT_POP_MPLS,
+                                ofproto.OFP_ACTION_POP_MPLS_SIZE)
+class OFPActionPopMpls(OFPAction):
+    """
+    Pop MPLS action
+
+    This action pops the MPLS header from the packet.
+    """
+
+    def __init__(self, ethertype=ether.ETH_TYPE_IP, type_=None, len_=None):
+        super(OFPActionPopMpls, self).__init__()
+        self.ethertype = ethertype
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (type_, len_, ethertype) = struct.unpack_from(
+            ofproto.OFP_ACTION_POP_MPLS_PACK_STR, buf, offset)
+        return cls(ethertype)
+
+    def serialize(self, buf, offset):
+        msg_pack_into(ofproto.OFP_ACTION_POP_MPLS_PACK_STR, buf, offset,
+                      self.type, self.len, self.ethertype)
+
+
+@OFPAction.register_action_type(ofproto.OFPAT_SET_FIELD,
+                                ofproto.OFP_ACTION_SET_FIELD_SIZE)
+class OFPActionSetField(OFPAction):
+    """
+    Set field action
+
+    This action modifies a header field in the packet.
+
+    The set of keywords available for this is same as OFPMatch.
+
+    Example::
+
+        set_field = OFPActionSetField(eth_src="00:00:00:00:00:00")
+    """
+
+    def __init__(self, field=None, **kwargs):
+        super(OFPActionSetField, self).__init__()
+        assert len(kwargs) == 1
+        key = list(kwargs.keys())[0]
+        value = kwargs[key]
+        assert isinstance(key, (str, six.text_type))
+        assert not isinstance(value, tuple)  # no mask
+        self.key = key
+        self.value = value
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (type_, len_) = struct.unpack_from(
+            ofproto.OFP_ACTION_SET_FIELD_PACK_STR, buf, offset)
+        (n, value, mask, _len) = ofproto.oxm_parse(buf, offset + 4)
+        k, uv = ofproto.oxm_to_user(n, value, mask)
+        action = cls(**{k: uv})
+        action.len = len_
+        return action
+
+    def serialize(self, buf, offset):
+        n, value, mask = ofproto.oxm_from_user(self.key, self.value)
+        len_ = ofproto.oxm_serialize(n, value, mask, buf, offset + 4)
+        self.len = utils.round_up(4 + len_, 8)
+        msg_pack_into('!HH', buf, offset, self.type, self.len)
+        pad_len = self.len - (4 + len_)
+        msg_pack_into("%dx" % pad_len, buf, offset + 4 + len_)
+
+    def to_jsondict(self):
+        return {
+            self.__class__.__name__: {
+                'field': ofproto.oxm_to_jsondict(self.key, self.value),
+                "len": self.len,
+                "type": self.type
+            }
+        }
+
+    @classmethod
+    def from_jsondict(cls, dict_):
+        k, v = ofproto.oxm_from_jsondict(dict_['field'])
+        return OFPActionSetField(**{k: v})
+
+    def stringify_attrs(self):
+        yield (self.key, self.value)
+
+
+@OFPAction.register_action_type(ofproto.OFPAT_PUSH_PBB,
+                                ofproto.OFP_ACTION_PUSH_SIZE)
+class OFPActionPushPbb(OFPAction):
+    """
+    Push PBB action
+
+    This action pushes a new PBB header to the packet.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    ethertype        Ether type
+    ================ ======================================================
+    """
+
+    def __init__(self, ethertype, type_=None, len_=None):
+        super(OFPActionPushPbb, self).__init__()
+        self.ethertype = ethertype
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (type_, len_, ethertype) = struct.unpack_from(
+            ofproto.OFP_ACTION_PUSH_PACK_STR, buf, offset)
+        return cls(ethertype)
+
+    def serialize(self, buf, offset):
+        msg_pack_into(ofproto.OFP_ACTION_PUSH_PACK_STR, buf, offset,
+                      self.type, self.len, self.ethertype)
+
+
+@OFPAction.register_action_type(ofproto.OFPAT_POP_PBB,
+                                ofproto.OFP_ACTION_HEADER_SIZE)
+class OFPActionPopPbb(OFPAction):
+    """
+    Pop PBB action
+
+    This action pops the outermost PBB service instance header from
+    the packet.
+    """
+
+    def __init__(self, type_=None, len_=None):
+        super(OFPActionPopPbb, self).__init__()
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (type_, len_) = struct.unpack_from(
+            ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
+        return cls()
+
+
+@OFPAction.register_action_type(
+    ofproto.OFPAT_EXPERIMENTER,
+    ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE)
+class OFPActionExperimenter(OFPAction):
+    """
+    Experimenter action
+
+    This action is an extensible action for the experimenter.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    experimenter     Experimenter ID
+    ================ ======================================================
+
+    .. Note::
+
+        For the list of the supported Nicira experimenter actions,
+        please refer to :ref:`ryu.ofproto.nx_actions <nx_actions_structures>`.
+    """
+
+    def __init__(self, experimenter):
+        super(OFPActionExperimenter, self).__init__()
+        self.type = ofproto.OFPAT_EXPERIMENTER
+        self.experimenter = experimenter
+        self.len = None
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (type_, len_, experimenter) = struct.unpack_from(
+            ofproto.OFP_ACTION_EXPERIMENTER_HEADER_PACK_STR, buf, offset)
+        data = buf[(offset + ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE
+                    ): offset + len_]
+        if experimenter == ofproto_common.NX_EXPERIMENTER_ID:
+            obj = NXAction.parse(data)  # noqa
+        else:
+            obj = OFPActionExperimenterUnknown(experimenter, data)
+        obj.len = len_
+        return obj
+
+    def serialize(self, buf, offset):
+        msg_pack_into(ofproto.OFP_ACTION_EXPERIMENTER_HEADER_PACK_STR,
+                      buf, offset, self.type, self.len, self.experimenter)
+
+
+class OFPActionExperimenterUnknown(OFPActionExperimenter):
+    def __init__(self, experimenter, data=None, type_=None, len_=None):
+        super(OFPActionExperimenterUnknown,
+              self).__init__(experimenter=experimenter)
+        self.data = data
+
+    def serialize(self, buf, offset):
+        # fixup
+        data = self.data
+        if data is None:
+            data = bytearray()
+        self.len = (utils.round_up(len(data), 8) +
+                    ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE)
+        super(OFPActionExperimenterUnknown, self).serialize(buf, offset)
+        msg_pack_into('!%ds' % len(self.data),
+                      buf,
+                      offset + ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE,
+                      self.data)
+
+
+@_register_parser
+@_set_msg_type(ofproto.OFPT_GROUP_MOD)
+class OFPGroupMod(MsgBase):
+    """
+    Modify group entry message
+
+    The controller sends this message to modify the group table.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    command          One of the following values.
+
+                     | OFPGC_ADD
+                     | OFPGC_MODIFY
+                     | OFPGC_DELETE
+    type             One of the following values.
+
+                     | OFPGT_ALL
+                     | OFPGT_SELECT
+                     | OFPGT_INDIRECT
+                     | OFPGT_FF
+    group_id         Group identifier
+    buckets          list of ``OFPBucket``
+    ================ ======================================================
+
+    ``type`` attribute corresponds to ``type_`` parameter of __init__.
+
+    Example::
+
+        def send_group_mod(self, datapath):
+            ofp = datapath.ofproto
+            ofp_parser = datapath.ofproto_parser
+
+            port = 1
+            max_len = 2000
+            actions = [ofp_parser.OFPActionOutput(port, max_len)]
+
+            weight = 100
+            watch_port = 0
+            watch_group = 0
+            buckets = [ofp_parser.OFPBucket(weight, watch_port, watch_group,
+                                            actions)]
+
+            group_id = 1
+            req = ofp_parser.OFPGroupMod(datapath, ofp.OFPGC_ADD,
+                                         ofp.OFPGT_SELECT, group_id, buckets)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, command=ofproto.OFPGC_ADD,
+                 type_=ofproto.OFPGT_ALL, group_id=0, buckets=None):
+        buckets = buckets if buckets else []
+        super(OFPGroupMod, self).__init__(datapath)
+        self.command = command
+        self.type = type_
+        self.group_id = group_id
+        self.buckets = buckets
+
+    @classmethod
+    def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+        msg = super(OFPGroupMod, cls).parser(
+            datapath, version, msg_type, msg_len, xid, buf)
+        (msg.command, msg.type, msg.group_id) = struct.unpack_from(
+            ofproto.OFP_GROUP_MOD_PACK_STR, buf, ofproto.OFP_HEADER_SIZE)
+        offset = ofproto.OFP_GROUP_MOD_SIZE
+
+        msg.buckets = []
+        while offset < msg.msg_len:
+            bucket = OFPBucket.parser(buf, offset)
+            msg.buckets.append(bucket)
+            offset += bucket.len
+
+        return msg
+
+    def _serialize_body(self):
+        msg_pack_into(ofproto.OFP_GROUP_MOD_PACK_STR, self.buf,
+                      ofproto.OFP_HEADER_SIZE,
+                      self.command, self.type, self.group_id)
+
+        offset = ofproto.OFP_GROUP_MOD_SIZE
+        for b in self.buckets:
+            b.serialize(self.buf, offset)
+            offset += b.len
+
+
+class OFPPortModProp(OFPPropBase):
+    _TYPES = {}
+
+
+class OFPPortModPropEthernet(OFPPortModProp):
+    def __init__(self, type_=None, length=None, advertise=None):
+        self.type = type_
+        self.advertise = advertise
+
+    def serialize(self):
+        # fixup
+        self.length = struct.calcsize(
+            ofproto.OFP_PORT_MOD_PROP_ETHERNET_PACK_STR)
+
+        buf = bytearray()
+        msg_pack_into(ofproto.OFP_PORT_MOD_PROP_ETHERNET_PACK_STR,
+                      buf, 0, self.type, self.length, self.advertise)
+        return buf
+
+
+class OFPPortModPropOptical(OFPPortModProp):
+    def __init__(self, type_=None, length=None, configure=None,
+                 freq_lmda=None, fl_offset=None, grid_span=None,
+                 tx_pwr=None):
+        self.type = type_
+        self.length = length
+        self.configure = configure
+        self.freq_lmda = freq_lmda
+        self.fl_offset = fl_offset
+        self.grid_span = grid_span
+        self.tx_pwr = tx_pwr
+
+    def serialize(self):
+        # fixup
+        self.length = struct.calcsize(
+            ofproto.OFP_PORT_MOD_PROP_OPTICAL_PACK_STR)
+
+        buf = bytearray()
+        msg_pack_into(ofproto.OFP_PORT_MOD_PROP_OPTICAL_PACK_STR, buf, 0,
+                      self.type, self.length, self.configure, self.freq_lmda,
+                      self.fl_offset, self.grid_span, self.tx_pwr)
+        return buf
+
+
+class OFPPortModPropExperimenter(OFPPropCommonExperimenter4ByteData):
+    pass
+
+
+@_set_msg_type(ofproto.OFPT_PORT_MOD)
+class OFPPortMod(MsgBase):
+    """
+    Port modification message
+
+    The controller sneds this message to modify the behavior of the port.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    port_no          Port number to modify
+    hw_addr          The hardware address that must be the same as hw_addr
+                     of ``OFPPort`` of ``OFPSwitchFeatures``
+    config           Bitmap of configuration flags.
+
+                     | OFPPC_PORT_DOWN
+                     | OFPPC_NO_RECV
+                     | OFPPC_NO_FWD
+                     | OFPPC_NO_PACKET_IN
+    mask             Bitmap of configuration flags above to be changed
+    properties       List of ``OFPPortModProp`` subclass instance
+    ================ ======================================================
+
+    Example::
+
+        def send_port_mod(self, datapath):
+            ofp = datapath.ofproto
+            ofp_parser = datapath.ofproto_parser
+
+            port_no = 3
+            hw_addr = 'fa:c8:e8:76:1d:7e'
+            config = 0
+            mask = (ofp.OFPPC_PORT_DOWN | ofp.OFPPC_NO_RECV |
+                    ofp.OFPPC_NO_FWD | ofp.OFPPC_NO_PACKET_IN)
+            advertise = (ofp.OFPPF_10MB_HD | ofp.OFPPF_100MB_FD |
+                         ofp.OFPPF_1GB_FD | ofp.OFPPF_COPPER |
+                         ofp.OFPPF_AUTONEG | ofp.OFPPF_PAUSE |
+                         ofp.OFPPF_PAUSE_ASYM)
+            properties = [ofp_parser.OFPPortModPropEthernet(advertise)]
+            req = ofp_parser.OFPPortMod(datapath, port_no, hw_addr, config,
+                                        mask, properties)
+            datapath.send_msg(req)
+    """
+
+    _TYPE = {
+        'ascii': [
+            'hw_addr',
+        ]
+    }
+
+    def __init__(self, datapath, port_no=0, hw_addr='00:00:00:00:00:00',
+                 config=0, mask=0, properties=None):
+        super(OFPPortMod, self).__init__(datapath)
+        self.port_no = port_no
+        self.hw_addr = hw_addr
+        self.config = config
+        self.mask = mask
+        self.properties = properties or []
+
+    def _serialize_body(self):
+        bin_props = bytearray()
+        for p in self.properties:
+            bin_props += p.serialize()
+
+        msg_pack_into(ofproto.OFP_PORT_MOD_PACK_STR, self.buf,
+                      ofproto.OFP_HEADER_SIZE,
+                      self.port_no, addrconv.mac.text_to_bin(self.hw_addr),
+                      self.config,
+                      self.mask)
+        self.buf += bin_props
+
+
+class OFPBucket(StringifyMixin):
+    def __init__(self, weight=0, watch_port=ofproto.OFPP_ANY,
+                 watch_group=ofproto.OFPG_ANY, actions=None, len_=None):
+        super(OFPBucket, self).__init__()
+        self.weight = weight
+        self.watch_port = watch_port
+        self.watch_group = watch_group
+        self.actions = actions
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (len_, weight, watch_port, watch_group) = struct.unpack_from(
+            ofproto.OFP_BUCKET_PACK_STR, buf, offset)
+        msg = cls(weight, watch_port, watch_group, [])
+        msg.len = len_
+
+        length = ofproto.OFP_BUCKET_SIZE
+        offset += ofproto.OFP_BUCKET_SIZE
+        while length < msg.len:
+            action = OFPAction.parser(buf, offset)
+            msg.actions.append(action)
+            offset += action.len
+            length += action.len
+
+        return msg
+
+    def serialize(self, buf, offset):
+        action_offset = offset + ofproto.OFP_BUCKET_SIZE
+        action_len = 0
+        for a in self.actions:
+            a.serialize(buf, action_offset)
+            action_offset += a.len
+            action_len += a.len
+
+        self.len = utils.round_up(ofproto.OFP_BUCKET_SIZE + action_len, 8)
+        msg_pack_into(ofproto.OFP_BUCKET_PACK_STR, buf, offset,
+                      self.len, self.weight, self.watch_port,
+                      self.watch_group)
+
+
+@_set_msg_type(ofproto.OFPT_ROLE_REQUEST)
+class OFPRoleRequest(MsgBase):
+    """
+    Role request message
+
+    The controller uses this message to change its role.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    role             One of the following values.
+
+                     | OFPCR_ROLE_NOCHANGE
+                     | OFPCR_ROLE_EQUAL
+                     | OFPCR_ROLE_MASTER
+                     | OFPCR_ROLE_SLAVE
+    generation_id    Master Election Generation ID
+    ================ ======================================================
+
+    Example::
+
+        def send_role_request(self, datapath):
+            ofp = datapath.ofproto
+            ofp_parser = datapath.ofproto_parser
+
+            req = ofp_parser.OFPRoleRequest(datapath, ofp.OFPCR_ROLE_EQUAL, 0)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, role=None, generation_id=None):
+        super(OFPRoleRequest, self).__init__(datapath)
+        self.role = role
+        self.generation_id = generation_id
+
+    def _serialize_body(self):
+        assert self.role is not None
+        assert self.generation_id is not None
+        msg_pack_into(ofproto.OFP_ROLE_REQUEST_PACK_STR,
+                      self.buf, ofproto.OFP_HEADER_SIZE,
+                      self.role, self.generation_id)
+
+
+@_register_parser
+@_set_msg_type(ofproto.OFPT_ROLE_REPLY)
+class OFPRoleReply(MsgBase):
+    """
+    Role reply message
+
+    The switch responds with this message to a role request.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    role             One of the following values.
+
+                     | OFPCR_ROLE_NOCHANGE
+                     | OFPCR_ROLE_EQUAL
+                     | OFPCR_ROLE_MASTER
+                     | OFPCR_ROLE_SLAVE
+    generation_id    Master Election Generation ID
+    ================ ======================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPRoleReply, MAIN_DISPATCHER)
+        def role_reply_handler(self, ev):
+            msg = ev.msg
+            dp = msg.datapath
+            ofp = dp.ofproto
+
+            if msg.role == ofp.OFPCR_ROLE_NOCHANGE:
+                role = 'NOCHANGE'
+            elif msg.role == ofp.OFPCR_ROLE_EQUAL:
+                role = 'EQUAL'
+            elif msg.role == ofp.OFPCR_ROLE_MASTER:
+                role = 'MASTER'
+            elif msg.role == ofp.OFPCR_ROLE_SLAVE:
+                role = 'SLAVE'
+            else:
+                role = 'unknown'
+
+            self.logger.debug('OFPRoleReply received: '
+                              'role=%s generation_id=%d',
+                              role, msg.generation_id)
+    """
+
+    def __init__(self, datapath, role=None, generation_id=None):
+        super(OFPRoleReply, self).__init__(datapath)
+        self.role = role
+        self.generation_id = generation_id
+
+    @classmethod
+    def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+        msg = super(OFPRoleReply, cls).parser(datapath, version,
+                                              msg_type, msg_len, xid,
+                                              buf)
+        (msg.role, msg.generation_id) = struct.unpack_from(
+            ofproto.OFP_ROLE_REQUEST_PACK_STR, msg.buf,
+            ofproto.OFP_HEADER_SIZE)
+        return msg
+
+
+class OFPAsyncConfigProp(OFPPropBase):
+    _TYPES = {}
+
+
+@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_PACKET_IN_SLAVE)
+@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_PACKET_IN_MASTER)
+@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_PORT_STATUS_SLAVE)
+@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_PORT_STATUS_MASTER)
+@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_FLOW_REMOVED_SLAVE)
+@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_FLOW_REMOVED_MASTER)
+@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_ROLE_STATUS_SLAVE)
+@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_ROLE_STATUS_MASTER)
+@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_TABLE_STATUS_SLAVE)
+@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_TABLE_STATUS_MASTER)
+@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_REQUESTFORWARD_SLAVE)
+@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_REQUESTFORWARD_MASTER)
+class OFPAsyncConfigPropReasons(OFPAsyncConfigProp):
+    def __init__(self, type_=None, length=None, mask=None):
+        self.type = type_
+        self.length = length
+        self.mask = mask
+
+    @classmethod
+    def parser(cls, buf):
+        reasons = cls()
+        (reasons.type, reasons.length, reasons.mask) = struct.unpack_from(
+            ofproto.OFP_ASYNC_CONFIG_PROP_REASONS_PACK_STR, buf, 0)
+        return reasons
+
+    def serialize(self):
+        # fixup
+        self.length = ofproto.OFP_ASYNC_CONFIG_PROP_REASONS_SIZE
+
+        buf = bytearray()
+        msg_pack_into(ofproto.OFP_ASYNC_CONFIG_PROP_REASONS_PACK_STR, buf, 0,
+                      self.type, self.length, self.mask)
+        return buf
+
+
+@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_EXPERIMENTER_SLAVE)
+@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_EXPERIMENTER_MASTER)
+class OFPAsyncConfigPropExperimenter(OFPPropCommonExperimenter4ByteData):
+    pass
+
+
+@_set_msg_type(ofproto.OFPT_GET_ASYNC_REQUEST)
+class OFPGetAsyncRequest(MsgBase):
+    """
+    Get asynchronous configuration request message
+
+    The controller uses this message to query the asynchronous message.
+
+    Example::
+
+        def send_get_async_request(self, datapath):
+            ofp_parser = datapath.ofproto_parser
+
+            req = ofp_parser.OFPGetAsyncRequest(datapath)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath):
+        super(OFPGetAsyncRequest, self).__init__(datapath)
+
+
+@_register_parser
+@_set_msg_type(ofproto.OFPT_GET_ASYNC_REPLY)
+class OFPGetAsyncReply(MsgBase):
+    """
+    Get asynchronous configuration reply message
+
+    The switch responds with this message to a get asynchronous configuration
+    request.
+
+    ================== ====================================================
+    Attribute          Description
+    ================== ====================================================
+    properties         List of ``OFPAsyncConfigProp`` subclass instances
+    ================== ====================================================
+
+    Example::
+
+        @set_ev_cls(ofp_event.EventOFPGetAsyncReply, MAIN_DISPATCHER)
+        def get_async_reply_handler(self, ev):
+            msg = ev.msg
+
+            self.logger.debug('OFPGetAsyncReply received: '
+                              'properties=%s', repr(msg.properties))
+    """
+
+    def __init__(self, datapath, properties=None):
+        super(OFPGetAsyncReply, self).__init__(datapath)
+        self.properties = properties
+
+    @classmethod
+    def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+        msg = super(OFPGetAsyncReply, cls).parser(datapath, version,
+                                                  msg_type, msg_len,
+                                                  xid, buf)
+
+        msg.properties = []
+        rest = msg.buf[ofproto.OFP_HEADER_SIZE:]
+        while rest:
+            p, rest = OFPAsyncConfigProp.parse(rest)
+            msg.properties.append(p)
+
+        return msg
+
+
+@_set_msg_type(ofproto.OFPT_SET_ASYNC)
+class OFPSetAsync(MsgBase):
+    """
+    Set asynchronous configuration message
+
+    The controller sends this message to set the asynchronous messages that
+    it wants to receive on a given OpneFlow channel.
+
+    ================== ====================================================
+    Attribute          Description
+    ================== ====================================================
+    properties         List of ``OFPAsyncConfigProp`` subclass instances
+    ================== ====================================================
+
+    Example::
+
+        def send_set_async(self, datapath):
+            ofp = datapath.ofproto
+            ofp_parser = datapath.ofproto_parser
+
+            properties = [
+                ofp_parser.OFPAsyncConfigPropReasons(
+                    ofp.OFPACPT_PACKET_IN_SLAVE, 8,
+                    (1 << ofp.OFPR_APPLY_ACTION
+                     | 1 << ofp.OFPR_INVALID_TTL))]
+            req = ofp_parser.OFPSetAsync(datapath, properties)
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, properties=None):
+        super(OFPSetAsync, self).__init__(datapath)
+        self.properties = properties
+
+    def _serialize_body(self):
+        bin_props = bytearray()
+        for p in self.properties:
+            bin_props += p.serialize()
+
+        self.buf += bin_props
+
+
+@_register_parser
+@_set_msg_type(ofproto.OFPT_BUNDLE_CONTROL)
+class OFPBundleCtrlMsg(MsgBase):
+    """
+    Bundle control message
+
+    The controller uses this message to create, destroy and commit bundles
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    bundle_id        Id of the bundle
+    type             One of the following values.
+
+                     | OFPBCT_OPEN_REQUEST
+                     | OFPBCT_OPEN_REPLY
+                     | OFPBCT_CLOSE_REQUEST
+                     | OFPBCT_CLOSE_REPLY
+                     | OFPBCT_COMMIT_REQUEST
+                     | OFPBCT_COMMIT_REPLY
+                     | OFPBCT_DISCARD_REQUEST
+                     | OFPBCT_DISCARD_REPLY
+    flags            Bitmap of the following flags.
+
+                     | OFPBF_ATOMIC
+                     | OFPBF_ORDERED
+    properties       List of ``OFPBundleProp`` subclass instance
+    ================ ======================================================
+
+    Example::
+
+        def send_bundle_control(self, datapath):
+            ofp = datapath.ofproto
+            ofp_parser = datapath.ofproto_parser
+
+            req = ofp_parser.OFPBundleCtrlMsg(datapath, 7,
+                                              ofp.OFPBCT_OPEN_REQUEST,
+                                              ofp.OFPBF_ATOMIC, [])
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, bundle_id=None, type_=None, flags=None,
+                 properties=None):
+        super(OFPBundleCtrlMsg, self).__init__(datapath)
+        self.bundle_id = bundle_id
+        self.type = type_
+        self.flags = flags
+        self.properties = properties
+
+    def _serialize_body(self):
+        bin_props = bytearray()
+        for p in self.properties:
+            bin_props += p.serialize()
+
+        msg_pack_into(ofproto.OFP_BUNDLE_CTRL_MSG_PACK_STR,
+                      self.buf, ofproto.OFP_HEADER_SIZE, self.bundle_id,
+                      self.type, self.flags)
+        self.buf += bin_props
+
+    @classmethod
+    def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+        msg = super(OFPBundleCtrlMsg, cls).parser(datapath, version,
+                                                  msg_type, msg_len,
+                                                  xid, buf)
+        (bundle_id, type_, flags) = struct.unpack_from(
+            ofproto.OFP_BUNDLE_CTRL_MSG_PACK_STR, buf,
+            ofproto.OFP_HEADER_SIZE)
+        msg.bundle_id = bundle_id
+        msg.type = type_
+        msg.flags = flags
+        msg.properties = []
+        rest = msg.buf[ofproto.OFP_BUNDLE_CTRL_MSG_SIZE:]
+        while rest:
+            p, rest = OFPBundleProp.parse(rest)
+            msg.properties.append(p)
+
+        return msg
+
+
+@_set_msg_type(ofproto.OFPT_BUNDLE_ADD_MESSAGE)
+class OFPBundleAddMsg(MsgInMsgBase):
+    """
+    Bundle add message
+
+    The controller uses this message to add a message to a bundle
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    bundle_id        Id of the bundle
+    flags            Bitmap of the following flags.
+
+                     | OFPBF_ATOMIC
+                     | OFPBF_ORDERED
+    message          ``MsgBase`` subclass instance
+    properties       List of ``OFPBundleProp`` subclass instance
+    ================ ======================================================
+
+    Example::
+
+        def send_bundle_add_message(self, datapath):
+            ofp = datapath.ofproto
+            ofp_parser = datapath.ofproto_parser
+
+            msg = ofp_parser.OFPRoleRequest(datapath, ofp.OFPCR_ROLE_EQUAL, 0)
+
+            req = ofp_parser.OFPBundleAddMsg(datapath, 7, ofp.OFPBF_ATOMIC,
+                                             msg, [])
+            datapath.send_msg(req)
+    """
+
+    def __init__(self, datapath, bundle_id, flags, message, properties):
+        super(OFPBundleAddMsg, self).__init__(datapath)
+        self.bundle_id = bundle_id
+        self.flags = flags
+        self.message = message
+        self.properties = properties
+
+    def _serialize_body(self):
+        # The xid of the inner message must be the same as
+        # that of the outer message (OF1.4.0 7.3.9.2)
+        if self.message.xid != self.xid:
+            self.message.set_xid(self.xid)
+
+        # Message
+        self.message.serialize()
+        tail_buf = self.message.buf
+
+        # Pad
+        if len(self.properties) > 0:
+            message_len = len(tail_buf)
+            pad_len = utils.round_up(message_len, 8) - message_len
+            msg_pack_into("%dx" % pad_len, tail_buf, message_len)
+
+        # Properties
+        for p in self.properties:
+            tail_buf += p.serialize()
+
+        # Head
+        msg_pack_into(ofproto.OFP_BUNDLE_ADD_MSG_0_PACK_STR,
+                      self.buf, ofproto.OFP_HEADER_SIZE, self.bundle_id,
+                      self.flags)
+
+        # Finish
+        self.buf += tail_buf
+
+
+nx_actions.generate(
+    'ryu.ofproto.ofproto_v1_4',
+    'ryu.ofproto.ofproto_v1_4_parser'
+)