summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorShu Shen <shu.shen@gmail.com>2015-02-11 16:22:20 -0800
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2015-02-15 09:06:20 +0900
commit2889711e4670b08d5afbe2f408a511d9acbb5f52 (patch)
treeaf9cf36e15a976ff477cd47e64234b4e32842a22
parent45e37843b9f38192a9440f62803abbdc1df7a400 (diff)
ofproto: Openflow 1.5 support (work-in-progress)
Work done: - The baseline is copied over from ofproto_v1_4.py and ofproto_v1_4_parser.py and into ofproto_v1_5.py and ofproto_v1_5_parser.py respectively. - Most of structs, enums, and pack strings in ofproto_v1_5.py has been updated to spec. Exception is oxs_fields has not been done yet. - ofproto_v1_5_parser.py has not been updated except those necessary to allow run_tests.sh to complete successfully - ofproto_protocol.py imports ofproto_v1_5 and ofproto_v1_5_parser now - oxm_fields.py is updated for OFPXMC_PACKET_REGS - Tests are updated to include Openflow v1.5 when it's obvious. But not much work has been done to acutally test v1.5 yet. I also found tests for v1.4 are scarce. TODO: - Add oxs_fields support. It shall be similar to oxm_fields - Update and implement ofproto_v1_5_parser.py - More tests, tests, tests. Signed-off-by: Shu Shen <shu.shen@gmail.com> Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r--ryu/ofproto/ofproto_protocol.py3
-rw-r--r--ryu/ofproto/ofproto_v1_5.py1798
-rw-r--r--ryu/ofproto/ofproto_v1_5_parser.py6083
-rw-r--r--ryu/ofproto/oxm_fields.py5
-rw-r--r--ryu/tests/switch/tester.py10
-rw-r--r--ryu/tests/unit/ofproto/test_ofproto.py5
-rw-r--r--ryu/tests/unit/ofproto/test_parser.py31
7 files changed, 7932 insertions, 3 deletions
diff --git a/ryu/ofproto/ofproto_protocol.py b/ryu/ofproto/ofproto_protocol.py
index 87c7d36b..9e54597a 100644
--- a/ryu/ofproto/ofproto_protocol.py
+++ b/ryu/ofproto/ofproto_protocol.py
@@ -22,6 +22,8 @@ from . import ofproto_v1_3
from . import ofproto_v1_3_parser
from . import ofproto_v1_4
from . import ofproto_v1_4_parser
+from . import ofproto_v1_5
+from . import ofproto_v1_5_parser
_versions = {
@@ -29,6 +31,7 @@ _versions = {
ofproto_v1_2.OFP_VERSION: (ofproto_v1_2, ofproto_v1_2_parser),
ofproto_v1_3.OFP_VERSION: (ofproto_v1_3, ofproto_v1_3_parser),
ofproto_v1_4.OFP_VERSION: (ofproto_v1_4, ofproto_v1_4_parser),
+ ofproto_v1_5.OFP_VERSION: (ofproto_v1_5, ofproto_v1_5_parser),
}
diff --git a/ryu/ofproto/ofproto_v1_5.py b/ryu/ofproto/ofproto_v1_5.py
new file mode 100644
index 00000000..eb7183f4
--- /dev/null
+++ b/ryu/ofproto/ofproto_v1_5.py
@@ -0,0 +1,1798 @@
+# Copyright (C) 2012,2013 Nippon Telegraph and Telephone Corporation.
+# Copyright (C) 2012 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.
+
+"""
+OpenFlow 1.5 definitions.
+"""
+
+from ryu.lib import type_desc
+from ryu.ofproto import oxm_fields
+# TODO: oxs_fields
+# from ryu.ofproto import oxs_fields
+
+from struct import calcsize
+
+
+# enum ofp_port_no
+# Port numbering. Ports are numbered starting from 1.
+OFPP_MAX = 0xffffff00 # Maximum number of physical and logical
+ # switch ports.
+OFPP_UNSET = 0xfffffff7 # Output port not set in action-set.
+ # used only in OXM_OF_ACTSET_OUTPUT.
+OFPP_IN_PORT = 0xfffffff8 # Send the packet out the input port. This
+ # reserved port must be explicitly used in
+ # order to send back out of the input port.
+OFPP_TABLE = 0xfffffff9 # Submit the packet to the first flow table
+ # NB: This destination port can only be used
+ # in packet-out messages.
+OFPP_NORMAL = 0xfffffffa # Forward using non-OpenFlow pipeline.
+OFPP_FLOOD = 0xfffffffb # Flood using non-OpenFlow pipeline.
+OFPP_ALL = 0xfffffffc # All standard ports except input port.
+OFPP_CONTROLLER = 0xfffffffd # Send to controller.
+OFPP_LOCAL = 0xfffffffe # Local openflow "port".
+OFPP_ANY = 0xffffffff # Special value used in some requests when
+ # no port is specified (i.e. wildcarded).
+
+
+# enum ofp_type
+# Immutable messages.
+OFPT_HELLO = 0 # Symmetric message
+OFPT_ERROR = 1 # Symmetric message
+OFPT_ECHO_REQUEST = 2 # Symmetric message
+OFPT_ECHO_REPLY = 3 # Symmetric message
+OFPT_EXPERIMENTER = 4 # Symmetric message
+# Switch configuration messages.
+OFPT_FEATURES_REQUEST = 5 # Controller/switch message
+OFPT_FEATURES_REPLY = 6 # Controller/switch message
+OFPT_GET_CONFIG_REQUEST = 7 # Controller/switch message
+OFPT_GET_CONFIG_REPLY = 8 # Controller/switch message
+OFPT_SET_CONFIG = 9 # Controller/switch message
+# Asynchronous messages.
+OFPT_PACKET_IN = 10 # Async message
+OFPT_FLOW_REMOVED = 11 # Async message
+OFPT_PORT_STATUS = 12 # Async message
+# Controller command messages.
+OFPT_PACKET_OUT = 13 # Controller/switch message
+OFPT_FLOW_MOD = 14 # Controller/switch message
+OFPT_GROUP_MOD = 15 # Controller/switch message
+OFPT_PORT_MOD = 16 # Controller/switch message
+OFPT_TABLE_MOD = 17 # Controller/switch message
+# Multipart messages.
+OFPT_MULTIPART_REQUEST = 18 # Controller/switch message
+OFPT_MULTIPART_REPLY = 19 # Controller/switch message
+# Barrier messages.
+OFPT_BARRIER_REQUEST = 20 # Controller/switch message
+OFPT_BARRIER_REPLY = 21 # Controller/switch message
+# Controller role change request messages.
+OFPT_ROLE_REQUEST = 24 # Controller/switch message
+OFPT_ROLE_REPLY = 25 # Controller/switch message
+# Asynchronous message configuration.
+OFPT_GET_ASYNC_REQUEST = 26 # Controller/switch message
+OFPT_GET_ASYNC_REPLY = 27 # Controller/switch message
+OFPT_SET_ASYNC = 28 # Controller/switch message
+# Meters and rate limiters configuration messages.
+OFPT_METER_MOD = 29 # Controller/switch message
+# Controller role change event messages.
+OFPT_ROLE_STATUS = 30 # Async message
+# Asynchronous messages.
+OFPT_TABLE_STATUS = 31 # Async message
+# Request forwarding by the switch.
+OFPT_REQUESTFORWARD = 32 # Async message
+# Bundle operations (multiple messages as a single operation).
+OFPT_BUNDLE_CONTROL = 33 # Controller/switch message
+OFPT_BUNDLE_ADD_MESSAGE = 34 # Controller/switch message
+# Controller Status async message.
+OFPT_CONTROLLER_STATUS = 35 # Async message
+
+_OFP_HEADER_PACK_STR = 'BBHI'
+OFP_HEADER_PACK_STR = '!' + _OFP_HEADER_PACK_STR
+OFP_HEADER_SIZE = 8
+
+
+# struct ofp_hello
+OFP_HELLO_HEADER_SIZE = 8
+
+# struct ofp_hello_elem_header
+OFP_HELLO_ELEM_HEADER_PACK_STR = '!HH'
+OFP_HELLO_ELEM_HEADER_SIZE = 4
+assert (calcsize(OFP_HELLO_ELEM_HEADER_PACK_STR) == OFP_HELLO_ELEM_HEADER_SIZE)
+
+# enum ofp_hello_elem_type
+
+OFPHET_VERSIONBITMAP = 1
+
+# struct ofp_hello_elem_versionbitmap
+OFP_HELLO_ELEM_VERSIONBITMAP_HEADER_PACK_STR = '!HH'
+OFP_HELLO_ELEM_VERSIONBITMAP_HEADER_SIZE = 4
+assert (calcsize(OFP_HELLO_ELEM_VERSIONBITMAP_HEADER_PACK_STR) ==
+ OFP_HELLO_ELEM_VERSIONBITMAP_HEADER_SIZE)
+
+
+OFP_DEFAULT_MISS_SEND_LEN = 128
+
+# enum ofp_config_flags
+# Handling of IP fragments.
+OFPC_FRAG_NORMAL = 0 # No special handling for fragments.
+OFPC_FRAG_DROP = 1 << 0 # Drop fragments.
+OFPC_FRAG_REASM = 1 << 1 # Reassemble (only if OFPC_IP_REASM set).
+OFPC_FRAG_MASK = 3
+
+# struct ofp_switch_config
+OFP_SWITCH_CONFIG_PACK_STR = '!HH'
+OFP_SWITCH_CONFIG_SIZE = 12
+assert (calcsize(OFP_SWITCH_CONFIG_PACK_STR) + OFP_HEADER_SIZE ==
+ OFP_SWITCH_CONFIG_SIZE)
+
+
+# enum ofp_table
+OFPTT_MAX = 0xfe # Last usable table number.
+OFPTT_ALL = 0xff # Wildcard table used for table config, flow stats
+ # and flow deletes.
+
+
+# enum ofp_table_config
+OFPTC_DEPRECATED_MASK = 3 # Deprecated bits
+OFPTC_EVICTION = 1 << 2 # Authorise table to evict flows.
+OFPTC_VACANCY_EVENTS = 1 << 3 # Enable vacancy events.
+
+# enum ofp_table_mod_prop_type
+OFPTMPT_EVICTION = 0x2 # Eviction property.
+OFPTMPT_VACANCY = 0x3 # Vacancy property.
+OFPTMPT_EXPERIMENTER = 0xFFFF # Experimenter property.
+
+# enum ofp_table_mod_prop_eviction_flag
+OFPTMPEF_OTHER = 1 << 0 # Using other factors.
+OFPTMPEF_IMPORTANCE = 1 << 1 # Using flow entry importance.
+OFPTMPEF_LIFETIME = 1 << 2 # Using flow entry lifetime.
+
+# struct ofp_table_mod_prop_eviction
+OFP_TABLE_MOD_PROP_EVICTION_PACK_STR = '!HHI'
+OFP_TABLE_MOD_PROP_EVICTION_SIZE = 8
+assert(calcsize(OFP_TABLE_MOD_PROP_EVICTION_PACK_STR) ==
+ OFP_TABLE_MOD_PROP_EVICTION_SIZE)
+
+# struct ofp_table_mod_prop_vacancy
+OFP_TABLE_MOD_PROP_VACANCY_PACK_STR = '!HHBBBx'
+OFP_TABLE_MOD_PROP_VACANCY_SIZE = 8
+assert(calcsize(OFP_TABLE_MOD_PROP_VACANCY_PACK_STR) ==
+ OFP_TABLE_MOD_PROP_VACANCY_SIZE)
+
+# struct ofp_table_mod_prop_experimenter
+OFP_TABLE_MOD_PROP_EXPERIMENTER_PACK_STR = '!HHII'
+OFP_TABLE_MOD_PROP_EXPERIMENTER_SIZE = 12
+assert(calcsize(OFP_TABLE_MOD_PROP_EXPERIMENTER_PACK_STR) ==
+ OFP_TABLE_MOD_PROP_EXPERIMENTER_SIZE)
+
+# struct ofp_table_mod
+OFP_TABLE_MOD_PACK_STR = '!B3xI'
+OFP_TABLE_MOD_SIZE = 16
+assert (calcsize(OFP_TABLE_MOD_PACK_STR) + OFP_HEADER_SIZE ==
+ OFP_TABLE_MOD_SIZE)
+
+# enum ofp_capabilities
+OFPC_FLOW_STATS = 1 << 0 # Flow statistics.
+OFPC_TABLE_STATS = 1 << 1 # Table statistics.
+OFPC_PORT_STATS = 1 << 2 # Port statistics.
+OFPC_GROUP_STATS = 1 << 3 # Group statistics.
+OFPC_IP_REASM = 1 << 5 # Can reassemble IP fragments.
+OFPC_QUEUE_STATS = 1 << 6 # Queue statistics.
+OFPC_PORT_BLOCKED = 1 << 8 # Switch will block looping ports.
+OFPC_BUNDLES = 1 << 9 # Switch supports bundles.
+OFPC_FLOW_MONITORING = 1 << 10 # Switch supports flow monitoring.
+
+# enum ofp_port_config
+OFPPC_PORT_DOWN = 1 << 0 # Port is administratively down.
+OFPPC_NO_RECV = 1 << 2 # Drop all packets recieved by port.
+OFPPC_NO_FWD = 1 << 5 # Drop packets forwarded to port.
+OFPPC_NO_PACKET_IN = 1 << 6 # Do not send packet-in msgs for port.
+
+# enum ofp_port_state
+OFPPS_LINK_DOWN = 1 << 0 # No physical link present.
+OFPPS_BLOCKED = 1 << 1 # Port is blocked
+OFPPS_LIVE = 1 << 2 # Live for Fast Failover Group.
+
+# enum ofp_port_features
+OFPPF_10MB_HD = 1 << 0 # 10 Mb half-duplex rate support.
+OFPPF_10MB_FD = 1 << 1 # 10 Mb full-duplex rate support.
+OFPPF_100MB_HD = 1 << 2 # 100 Mb half-duplex rate support.
+OFPPF_100MB_FD = 1 << 3 # 100 Mb full-duplex rate support.
+OFPPF_1GB_HD = 1 << 4 # 1 Gb half-duplex rate support.
+OFPPF_1GB_FD = 1 << 5 # 1 Gb full-duplex rate support.
+OFPPF_10GB_FD = 1 << 6 # 10 Gb full-duplex rate support.
+OFPPF_40GB_FD = 1 << 7 # 40 Gb full-duplex rate support.
+OFPPF_100GB_FD = 1 << 8 # 100 Gb full-duplex rate support.
+OFPPF_1TB_FD = 1 << 9 # 1 Tb full-duplex rate support.
+OFPPF_OTHER = 1 << 10 # Other rate, not in the list.
+OFPPF_COPPER = 1 << 11 # Copper medium.
+OFPPF_FIBER = 1 << 12 # Fiber medium.
+OFPPF_AUTONEG = 1 << 13 # Auto-negotiation.
+OFPPF_PAUSE = 1 << 14 # Pause.
+OFPPF_PAUSE_ASYM = 1 << 15 # Asymmetric pause.
+
+# enum ofp_port_desc_prop_type
+OFPPDPT_ETHERNET = 0 # Ethernet property.
+OFPPDPT_OPTICAL = 1 # Optical property.
+OFPPDPT_PIPELINE_INPUT = 2 # Ingress pipeline fields.
+OFPPDPT_PIPELINE_OUTPUT = 3 # Egress pipeline fields.
+OFPPDPT_RECIRCULATE = 4 # Recirculation property.
+OFPPDPT_EXPERIMENTER = 0xFFFF # Experimenter property.
+
+# struct ofp_port_desc_prop_ethernet
+OFP_PORT_DESC_PROP_ETHERNET_PACK_STR = '!HH4xIIIIII'
+OFP_PORT_DESC_PROP_ETHERNET_SIZE = 32
+assert (calcsize(OFP_PORT_DESC_PROP_ETHERNET_PACK_STR) ==
+ OFP_PORT_DESC_PROP_ETHERNET_SIZE)
+
+# enum ofp_optical_port_features
+OFPOPF_RX_TUNE = 1 << 0 # Receiver is tunable
+OFPOPF_TX_TUNE = 1 << 1 # Transmit is tunable
+OFPOPF_TX_PWR = 1 << 2 # Power is configurable
+OFPOPF_USE_FREQ = 1 << 3 # Use Frequency, not wavelength
+
+# struct ofp_port_desc_prop_optical
+OFP_PORT_DESC_PROP_OPTICAL_PACK_STR = '!HH4xIIIIIIIHH'
+OFP_PORT_DESC_PROP_OPTICAL_SIZE = 40
+assert (calcsize(OFP_PORT_DESC_PROP_OPTICAL_PACK_STR) ==
+ OFP_PORT_DESC_PROP_OPTICAL_SIZE)
+
+# struct ofp_port_desc_prop_oxm
+OFP_PORT_DESC_PROP_OXM_PACK_STR = '!HH'
+OFP_PORT_DESC_PROP_OXM_SIZE = 4
+assert (calcsize(OFP_PORT_DESC_PROP_OXM_PACK_STR) ==
+ OFP_PORT_DESC_PROP_OXM_SIZE)
+
+# struct ofp_port_desc_prop_recirculate
+OFP_PORT_DESC_PROP_RECIRCULATE_PACK_STR = '!HH'
+OFP_PORT_DESC_PROP_RECIRCULATE_SIZE = 4
+assert (calcsize(OFP_PORT_DESC_PROP_RECIRCULATE_PACK_STR) ==
+ OFP_PORT_DESC_PROP_RECIRCULATE_SIZE)
+
+# struct ofp_port_desc_prop_experimenter
+OFP_PORT_DESC_PROP_EXPERIMENTER_PACK_STR = '!HHII'
+OFP_PORT_DESC_PROP_EXPERIMENTER_SIZE = 12
+assert (calcsize(OFP_PORT_DESC_PROP_EXPERIMENTER_PACK_STR) ==
+ OFP_PORT_DESC_PROP_EXPERIMENTER_SIZE)
+
+# struct ofp_port
+OFP_MAX_PORT_NAME_LEN = 16
+OFP_ETH_ALEN = 6
+OFP_ETH_ALEN_STR = str(OFP_ETH_ALEN)
+_OFP_PORT_PACK_STR = 'IH2x' + OFP_ETH_ALEN_STR + 's' + '2x' + \
+ str(OFP_MAX_PORT_NAME_LEN) + 's' + 'II'
+OFP_PORT_PACK_STR = '!' + _OFP_PORT_PACK_STR
+OFP_PORT_SIZE = 40
+assert (calcsize(OFP_PORT_PACK_STR) == OFP_PORT_SIZE)
+
+# struct ofp_switch_features
+OFP_SWITCH_FEATURES_PACK_STR = '!QIBB2xII'
+OFP_SWITCH_FEATURES_SIZE = 32
+assert (calcsize(OFP_SWITCH_FEATURES_PACK_STR) + OFP_HEADER_SIZE ==
+ OFP_SWITCH_FEATURES_SIZE)
+
+# enum ofp_port_reason
+OFPPR_ADD = 0 # The port was added.
+OFPPR_DELETE = 1 # The port was removed.
+OFPPR_MODIFY = 2 # Some attribute of the port has changed.
+
+# struct ofp_port_status
+OFP_PORT_STATUS_PACK_STR = '!B7x' + _OFP_PORT_PACK_STR
+OFP_PORT_STATUS_SIZE = 56
+assert (calcsize(OFP_PORT_STATUS_PACK_STR) + OFP_HEADER_SIZE ==
+ OFP_PORT_STATUS_SIZE)
+
+# enum ofp_port_mod_prop_type
+OFPPMPT_ETHERNET = 0 # Ethernet property.
+OFPPMPT_OPTICAL = 1 # Optical property.
+OFPPMPT_EXPERIMENTER = 0xFFFF # Experimenter property.
+
+# struct ofp_port_mod_prop_ethernet
+OFP_PORT_MOD_PROP_ETHERNET_PACK_STR = '!HHI'
+OFP_PORT_MOD_PROP_ETHERNET_SIZE = 8
+assert (calcsize(OFP_PORT_MOD_PROP_ETHERNET_PACK_STR) ==
+ OFP_PORT_MOD_PROP_ETHERNET_SIZE)
+
+# struct ofp_port_mod_prop_optical
+OFP_PORT_MOD_PROP_OPTICAL_PACK_STR = '!HHIIIII'
+OFP_PORT_MOD_PROP_OPTICAL_SIZE = 24
+assert (calcsize(OFP_PORT_MOD_PROP_OPTICAL_PACK_STR) ==
+ OFP_PORT_MOD_PROP_OPTICAL_SIZE)
+
+# struct ofp_port_mod_prop_experimenter
+OFP_PORT_MOD_PROP_EXPERIMENTER_PACK_STR = '!HHII'
+OFP_PORT_MOD_PROP_EXPERIMENTER_SIZE = 12
+assert (calcsize(OFP_PORT_MOD_PROP_EXPERIMENTER_PACK_STR) ==
+ OFP_PORT_MOD_PROP_EXPERIMENTER_SIZE)
+
+# struct ofp_port_mod
+OFP_PORT_MOD_PACK_STR = '!I4x' + OFP_ETH_ALEN_STR + 's2xII'
+OFP_PORT_MOD_SIZE = 32
+assert (calcsize(OFP_PORT_MOD_PACK_STR) + OFP_HEADER_SIZE ==
+ OFP_PORT_MOD_SIZE)
+
+# enum ofp_header_type_namespaces
+OFPHTN_ONF = 0 # ONF namespace.
+OFPHTN_ETHERTYPE = 1 # ns_type is an Ethertype.
+OFPHTN_IP_PROTO = 2 # ns_type is a IP protocol number.
+OFPHTN_UDP_TCP_PORT = 3 # ns_type is a TCP or UDP port.
+OFPHTN_IPV4_OPTION = 4 # ns_type is an IPv4 option number.
+
+# enum ofp_header_type_onf
+OFPHTO_ETHERNET = 0 # Ethernet (DIX or IEEE 802.3) - default.
+OFPHTO_NO_HEADER = 1 # No header, ex. circuit switch.
+OFPHTO_OXM_EXPERIMENTER = 0xFFFF # Use Experimenter OXM.
+
+# struct ofp_header_type
+OFP_HEADER_TYPE_PACK_STR = '!HH'
+OFP_HEADER_TYPE_SIZE = 4
+assert (calcsize(OFP_HEADER_TYPE_PACK_STR) ==
+ OFP_HEADER_TYPE_SIZE)
+
+# enum ofp_match_type
+OFPMT_STANDARD = 0 # Deprecated
+OFPMT_OXM = 1 # OpenFlow Extensible Match
+
+# struct ofp_match
+_OFP_MATCH_PACK_STR = 'HH4x'
+OFP_MATCH_PACK_STR = '!' + _OFP_MATCH_PACK_STR
+OFP_MATCH_SIZE = 8
+assert calcsize(OFP_MATCH_PACK_STR) == OFP_MATCH_SIZE
+
+# enum ofp_oxm_class
+OFPXMC_NXM_0 = 0x0000 # Backward compatibility with NXM
+OFPXMC_NXM_1 = 0x0001 # Backward compatibility with NXM
+OFPXMC_OPENFLOW_BASIC = 0x8000 # Basic class for OpenFlow
+OFPXMC_PACKET_REGS = 0x8001 # Packet registers (pipeline fields).
+OFPXMC_EXPERIMENTER = 0xFFFF # Experimenter class
+
+# enum ofp_vlan_id
+OFPVID_PRESENT = 0x1000 # bit that indicate that a VLAN id is set.
+OFPVID_NONE = 0X0000 # No VLAN id was set.
+
+
+def _oxm_tlv_header(class_, field, hasmask, length):
+ return (class_ << 16) | (field << 9) | (hasmask << 8) | length
+
+
+def oxm_tlv_header(field, length):
+ return _oxm_tlv_header(OFPXMC_OPENFLOW_BASIC, field, 0, length)
+
+
+def oxm_tlv_header_w(field, length):
+ return _oxm_tlv_header(OFPXMC_OPENFLOW_BASIC, field, 1, length * 2)
+
+
+def oxm_tlv_header_extract_hasmask(header):
+ return (header >> 8) & 1
+
+
+def oxm_tlv_header_extract_length(header):
+ if oxm_tlv_header_extract_hasmask(header):
+ length = (header & 0xff) / 2
+ else:
+ length = header & 0xff
+ return length
+
+oxm_types = [
+ oxm_fields.OpenFlowBasic('in_port', 0, type_desc.Int4),
+ oxm_fields.OpenFlowBasic('in_phy_port', 1, type_desc.Int4),
+ oxm_fields.OpenFlowBasic('metadata', 2, type_desc.Int8),
+ oxm_fields.OpenFlowBasic('eth_dst', 3, type_desc.MacAddr),
+ oxm_fields.OpenFlowBasic('eth_src', 4, type_desc.MacAddr),
+ oxm_fields.OpenFlowBasic('eth_type', 5, type_desc.Int2),
+ oxm_fields.OpenFlowBasic('vlan_vid', 6, type_desc.Int2),
+ oxm_fields.OpenFlowBasic('vlan_pcp', 7, type_desc.Int1),
+ oxm_fields.OpenFlowBasic('ip_dscp', 8, type_desc.Int1),
+ oxm_fields.OpenFlowBasic('ip_ecn', 9, type_desc.Int1),
+ oxm_fields.OpenFlowBasic('ip_proto', 10, type_desc.Int1),
+ oxm_fields.OpenFlowBasic('ipv4_src', 11, type_desc.IPv4Addr),
+ oxm_fields.OpenFlowBasic('ipv4_dst', 12, type_desc.IPv4Addr),
+ oxm_fields.OpenFlowBasic('tcp_src', 13, type_desc.Int2),
+ oxm_fields.OpenFlowBasic('tcp_dst', 14, type_desc.Int2),
+ oxm_fields.OpenFlowBasic('udp_src', 15, type_desc.Int2),
+ oxm_fields.OpenFlowBasic('udp_dst', 16, type_desc.Int2),
+ oxm_fields.OpenFlowBasic('sctp_src', 17, type_desc.Int2),
+ oxm_fields.OpenFlowBasic('sctp_dst', 18, type_desc.Int2),
+ oxm_fields.OpenFlowBasic('icmpv4_type', 19, type_desc.Int1),
+ oxm_fields.OpenFlowBasic('icmpv4_code', 20, type_desc.Int1),
+ oxm_fields.OpenFlowBasic('arp_op', 21, type_desc.Int2),
+ oxm_fields.OpenFlowBasic('arp_spa', 22, type_desc.IPv4Addr),
+ oxm_fields.OpenFlowBasic('arp_tpa', 23, type_desc.IPv4Addr),
+ oxm_fields.OpenFlowBasic('arp_sha', 24, type_desc.MacAddr),
+ oxm_fields.OpenFlowBasic('arp_tha', 25, type_desc.MacAddr),
+ oxm_fields.OpenFlowBasic('ipv6_src', 26, type_desc.IPv6Addr),
+ oxm_fields.OpenFlowBasic('ipv6_dst', 27, type_desc.IPv6Addr),
+ oxm_fields.OpenFlowBasic('ipv6_flabel', 28, type_desc.Int4),
+ oxm_fields.OpenFlowBasic('icmpv6_type', 29, type_desc.Int1),
+ oxm_fields.OpenFlowBasic('icmpv6_code', 30, type_desc.Int1),
+ oxm_fields.OpenFlowBasic('ipv6_nd_target', 31, type_desc.IPv6Addr),
+ oxm_fields.OpenFlowBasic('ipv6_nd_sll', 32, type_desc.MacAddr),
+ oxm_fields.OpenFlowBasic('ipv6_nd_tll', 33, type_desc.MacAddr),
+ oxm_fields.OpenFlowBasic('mpls_label', 34, type_desc.Int4),
+ oxm_fields.OpenFlowBasic('mpls_tc', 35, type_desc.Int1),
+ oxm_fields.OpenFlowBasic('mpls_bos', 36, type_desc.Int1),
+ oxm_fields.OpenFlowBasic('pbb_isid', 37, type_desc.Int3),
+ oxm_fields.OpenFlowBasic('tunnel_id', 38, type_desc.Int8),
+ oxm_fields.OpenFlowBasic('ipv6_exthdr', 39, type_desc.Int2),
+ oxm_fields.OpenFlowBasic('pbb_uca', 41, type_desc.Int1),
+ oxm_fields.OpenFlowBasic('tcp_flags', 42, type_desc.Int2),
+ oxm_fields.OpenFlowBasic('actset_output', 43, type_desc.Int4),
+ oxm_fields.OpenFlowBasic('packet_type', 44, type_desc.Int4),
+ oxm_fields.NiciraExtended1('tun_ipv4_src', 31, type_desc.IPv4Addr),
+ oxm_fields.NiciraExtended1('tun_ipv4_dst', 32, type_desc.IPv4Addr),
+]
+
+oxm_fields.generate(__name__)
+
+# struct ofp_stats
+_OFP_STATS_PACK_STR = 'HH4x'
+OFP_STATS_PACK_STR = '!' + _OFP_STATS_PACK_STR
+OFP_STATS_SIZE = 8
+assert calcsize(OFP_STATS_PACK_STR) == OFP_STATS_SIZE
+
+# enum ofp_oxs_class
+OFPXSC_OPENFLOW_BASIC = 0x8002 # Basic stats class for OpenFlow
+OFPXSC_EXPERIMENTER = 0xFFFF # Experimenter class
+
+# enum oxs_ofb_stat_fields
+OFPXST_OFB_DURATION = 0 # Time flow entry has been alive.
+OFPXST_OFB_IDLE_TIME = 1 # Time flow entry has been idle.
+OFPXST_OFB_FLOW_COUNT = 3 # Number of aggregated flow entries.
+OFPXST_OFB_PACKET_COUNT = 4 # Number of packets in flow entry.
+OFPXST_OFB_BYTE_COUNT = 5 # Number of bytes in flow entry.
+
+# enum ofp_action_type
+OFPAT_OUTPUT = 0 # Output to switch port.
+OFPAT_COPY_TTL_OUT = 11 # Copy TTL "outwards" -- from
+ # next-to-outermost to outermost
+OFPAT_COPY_TTL_IN = 12 # Copy TTL "inwards" -- from outermost to
+ # next-to-outermost
+OFPAT_SET_MPLS_TTL = 15 # MPLS TTL.
+OFPAT_DEC_MPLS_TTL = 16 # Decrement MPLS TTL
+OFPAT_PUSH_VLAN = 17 # Push a new VLAN tag
+OFPAT_POP_VLAN = 18 # Pop the outer VLAN tag
+OFPAT_PUSH_MPLS = 19 # Push a new MPLS tag
+OFPAT_POP_MPLS = 20 # Pop the outer MPLS tag
+OFPAT_SET_QUEUE = 21 # Set queue id when outputting to a port
+OFPAT_GROUP = 22 # Apply group
+OFPAT_SET_NW_TTL = 23 # IP TTL.
+OFPAT_DEC_NW_TTL = 24 # Decrement IP TTL.
+OFPAT_SET_FIELD = 25 # Set a header field using OXM TLV format.
+OFPAT_PUSH_PBB = 26 # Push a new PBB service tag (I-TAG)
+OFPAT_POP_PBB = 27 # Pop the outer PBB service tag (I-TAG)
+OFPAT_COPY_FIELD = 28 # Copy value between header and register.
+OFPAT_METER = 29 # Apply meter (rate limiter)
+OFPAT_EXPERIMENTER = 0xffff
+
+
+# struct ofp_action_header
+OFP_ACTION_HEADER_PACK_STR = '!HH4x'
+OFP_ACTION_HEADER_SIZE = 8
+assert calcsize(OFP_ACTION_HEADER_PACK_STR) == OFP_ACTION_HEADER_SIZE
+
+# enum ofp_controller_max_len
+OFPCML_MAX = 0xffe5 # maximum max_len value which can be used to
+ # request a specific byte length.
+OFPCML_NO_BUFFER = 0xffff # indicates that no buffering should be
+ # applied and the whole packet is to be
+ # sent to the controller.
+
+# struct ofp_action_output
+OFP_ACTION_OUTPUT_PACK_STR = '!HHIH6x'
+OFP_ACTION_OUTPUT_SIZE = 16
+assert calcsize(OFP_ACTION_OUTPUT_PACK_STR) == OFP_ACTION_OUTPUT_SIZE
+
+# struct ofp_action_generic
+OFP_ACTION_GENERIC_PACK_STR = '!HH4x'
+OFP_ACTION_GENERIC_SIZE = 8
+assert (calcsize(OFP_ACTION_GENERIC_PACK_STR) == OFP_ACTION_GENERIC_SIZE)
+
+# struct ofp_action_mpls_ttl
+OFP_ACTION_MPLS_TTL_PACK_STR = '!HHB3x'
+OFP_ACTION_MPLS_TTL_SIZE = 8
+assert calcsize(OFP_ACTION_MPLS_TTL_PACK_STR) == OFP_ACTION_MPLS_TTL_SIZE
+
+# struct ofp_action_push
+OFP_ACTION_PUSH_PACK_STR = '!HHH2x'
+OFP_ACTION_PUSH_SIZE = 8
+assert calcsize(OFP_ACTION_PUSH_PACK_STR) == OFP_ACTION_PUSH_SIZE
+
+# struct ofp_action_pop_mpls
+OFP_ACTION_POP_MPLS_PACK_STR = '!HHH2x'
+OFP_ACTION_POP_MPLS_SIZE = 8
+assert calcsize(OFP_ACTION_POP_MPLS_PACK_STR) == OFP_ACTION_POP_MPLS_SIZE
+
+# struct ofp_action_set_queue
+OFP_ACTION_SET_QUEUE_PACK_STR = '!HHI'
+OFP_ACTION_SET_QUEUE_SIZE = 8
+assert calcsize(OFP_ACTION_SET_QUEUE_PACK_STR) == OFP_ACTION_SET_QUEUE_SIZE
+
+# struct ofp_action_group
+OFP_ACTION_GROUP_PACK_STR = '!HHI'
+OFP_ACTION_GROUP_SIZE = 8
+assert calcsize(OFP_ACTION_GROUP_PACK_STR) == OFP_ACTION_GROUP_SIZE
+
+# struct ofp_action_nw_ttl
+OFP_ACTION_NW_TTL_PACK_STR = '!HHB3x'
+OFP_ACTION_NW_TTL_SIZE = 8
+assert calcsize(OFP_ACTION_NW_TTL_PACK_STR) == OFP_ACTION_NW_TTL_SIZE
+
+# struct ofp_action_set_field
+OFP_ACTION_SET_FIELD_PACK_STR = '!HH4x'
+OFP_ACTION_SET_FIELD_SIZE = 8
+assert calcsize(OFP_ACTION_SET_FIELD_PACK_STR) == OFP_ACTION_SET_FIELD_SIZE
+
+# struct ofp_action_copy_field
+OFP_ACTION_COPY_FIELD_PACK_STR = '!HHHHH2x'
+OFP_ACTION_COPY_FIELD_SIZE = 12
+assert calcsize(OFP_ACTION_COPY_FIELD_PACK_STR) == OFP_ACTION_COPY_FIELD_SIZE
+
+# struct ofp_action_meter
+OFP_ACTION_METER_PACK_STR = '!HHI'
+OFP_ACTION_METER_SIZE = 8
+assert calcsize(OFP_ACTION_METER_PACK_STR) == OFP_ACTION_METER_SIZE
+
+# struct ofp_action_experimenter_header
+OFP_ACTION_EXPERIMENTER_HEADER_PACK_STR = '!HHI'
+OFP_ACTION_EXPERIMENTER_HEADER_SIZE = 8
+assert (calcsize(OFP_ACTION_EXPERIMENTER_HEADER_PACK_STR) ==
+ OFP_ACTION_EXPERIMENTER_HEADER_SIZE)
+
+# enum ofp_instruction_type
+OFPIT_GOTO_TABLE = 1 # Setup the next table in the lookup pipeline.
+OFPIT_WRITE_METADATA = 2 # Setup the metadata field for use later in
+ # pipeline.
+OFPIT_WRITE_ACTIONS = 3 # Write the action(s) onto the datapath
+ # action set
+OFPIT_APPLY_ACTIONS = 4 # Applies the action(s) immediately
+OFPIT_CLEAR_ACTIONS = 5 # Clears all actions from the datapath action
+ # set
+OFPIT_DEPRECATED = 6 # Deprecated (was apply meter)
+OFPIT_STAT_TRIGGER = 7 # Statistics triggers
+OFPIT_EXPERIMENTER = 0xFFFF # Experimenter instruction
+
+# struct ofp_instruction_goto_table
+OFP_INSTRUCTION_GOTO_TABLE_PACK_STR = '!HHB3x'
+OFP_INSTRUCTION_GOTO_TABLE_SIZE = 8
+assert (calcsize(OFP_INSTRUCTION_GOTO_TABLE_PACK_STR) ==
+ OFP_INSTRUCTION_GOTO_TABLE_SIZE)
+
+# struct ofp_instruction_write_metadata
+OFP_INSTRUCTION_WRITE_METADATA_PACK_STR = '!HH4xQQ'
+OFP_INSTRUCTION_WRITE_METADATA_SIZE = 24
+assert (calcsize(OFP_INSTRUCTION_WRITE_METADATA_PACK_STR) ==
+ OFP_INSTRUCTION_WRITE_METADATA_SIZE)
+
+# struct ofp_instruction_actions
+OFP_INSTRUCTION_ACTIONS_PACK_STR = '!HH4x'
+OFP_INSTRUCTION_ACTIONS_SIZE = 8
+assert (calcsize(OFP_INSTRUCTION_ACTIONS_PACK_STR) ==
+ OFP_INSTRUCTION_ACTIONS_SIZE)
+
+# enum ofp_stat_trigger_flags
+OFPSTF_PERIODIC = 1 << 0 # Trigger for all multiples of thresholds.
+OFPSTF_ONLY_FIRST = 1 << 1 # Trigger on only first reach threshold.
+
+# struct ofp_instruction_stat_trigger
+_OFP_INSTRUCTION_STAT_TRIGGER_PACK_STR0 = 'HHI'
+OFP_INSTRUCTION_STAT_TRIGGER_PACK_STR = (
+ '!' + _OFP_INSTRUCTION_STAT_TRIGGER_PACK_STR0 + _OFP_STATS_PACK_STR)
+OFP_INSTRUCTION_STAT_TRIGGER_PACK_STR0 = (
+ '!' + _OFP_INSTRUCTION_STAT_TRIGGER_PACK_STR0)
+OFP_INSTRUCTION_STAT_TRIGGER_PACK_SIZE = 16
+assert (calcsize(OFP_INSTRUCTION_STAT_TRIGGER_PACK_STR) ==
+ OFP_INSTRUCTION_STAT_TRIGGER_PACK_SIZE)
+
+# struct ofp_instruction_experimenter_header
+OFP_INSTRUCTION_EXPERIMENTER_HEADER_PACK_STR = '!HHI'
+OFP_INSTRUCTION_EXPERIMENTER_HEADER_SIZE = 8
+assert (calcsize(OFP_INSTRUCTION_EXPERIMENTER_HEADER_PACK_STR) ==
+ OFP_INSTRUCTION_EXPERIMENTER_HEADER_SIZE)
+
+# enum ofp_flow_mod_command
+OFPFC_ADD = 0 # New flow.
+OFPFC_MODIFY = 1 # Modify all matching flows.
+OFPFC_MODIFY_STRICT = 2 # Modify entry strictly matching wildcards
+OFPFC_DELETE = 3 # Delete all matching flows.
+OFPFC_DELETE_STRICT = 4 # Strictly match wildcards and priority.
+
+# Value used in "idle_timeout" and "hard_timeout" to indicate that the
+# entry is permanent. */
+OFP_FLOW_PERMANENT = 0
+
+# By default, choose a priority in the middle.
+OFP_DEFAULT_PRIORITY = 0x8000
+
+# enum ofp_flow_mod_flags
+OFPFF_SEND_FLOW_REM = 1 << 0 # Send flow removed message when flow
+ # expires or is deleted.
+OFPFF_CHECK_OVERLAP = 1 << 1 # Check for overlapping entries first.
+OFPFF_RESET_COUNTS = 1 << 2 # Reset flow packet and byte counts.
+OFPFF_NO_PKT_COUNTS = 1 << 3 # Don't keep track of packet count.
+OFPFF_NO_BYT_COUNTS = 1 << 4 # Don't keep track of byte count.
+
+# struct ofp_flow_mod
+_OFP_FLOW_MOD_PACK_STR0 = 'QQBBHHHIIIHH'
+OFP_FLOW_MOD_PACK_STR = '!' + _OFP_FLOW_MOD_PACK_STR0 + _OFP_MATCH_PACK_STR
+OFP_FLOW_MOD_PACK_STR0 = '!' + _OFP_FLOW_MOD_PACK_STR0
+OFP_FLOW_MOD_SIZE = 56
+assert (calcsize(OFP_FLOW_MOD_PACK_STR) + OFP_HEADER_SIZE ==
+ OFP_FLOW_MOD_SIZE)
+
+# enum ofp_group
+OFPG_MAX = 0xffffff00 # Last usable group number.
+OFPG_ALL = 0xfffffffc # Represents all groups for group delete commands.
+OFPG_ANY = 0xffffffff # Special wildcard: no group specified.
+
+# enum ofp_group_mod_command
+OFPGC_ADD = 0 # New group.
+OFPGC_MODIFY = 1 # Modify all matching groups.
+OFPGC_DELETE = 2 # Delete all matching groups.
+OFPGC_INSERT_BUCKET = 3 # Insert action buckets to the already available
+ # list of action buckets in a matching group
+# OFPGC_??? = 4 # Reserved for future use.
+OFPGC_REMOVE_BUCKET = 5 # Remove all action buckets or any specific action
+ # bucket from matching group
+
+# enum ofp_group_bucket_prop_type
+OFPGBPT_WEIGHT = 0 # Select groups only.
+OFPGBPT_WATCH_PORT = 1 # Fast failover groups only.
+OFPGBPT_WATCH_GROU = 2 # Fast failover groups only.
+OFPGBPT_EXPERIMENTER = 0xFFFF # Experimenter defined.
+
+# struct ofp_group_bucket_prop_header
+OFP_GROUP_BUCKET_PROP_HEADER_PACK_STR = '!HH'
+OFP_GROUP_BUCKET_PROP_HEADER_SIZE = 4
+assert (calcsize(OFP_GROUP_BUCKET_PROP_HEADER_PACK_STR) ==
+ OFP_GROUP_BUCKET_PROP_HEADER_SIZE)
+
+# struct ofp_group_bucket_prop_weight
+OFP_GROUP_BUCKET_PROP_WEIGHT_PACK_STR = '!HHH2x'
+OFP_GROUP_BUCKET_PROP_WEIGHT_SIZE = 8
+assert (calcsize(OFP_GROUP_BUCKET_PROP_WEIGHT_PACK_STR) ==
+ OFP_GROUP_BUCKET_PROP_WEIGHT_SIZE)
+
+# struct ofp_group_bucket_prop_watch
+OFP_GROUP_BUCKET_PROP_WATCH_PACK_STR = '!HHI'
+OFP_GROUP_BUCKET_PROP_WATCH_SIZE = 8
+assert (calcsize(OFP_GROUP_BUCKET_PROP_WATCH_PACK_STR) ==
+ OFP_GROUP_BUCKET_PROP_WATCH_SIZE)
+
+# struct ofp_group_bucket_prop_experimenter
+OFP_GROUP_BUCKET_PROP_EXPERIMENTER_PACK_STR = '!HHII'
+OFP_GROUP_BUCKET_PROP_EXPERIMENTER_SIZE = 12
+assert (calcsize(OFP_GROUP_BUCKET_PROP_EXPERIMENTER_PACK_STR) ==
+ OFP_GROUP_BUCKET_PROP_EXPERIMENTER_SIZE)
+
+# struct ofp_bucket
+OFP_BUCKET_PACK_STR = '!HHI'
+OFP_BUCKET_SIZE = 8
+assert calcsize(OFP_BUCKET_PACK_STR) == OFP_BUCKET_SIZE
+
+# enum ofp_group_bucket
+OFPG_BUCKET_MAX = 0xffffff00 # Last usable bucket ID.
+OFPG_BUCKET_FIRST = 0xfffffffd # First bucket ID in the list of action
+ # buckets of a group. This is applicable
+ # for OFPGC_INSERT_BUCKET and
+ # OFPGC_REMOVE_BUCKET commands.
+OFPG_BUCKET_LAST = 0xfffffffe # Last bucket ID in the list of action
+ # buckets of a group. This is applicable
+ # for OFPGC_INSERT_BUCKET and
+ # OFPGC_REMOVE_BUCKET commands.
+OFPG_BUCKET_ALL = 0xffffffff # All action buckets in a group,
+ # This is applicable for
+ # only OFPGC_REMOVE_BUCKET command.
+
+# enum ofp_group_prop_type
+OFPGPT_EXPERIMENTER = 0xFFFF # Experimenter defined.
+
+# struct ofp_group_prop_header
+OFP_GROUP_PROP_HEADER_PACK_STR = '!HH'
+OFP_GROUP_PROP_HEADER_SIZE = 4
+assert (calcsize(OFP_GROUP_PROP_HEADER_PACK_STR) ==
+ OFP_GROUP_PROP_HEADER_SIZE)
+
+# struct ofp_group_prop_experimenter
+OFP_GROUP_PROP_EXPERIMENTER_PACK_STR = '!HHII'
+OFP_GROUP_PROP_EXPERIMENTER_SIZE = 12
+assert (calcsize(OFP_GROUP_PROP_EXPERIMENTER_PACK_STR) ==
+ OFP_GROUP_PROP_EXPERIMENTER_SIZE)
+
+# struct ofp_group_mod
+OFP_GROUP_MOD_PACK_STR = '!HBxIH2xI'
+OFP_GROUP_MOD_SIZE = 24
+assert (calcsize(OFP_GROUP_MOD_PACK_STR) + OFP_HEADER_SIZE ==
+ OFP_GROUP_MOD_SIZE)
+
+# enum ofp_group_type
+OFPGT_ALL = 0 # All (multicast/broadcast) group.
+OFPGT_SELECT = 1 # Select group.
+OFPGT_INDIRECT = 2 # Indirect group.
+OFPGT_FF = 3 # Fast failover group.
+
+
+OFP_NO_BUFFER = 0xffffffff # Special buffer-id to indicate 'no buffer'
+
+# struct ofp_packet_out
+OFP_PACKET_OUT_PACK_STR = '!IH2x'
+OFP_PACKET_OUT_SIZE = 24
+assert (calcsize(OFP_PACKET_OUT_PACK_STR) + OFP_MATCH_SIZE + OFP_HEADER_SIZE ==
+ OFP_PACKET_OUT_SIZE)
+
+# enum ofp_packet_in_reason
+OFPR_TABLE_MISS = 0 # No matching flow (table-miss flow entry).
+OFPR_APPLY_ACTION = 1 # Output to controller in apply-actions.
+OFPR_INVALID_TTL = 2 # Packet has invalid TTL.
+OFPR_ACTION_SET = 3 # Output to controller in action set.
+OFPR_GROUP = 4 # Output to controller in group bucket.
+OFPR_PACKET_OUT = 5 # Output to controller in packet-out.
+
+# struct ofp_packet_in
+OFP_PACKET_IN_PACK_STR = '!IHBBQ'
+OFP_PACKET_IN_SIZE = 32
+assert (calcsize(OFP_PACKET_IN_PACK_STR) + OFP_MATCH_SIZE + OFP_HEADER_SIZE ==
+ OFP_PACKET_IN_SIZE)
+
+# enum ofp_flow_removed_reason
+OFPRR_IDLE_TIMEOUT = 0 # Flow idle time exceeded idle_timeout.
+OFPRR_HARD_TIMEOUT = 1 # Time exceeded hard_timeout.
+OFPRR_DELETE = 2 # Evicted by a DELETE flow mod.
+OFPRR_GROUP_DELETE = 3 # Group was removed.
+OFPRR_METER_DELETE = 4 # Meter was removed.
+OFPRR_EVICTION = 5 # Switch eviction to free resources.
+
+# struct ofp_port_status
+OFP_PORT_STATUS_PACK_STR = '!B7x' + _OFP_PORT_PACK_STR
+OFP_PORT_STATUS_DESC_OFFSET = OFP_HEADER_SIZE + 8
+OFP_PORT_STATUS_SIZE = 56
+assert (calcsize(OFP_PORT_STATUS_PACK_STR) + OFP_HEADER_SIZE ==
+ OFP_PORT_STATUS_SIZE)
+
+# struct ofp_flow_removed
+_OFP_FLOW_REMOVED_PACK_STR0 = 'BBHHHQ'
+OFP_FLOW_REMOVED_PACK_STR = '!' + _OFP_FLOW_REMOVED_PACK_STR0 + \
+ _OFP_MATCH_PACK_STR
+OFP_FLOW_REMOVED_PACK_STR0 = '!' + _OFP_FLOW_REMOVED_PACK_STR0
+OFP_FLOW_REMOVED_SIZE = 32
+assert (calcsize(OFP_FLOW_REMOVED_PACK_STR) + OFP_HEADER_SIZE ==
+ OFP_FLOW_REMOVED_SIZE)
+
+# enum ofp_meter
+OFPM_MAX = 0xffff0000
+OFPM_SLOWPATH = 0xfffffffd # Meter for slow datapath, if any.
+OFPM_CONTROLLER = 0xfffffffe # Meter for controller connection.
+OFPM_ALL = 0xffffffff # Represents all meters for stat requests
+ # commands.
+
+# enum ofp_meter_band_type
+OFPMBT_DROP = 1 # Drop packet.
+OFPMBT_DSCP_REMARK = 2 # Remark DSCP in the IP header.
+OFPMBT_EXPERIMENTER = 0xFFFF # Experimenter meter band.
+
+# struct ofp_meter_band_drop
+OFP_METER_BAND_DROP_PACK_STR = '!HHII4x'
+OFP_METER_BAND_DROP_SIZE = 16
+assert (calcsize(OFP_METER_BAND_DROP_PACK_STR) ==
+ OFP_METER_BAND_DROP_SIZE)
+
+# struct ofp_meter_band_dscp_remark
+OFP_METER_BAND_DSCP_REMARK_PACK_STR = '!HHIIB3x'
+OFP_METER_BAND_DSCP_REMARK_SIZE = 16
+assert (calcsize(OFP_METER_BAND_DSCP_REMARK_PACK_STR) ==
+ OFP_METER_BAND_DSCP_REMARK_SIZE)
+
+# struct ofp_meter_band_experimenter
+OFP_METER_BAND_EXPERIMENTER_PACK_STR = '!HHIII'
+OFP_METER_BAND_EXPERIMENTER_SIZE = 16
+assert (calcsize(OFP_METER_BAND_EXPERIMENTER_PACK_STR) ==
+ OFP_METER_BAND_EXPERIMENTER_SIZE)
+
+# enum ofp_meter_mod_command
+OFPMC_ADD = 0 # New meter.
+OFPMC_MODIFY = 1 # Modify specified meter.
+OFPMC_DELETE = 2 # Delete specified meter.
+
+# enum ofp_meter_flags
+OFPMF_KBPS = 1 << 0 # Rate value in kb/s (kilo-bit per second).
+OFPMF_PKTPS = 1 << 1 # Rate value in packet/sec.
+OFPMF_BURST = 1 << 2 # Do burst size.
+OFPMF_STATS = 1 << 3 # Collect statistics.
+
+# struct ofp_meter_band_header
+OFP_METER_BAND_HEADER_PACK_STR = '!HHII'
+OFP_METER_BAND_HEADER_SIZE = 12
+assert (calcsize(OFP_METER_BAND_HEADER_PACK_STR) ==
+ OFP_METER_BAND_HEADER_SIZE)
+
+# struct ofp_meter_mod
+OFP_METER_MOD_PACK_STR = '!HHI'
+OFP_METER_MOD_SIZE = 16
+assert (calcsize(OFP_METER_MOD_PACK_STR) + OFP_HEADER_SIZE ==
+ OFP_METER_MOD_SIZE)
+
+
+# enum ofp_error_type
+OFPET_HELLO_FAILED = 0 # Hello protocol failed.
+OFPET_BAD_REQUEST = 1 # Request was not understood.
+OFPET_BAD_ACTION = 2 # Error in action description.
+OFPET_BAD_INSTRUCTION = 3 # Error in instruction list.
+OFPET_BAD_MATCH = 4 # Error in match.
+OFPET_FLOW_MOD_FAILED = 5 # Problem modifying flow entry.
+OFPET_GROUP_MOD_FAILED = 6 # Problem modifying group entry.
+OFPET_PORT_MOD_FAILED = 7 # OFPT_PORT_MOD failed.
+OFPET_TABLE_MOD_FAILED = 8 # Table mod request failed.
+OFPET_QUEUE_OP_FAILED = 9 # Queue operation failed.
+OFPET_SWITCH_CONFIG_FAILED = 10 # Switch config request failed.
+OFPET_ROLE_REQUEST_FAILED = 11 # Controller Role request failed.
+OFPET_METER_MOD_FAILED = 12 # Error in meter.
+OFPET_TABLE_FEATURES_FAILED = 13 # Setting table features failed.
+OFPET_BAD_PROPERTY = 14 # Some property is invalid.
+OFPET_ASYNC_CONFIG_FAILED = 15 # Asynchronous config request failed.
+OFPET_FLOW_MONITOR_FAILED = 16 # Setting flow monitor failed.
+OFPET_BUNDLE_FAILED = 17 # Bundle operation failed.
+OFPET_EXPERIMENTER = 0xffff # Experimenter error messages.
+
+# enum ofp_hello_failed_code
+OFPHFC_INCOMPATIBLE = 0 # No compatible version.
+OFPHFC_EPERM = 1 # Permissions error.
+
+# enum ofp_bad_request_code
+OFPBRC_BAD_VERSION = 0 # ofp_header.version not supported.
+OFPBRC_BAD_TYPE = 1 # ofp_header.type not supported.
+OFPBRC_BAD_MULTIPART = 2 # ofp_multipart_request.type not
+ # supported.
+OFPBRC_BAD_EXPERIMENTER = 3 # Experimenter id not supported
+ # (in ofp_experimenter_header
+ # or ofp_multipart_request or
+ # ofp_multipart_reply).
+OFPBRC_BAD_EXP_TYPE = 4 # Experimenter type not supported.
+OFPBRC_EPERM = 5 # Permissions error.
+OFPBRC_BAD_LEN = 6 # Wrong request length for type.
+OFPBRC_BUFFER_EMPTY = 7 # Specified buffer has already been
+ # used.
+OFPBRC_BUFFER_UNKNOWN = 8 # Specified buffer does not exist.
+OFPBRC_BAD_TABLE_ID = 9 # Specified table-id invalid or does
+ # not exist.
+OFPBRC_IS_SLAVE = 10 # Denied because controller is slave.
+OFPBRC_BAD_PORT = 11 # Invalid port or missing port.
+OFPBRC_BAD_PACKET = 12 # Invalid packet in packet-out
+OFPBRC_MULTIPART_BUFFER_OVERFLOW = 13 # ofp_multipart_request
+ # overflowed the assigned buffer.
+OFPBRC_MULTIPART_REQUEST_TIMEOUT = 14 # Timeout during multipart request.
+OFPBRC_MULTIPART_REPLY_TIMEOUT = 15 # Timeout during multipart reply.
+OFPBRC_MULTIPART_BAD_SCHED = 16 # Switch received a
+ # OFPMP_BUNDLE_FEATURES request and
+ # failed to update the scheduling
+ # tolerance.
+OFPBRC_PIPELINE_FIELDS_ONLY = 17 # Match fields must include only
+ # pipeline fields.
+OFPBRC_UNKNOWN = 18 # Unspecified error.
+
+
+# enum ofp_bad_action_code
+OFPBAC_BAD_TYPE = 0 # Unknown or unsupported action type.
+OFPBAC_BAD_LEN = 1 # Length problem in actions.
+OFPBAC_BAD_EXPERIMENTER = 2 # Unknown experimenter id specified.
+OFPBAC_BAD_EXP_TYPE = 3 # Unknown action type for experimenter id.
+OFPBAC_BAD_OUT_PORT = 4 # Problem validating output action.
+OFPBAC_BAD_ARGUMENT = 5 # Bad action argument.
+OFPBAC_EPERM = 6 # Permissions error.
+OFPBAC_TOO_MANY = 7 # Can't handle this many actions.
+OFPBAC_BAD_QUEUE = 8 # Problem validating output queue.
+OFPBAC_BAD_OUT_GROUP = 9 # Invalid group id in forward action.
+OFPBAC_MATCH_INCONSISTENT = 10 # Action can't apply for this match,
+ # or Set-Field missing prerequisite.
+OFPBAC_UNSUPPORTED_ORDER = 11 # Action order is unsupported for
+ # the action list in an Apply-Actions
+ # instruction
+OFPBAC_BAD_TAG = 12 # Actions uses an unsupported tag/encap.
+OFPBAC_BAD_SET_TYPE = 13 # Unsupported type in SET_FIELD action.
+OFPBAC_BAD_SET_LEN = 14 # Length problem in SET_FIELD action.
+OFPBAC_BAD_SET_ARGUMENT = 15 # Bad arguement in SET_FIELD action.
+OFPBAC_BAD_SET_MASK = 16 # Bad mask in SET_FIELD action.
+
+# enum ofp_bad_instruction_code
+OFPBIC_UNKNOWN_INST = 0 # Unknown instruction.
+OFPBIC_UNSUP_INST = 1 # Switch or table does not support
+ # the instruction.
+OFPBIC_BAD_TABLE_ID = 2 # Invalid Table-Id specified
+OFPBIC_UNSUP_METADATA = 3 # Metadata value unsupported by datapath.
+OFPBIC_UNSUP_METADATA_MASK = 4 # Metadata mask value unsupported by
+ # datapath.
+OFPBIC_BAD_EXPERIMENTER = 5 # Unknown experimenter id specified.
+OFPBIC_BAD_EXP_TYPE = 6 # Unknown instruction for experimenter id.
+OFPBIC_BAD_LEN = 7 # Length problem in instrucitons.
+OFPBIC_EPERM = 8 # Permissions error.
+OFPBIC_DUP_INST = 9 # Duplicate instruction.
+
+# enum ofp_bad_match_code
+OFPBMC_BAD_TYPE = 0 # Unsupported match type apecified by
+ # the match.
+OFPBMC_BAD_LEN = 1 # Length problem in math.
+OFPBMC_BAD_TAG = 2 # Match uses an unsupported tag/encap.
+OFPBMC_BAD_DL_ADDR_MASK = 3 # Unsupported datalink addr mask -
+ # switch does not support arbitrary
+ # datalink address mask.
+OFPBMC_BAD_NW_ADDR_MASK = 4 # Unsupported network addr mask -
+ # switch does not support arbitrary
+ # network addres mask.
+OFPBMC_BAD_WILDCARDS = 5 # Unsupported combination of fields
+ # masked or omitted in the match.
+OFPBMC_BAD_FIELD = 6 # Unsupported field type in the match.
+OFPBMC_BAD_VALUE = 7 # Unsupported value in a match field.
+OFPBMC_BAD_MASK = 8 # Unsupported mask specified in the match.
+OFPBMC_BAD_PREREQ = 9 # A prerequisite was not met.
+OFPBMC_DUP_FIELD = 10 # A field type was duplicated.
+OFPBMC_EPERM = 11 # Permissions error.
+
+# enum ofp_flow_mod_failed_code
+OFPFMFC_UNKNOWN = 0 # Unspecified error.
+OFPFMFC_TABLE_FULL = 1 # Flow not added because table was full.
+OFPFMFC_BAD_TABLE_ID = 2 # Table does not exist
+OFPFMFC_OVERLAP = 3 # Attempted to add overlapping flow with
+ # CHECK_OVERLAP flag set.
+OFPFMFC_EPERM = 4 # Permissions error.
+OFPFMFC_BAD_TIMEOUT = 5 # Flow not added because of unsupported
+ # idle/hard timeout.
+OFPFMFC_BAD_COMMAND = 6 # Unsupported or unknown command.
+OFPFMFC_BAD_FLAGS = 7 # Unsupported or unknown flags.
+OFPFMFC_CANT_SYNC = 8 # Problem in table synchronisation.
+OFPFMFC_BAD_PRIORITY = 9 # Unsupported priority value.
+OFPFMFC_IS_SYNC = 10 # Synchronised flow entry is read only.
+
+# enum ofp_group_mod_failed_code
+OFPGMFC_GROUP_EXISTS = 0 # Group not added because a group ADD
+ # attempted to replace an already-present
+ # group.
+OFPGMFC_INVALID_GROUP = 1 # Group not added because Group specified
+ # is invalid.
+OFPGMFC_WEIGHT_UNSUPPORTED = 2 # Switch does not support unequal load
+ # sharing with select groups.
+OFPGMFC_OUT_OF_GROUPS = 3 # The group table is full.
+OFPGMFC_OUT_OF_BUCKETS = 4 # The maximum number of action buckets
+ # for a group has been exceeded.
+OFPGMFC_CHAINING_UNSUPPORTED = 5 # Switch does not support groups that
+ # forward to groups.
+OFPGMFC_WATCH_UNSUPPORTED = 6 # This group cannot watch the
+ # watch_port or watch_group specified.
+OFPGMFC_LOOP = 7 # Group entry would cause a loop.
+OFPGMFC_UNKNOWN_GROUP = 8 # Group not modified because a group MODIFY
+ # attempted to modify a non-existent group.
+OFPGMFC_CHAINED_GROUP = 9 # Group not deleted because another group
+ # is forwarding to it.
+OFPGMFC_BAD_TYPE = 10 # Unsupported or unknown group type.
+OFPGMFC_BAD_COMMAND = 11 # Unsupported or unknown command.
+OFPGMFC_BAD_BUCKET = 12 # Error in bucket.
+OFPGMFC_BAD_WATCH = 13 # Error in watch port/group.
+OFPGMFC_EPERM = 14 # Permissions error.
+OFPGMFC_UNKNOWN_BUCKET = 15 # Invalid bucket identifier used in
+ # INSERT BUCKET or REMOVE BUCKET command.
+OFPGMFC_BUCKET_EXISTS = 16 # Can't insert bucket because a bucket
+ # already exist with that bucket-id.
+
+# enum ofp_port_mod_failed_code
+OFPPMFC_BAD_PORT = 0 # Specified port does not exist.
+OFPPMFC_BAD_HW_ADDR = 1 # Specified hardware address does not match
+ # the port number.
+OFPPMFC_BAD_CONFIG = 2 # Specified config is invalid.
+OFPPMFC_BAD_ADVERTISE = 3 # Specified advertise is invalid.
+OFPPMFC_EPERM = 4 # Permissions error.
+
+# enum ofp_table_mod_failed_code
+OFPTMFC_BAD_TABLE = 0 # Specified table does not exist.
+OFPTMFC_BAD_CONFIG = 1 # Specified config is invalid.
+OFPTMFC_EPERM = 2 # Permissions error
+
+# enum ofp_queue_op_failed_code
+OFPQOFC_BAD_PORT = 0 # Invalid port (or port does not exist).
+OFPQOFC_BAD_QUEUE = 1 # Queue does not exist.
+OFPQOFC_EPERM = 2 # Permissions error.
+
+# enum ofp_switch_config_failed_code
+OFPSCFC_BAD_FLAGS = 0 # Specified flags is invalid.
+OFPSCFC_BAD_LEN = 1 # Specified miss send len is invalid.
+OFPSCFC_EPERM = 2 # Permissions error.
+
+
+# enum ofp_role_request_failed_code
+OFPRRFC_STALE = 0 # Stale Message: old generation_id.
+OFPRRFC_UNSUP = 1 # Controller role change unsupported.
+OFPRRFC_BAD_ROLE = 2 # Invalid role.
+OFPRRFC_ID_UNSUP = 3 # Switch doesn't support changing ID.
+OFPRRFC_ID_IN_USE = 4 # Requested ID is in use.
+
+# enum ofp_meter_mod_failed_code
+OFPMMFC_UNKNOWN = 0 # Unspecified error.
+OFPMMFC_METER_EXISTS = 1 # Meter not added because a Meter ADD
+ # attempted to replace an existing Meter.
+OFPMMFC_INVALID_METER = 2 # Meter not added because Meter specified
+ # is invalid, or invalid meter in meter action.
+OFPMMFC_UNKNOWN_METER = 3 # Meter not modified because a Meter MODIFY
+ # attempted to modify a non-existent Meter,
+ # or bad meter in meter action.
+OFPMMFC_BAD_COMMAND = 4 # Unsupported or unknown command.
+OFPMMFC_BAD_FLAGS = 5 # Flag configuration unsupported.
+OFPMMFC_BAD_RATE = 6 # Rate unsupported.
+OFPMMFC_BAD_BURST = 7 # Burst size unsupported.
+OFPMMFC_BAD_BAND = 8 # Band unsupported.
+OFPMMFC_BAD_BAND_VALUE = 9 # Band value unsupported.
+OFPMMFC_OUT_OF_METERS = 10 # No more meters availabile.
+OFPMMFC_OUT_OF_BANDS = 11 # The maximum number of properties for a
+ # meter has been exceeded.
+
+# enum ofp_table_features_failed_code
+OFPTFFC_BAD_TABLE = 0 # Specified table does not exist.
+OFPTFFC_BAD_METADATA = 1 # Invalid metadata mask.
+OFPTFFC_EPERM = 5 # Permissions error.
+OFPTFFC_BAD_CAP = 6 # Invalid capability field.
+OFPTFFC_BAD_MAX_ENT = 7 # Invalid max_entries field.
+OFPTFFC_BAD_FEATURES = 8 # Invalid features field.
+OFPTFFC_BAD_COMMAND = 9 # Invalid command.
+OFPTFFC_TOO_MANY = 10 # Can't handle this many flow tables.
+
+# enum ofp_bad_property_code
+OFPBPC_BAD_TYPE = 0 # Unknown or unsupported property type.
+OFPBPC_BAD_LEN = 1 # Length problem in property.
+OFPBPC_BAD_VALUE = 2 # Unsupported property value.
+OFPBPC_TOO_MANY = 3 # Can't handle this many properties.
+OFPBPC_DUP_TYPE = 4 # A property type was duplicated.
+OFPBPC_BAD_EXPERIMENTER = 5 # Unknown experimenter id specified.
+OFPBPC_BAD_EXP_TYPE = 6 # Unknown exp_type for experimenter id.
+OFPBPC_BAD_EXP_VALUE = 7 # Unknown value for experimenter id.
+OFPBPC_EPERM = 8 # Permissions error.
+
+# enum ofp_async_config_failed_code
+OFPACFC_INVALID = 0 # One mask is invalid.
+OFPACFC_UNSUPPORTED = 1 # Requested configuration not supported.
+OFPACFC_EPERM = 2 # Permissions error.
+
+# enum ofp_flow_monitor_failed_code
+OFPMOFC_UNKNOWN = 0 # Unspecified error.
+OFPMOFC_MONITOR_EXISTS = 1 # Monitor not added because a Monitor ADD
+ # attempted to replace an existing
+ # Monitor.
+OFPMOFC_INVALID_MONITOR = 2 # Monitor not added because Monitor
+ # specified is invalid.
+OFPMOFC_UNKNOWN_MONITOR = 3 # Monitor not modified because a Monitor
+ # MODIFY attempted to modify a non-existent
+ # Monitor.
+OFPMOFC_BAD_COMMAND = 4 # Unsupported or unknown command.
+OFPMOFC_BAD_FLAGS = 5 # Flag configuration unsupported.
+OFPMOFC_BAD_TABLE_ID = 6 # Specified table does not exist.
+OFPMOFC_BAD_OUT = 7 # Error in output port/group.
+
+# enum ofp_bundle_failed_code
+OFPBFC_UNKNOWN = 0 # Unspecified error.
+OFPBFC_EPERM = 1 # Permissions error.
+OFPBFC_BAD_ID = 2 # Bundle ID doesn't exist.
+OFPBFC_BUNDLE_EXIST = 3 # Bundle ID already exist.
+OFPBFC_BUNDLE_CLOSED = 4 # Bundle ID is closed.
+OFPBFC_OUT_OF_BUNDLES = 5 # Too many bundles IDs.
+OFPBFC_BAD_TYPE = 6 # Unsupported or unknown message control type.
+OFPBFC_BAD_FLAGS = 7 # Unsupported, unknown, or inconsistent flags.
+OFPBFC_MSG_BAD_LEN = 8 # Length problem in included message.
+OFPBFC_MSG_BAD_XID = 9 # Inconsistent or duplicate XID.
+OFPBFC_MSG_UNSUP = 10 # Unsupported message in this bundle.
+OFPBFC_MSG_CONFLICT = 11 # Unsupported message combination in this
+ # bundle.
+OFPBFC_MSG_TOO_MANY = 12 # Can't handle this many messages in bundle.
+OFPBFC_MSG_FAILED = 13 # One message in bundle failed.
+OFPBFC_TIMEOUT = 14 # Bundle is taking too long.
+OFPBFC_BUNDLE_IN_PROGRESS = 15 # Bundle is locking the resource.
+OFPBFC_SCHED_NOT_SUPPORTED = 16 # Scheduled commit was received and
+ # scheduling is not supported.
+OFPBFC_SCHED_FUTURE = 17 # Scheduled commit time exceeds upper bound.
+OFPBFC_SCHED_PAST = 18 # Scheduled commit time exceeds lower bound.
+
+# struct ofp_error_msg
+OFP_ERROR_MSG_PACK_STR = '!HH'
+OFP_ERROR_MSG_SIZE = 12
+assert (calcsize(OFP_ERROR_MSG_PACK_STR) + OFP_HEADER_SIZE ==
+ OFP_ERROR_MSG_SIZE)
+
+# struct ofp_error_experimenter_msg
+OFP_ERROR_EXPERIMENTER_MSG_PACK_STR = '!HHI'
+OFP_ERROR_EXPERIMENTER_MSG_SIZE = 16
+assert (calcsize(OFP_ERROR_EXPERIMENTER_MSG_PACK_STR) +
+ OFP_HEADER_SIZE) == OFP_ERROR_EXPERIMENTER_MSG_SIZE
+
+# struct ofp_experimenter_header
+OFP_EXPERIMENTER_HEADER_PACK_STR = '!II'
+OFP_EXPERIMENTER_HEADER_SIZE = 16
+assert (calcsize(OFP_EXPERIMENTER_HEADER_PACK_STR) + OFP_HEADER_SIZE
+ == OFP_EXPERIMENTER_HEADER_SIZE)
+
+# enum ofp_multipart_type
+OFPMP_DESC = 0
+OFPMP_FLOW_DESC = 1
+OFPMP_AGGREGATE_STATS = 2
+OFPMP_TABLE_STATS = 3
+OFPMP_PORT_STATS = 4
+OFPMP_QUEUE_STATS = 5
+OFPMP_GROUP_STATS = 6
+OFPMP_GROUP_DESC = 7
+OFPMP_GROUP_FEATURES = 8
+OFPMP_METER_STATS = 9
+OFPMP_METER_DESC = 10
+OFPMP_METER_FEATURES = 11
+OFPMP_TABLE_FEATURES = 12
+OFPMP_PORT_DESC = 13
+OFPMP_TABLE_DESC = 14
+OFPMP_QUEUE_DESC = 15
+OFPMP_FLOW_MONITOR = 16
+OFPMP_FLOW_STATS = 17
+OFPMP_CONTROLLER_STATUS = 18
+OFPMP_BUNDLE_FEATURES = 19
+OFPMP_EXPERIMENTER = 0xffff
+
+# struct ofp_multipart_request
+OFP_MULTIPART_REQUEST_PACK_STR = '!HH4x'
+OFP_MULTIPART_REQUEST_SIZE = 16
+assert (calcsize(OFP_MULTIPART_REQUEST_PACK_STR) + OFP_HEADER_SIZE ==
+ OFP_MULTIPART_REQUEST_SIZE)
+
+# enum ofp_multipart_reply_flags
+OFPMPF_REPLY_MORE = 1 << 0 # More requests to follow.
+
+# struct ofp_multipart_reply
+OFP_MULTIPART_REPLY_PACK_STR = '!HH4x'
+OFP_MULTIPART_REPLY_SIZE = 16
+assert (calcsize(OFP_MULTIPART_REPLY_PACK_STR) + OFP_HEADER_SIZE ==
+ OFP_MULTIPART_REPLY_SIZE)
+
+DESC_STR_LEN = 256
+DESC_STR_LEN_STR = str(DESC_STR_LEN)
+SERIAL_NUM_LEN = 32
+SERIAL_NUM_LEN_STR = str(SERIAL_NUM_LEN)
+OFP_DESC_PACK_STR = '!' + \
+ DESC_STR_LEN_STR + 's' + \
+ DESC_STR_LEN_STR + 's' + \
+ DESC_STR_LEN_STR + 's' + \
+ SERIAL_NUM_LEN_STR + 's' + \
+ DESC_STR_LEN_STR + 's'
+OFP_DESC_SIZE = 1056
+assert calcsize(OFP_DESC_PACK_STR) == OFP_DESC_SIZE
+
+# struct ofp_flow_stats_request
+_OFP_FLOW_STATS_REQUEST_0_PACK_STR = 'B3xII4xQQ'
+OFP_FLOW_STATS_REQUEST_0_PACK_STR = '!' + _OFP_FLOW_STATS_REQUEST_0_PACK_STR
+OFP_FLOW_STATS_REQUEST_0_SIZE = 32
+assert (calcsize(OFP_FLOW_STATS_REQUEST_0_PACK_STR) ==
+ OFP_FLOW_STATS_REQUEST_0_SIZE)
+OFP_FLOW_STATS_REQUEST_PACK_STR = (OFP_FLOW_STATS_REQUEST_0_PACK_STR +
+ _OFP_MATCH_PACK_STR)
+OFP_FLOW_STATS_REQUEST_SIZE = 40
+assert (calcsize(OFP_FLOW_STATS_REQUEST_PACK_STR) ==
+ OFP_FLOW_STATS_REQUEST_SIZE)
+
+# struct ofp_flow_desc
+_OFP_FLOW_DESC_0_PACK_STR = 'H2xBBHHHHHQ'
+OFP_FLOW_DESC_0_PACK_STR = '!' + _OFP_FLOW_DESC_0_PACK_STR
+OFP_FLOW_DESC_0_SIZE = 24
+assert calcsize(OFP_FLOW_DESC_0_PACK_STR) == OFP_FLOW_DESC_0_SIZE
+OFP_FLOW_DESC_PACK_STR = OFP_FLOW_DESC_0_PACK_STR + _OFP_MATCH_PACK_STR
+OFP_FLOW_DESC_SIZE = 32
+assert calcsize(OFP_FLOW_DESC_PACK_STR) == OFP_FLOW_DESC_SIZE
+
+# enum ofp_flow_stats_reason
+OFPFSR_STATS_REQUEST = 0 # Reply to a OFPMP_FLOW_STATS request.
+OFPFSR_STAT_TRIGGER = 1 # Status generated by OFPIT_STAT_TRIGGER.
+
+# struct ofp_flow_stats
+_OFP_FLOW_STATS_0_PACK_STR = 'H2xBBH'
+OFP_FLOW_STATS_0_PACK_STR = '!' + _OFP_FLOW_STATS_0_PACK_STR
+OFP_FLOW_STATS_0_SIZE = 8
+assert calcsize(OFP_FLOW_STATS_0_PACK_STR) == OFP_FLOW_STATS_0_SIZE
+OFP_FLOW_STATS_PACK_STR = (OFP_FLOW_STATS_0_PACK_STR +
+ _OFP_MATCH_PACK_STR)
+OFP_FLOW_STATS_SIZE = 16
+assert calcsize(OFP_FLOW_STATS_PACK_STR) == OFP_FLOW_STATS_SIZE
+
+# struct ofp_aggregate_stats_request
+OFP_AGGREGATE_STATS_REQUEST_PACK_STR = '!B3xII4xQQ' + _OFP_MATCH_PACK_STR
+OFP_AGGREGATE_STATS_REQUEST_SIZE = 40
+assert (calcsize(OFP_AGGREGATE_STATS_REQUEST_PACK_STR) ==
+ OFP_AGGREGATE_STATS_REQUEST_SIZE)
+
+# struct ofp_aggregate_stats_reply
+OFP_AGGREGATE_STATS_REPLY_PACK_STR = OFP_STATS_PACK_STR
+OFP_AGGREGATE_STATS_REPLY_SIZE = OFP_STATS_SIZE
+assert (calcsize(OFP_AGGREGATE_STATS_REPLY_PACK_STR) ==
+ OFP_AGGREGATE_STATS_REPLY_SIZE)
+
+
+# enum ofp_table_feature_prop_type
+OFPTFPT_INSTRUCTIONS = 0
+OFPTFPT_INSTRUCTIONS_MISS = 1
+OFPTFPT_NEXT_TABLES = 2
+OFPTFPT_NEXT_TABLES_MISS = 3
+OFPTFPT_WRITE_ACTIONS = 4
+OFPTFPT_WRITE_ACTIONS_MISS = 5
+OFPTFPT_APPLY_ACTIONS = 6
+OFPTFPT_APPLY_ACTIONS_MISS = 7
+OFPTFPT_MATCH = 8
+OFPTFPT_WILDCARDS = 10
+OFPTFPT_WRITE_SETFIELD = 12
+OFPTFPT_WRITE_SETFIELD_MISS = 13
+OFPTFPT_APPLY_SETFIELD = 14
+OFPTFPT_APPLY_SETFIELD_MISS = 15
+OFPTFPT_TABLE_SYNC_FROM = 16
+OFPTFPT_WRITE_COPYFIELD = 18 # Write Copy-Field property.
+OFPTFPT_WRITE_COPYFIELD_MISS = 19 # Write Copy-Field for table-miss.
+OFPTFPT_APPLY_COPYFIELD = 20 # Apply Copy-Field property.
+OFPTFPT_APPLY_COPYFIELD_MISS = 21 # Apply Copy-Field for table-miss.
+OFPTFPT_PACKET_TYPES = 22 # Packet types property.
+OFPTFPT_EXPERIMENTER = 0xFFFE
+OFPTFPT_EXPERIMENTER_MISS = 0xFFFF
+
+# struct ofp_instruction_id
+OFP_INSTRUCTION_ID_PACK_STR = '!HH'
+OFP_INSTRUCTION_ID_SIZE = 4
+assert calcsize(OFP_INSTRUCTION_ID_PACK_STR) == OFP_INSTRUCTION_ID_SIZE
+
+# struct ofp_table_feature_prop_instructions
+OFP_TABLE_FEATURE_PROP_INSTRUCTIONS_PACK_STR = '!HH'
+OFP_TABLE_FEATURE_PROP_INSTRUCTIONS_SIZE = 4
+assert (calcsize(OFP_TABLE_FEATURE_PROP_INSTRUCTIONS_PACK_STR) ==
+ OFP_TABLE_FEATURE_PROP_INSTRUCTIONS_SIZE)
+
+# struct ofp_table_feature_prop_actions
+OFP_TABLE_FEATURE_PROP_ACTIONS_PACK_STR = '!HH'
+OFP_TABLE_FEATURE_PROP_ACTIONS_SIZE = 4
+assert (calcsize(OFP_TABLE_FEATURE_PROP_ACTIONS_PACK_STR) ==
+ OFP_TABLE_FEATURE_PROP_ACTIONS_SIZE)
+
+# struct ofp_table_feature_prop_oxm
+OFP_TABLE_FEATURE_PROP_OXM_PACK_STR = '!HH'
+OFP_TABLE_FEATURE_PROP_OXM_SIZE = 4
+assert (calcsize(OFP_TABLE_FEATURE_PROP_OXM_PACK_STR) ==
+ OFP_TABLE_FEATURE_PROP_OXM_SIZE)
+
+# struct ofp_table_feature_prop_oxm_values
+OFP_TABLE_FEATURE_PROP_OXM_VALUES_PACK_STR = '!HH'
+OFP_TABLE_FEATURE_PROP_OXM_VALUES_SIZE = 4
+assert (calcsize(OFP_TABLE_FEATURE_PROP_OXM_VALUES_PACK_STR) ==
+ OFP_TABLE_FEATURE_PROP_OXM_VALUES_SIZE)
+
+# struct ofp_table_feature_prop_experimenter
+OFP_TABLE_FEATURE_PROP_EXPERIMENTER_PACK_STR = '!HHII'
+OFP_TABLE_FEATURE_PROP_EXPERIMENTER_SIZE = 12
+assert (calcsize(OFP_TABLE_FEATURE_PROP_EXPERIMENTER_PACK_STR) ==
+ OFP_TABLE_FEATURE_PROP_EXPERIMENTER_SIZE)
+
+# enum ofp_table_feature_flag
+OFPTFF_INGRESS_TABLE = 1 << 0 # Can be configured as ingress table.
+OFPTFF_EGRESS_TABLE = 1 << 1 # Can be configured as egress table.
+OFPTFF_FIRST_EGRESS = 1 << 4 # Is the first egress table.
+
+# enum ofp_table_features_command
+OFPTFC_REPLACE = 0 # Replace full pipeline.
+OFPTFC_MODIFY = 1 # Modify flow tables capabilities.
+OFPTFC_ENABLE = 2 # Enable flow tables in the pipeline.
+OFPTFC_DISABLE = 3 # Disable flow tables in pipeline.
+
+# struct ofp_table_features
+OFP_MAX_TABLE_NAME_LEN = 32
+OFP_MAX_TABLE_NAME_LEN_STR = str(OFP_MAX_TABLE_NAME_LEN)
+OFP_TABLE_FEATURES_PACK_STR = '!HBBI' + OFP_MAX_TABLE_NAME_LEN_STR + \
+ 's' + 'QQII'
+OFP_TABLE_FEATURES_SIZE = 64
+assert (calcsize(OFP_TABLE_FEATURES_PACK_STR) ==
+ OFP_TABLE_FEATURES_SIZE)
+
+# struct ofp_table_stats
+OFP_TABLE_STATS_PACK_STR = '!B3xIQQ'
+OFP_TABLE_STATS_SIZE = 24
+assert calcsize(OFP_TABLE_STATS_PACK_STR) == OFP_TABLE_STATS_SIZE
+
+# struct ofp_table_desc
+_OFP_TABLE_DESC_PACK_STR = 'HBxI'
+OFP_TABLE_DESC_PACK_STR = '!' + _OFP_TABLE_DESC_PACK_STR
+OFP_TABLE_DESC_SIZE = 8
+assert calcsize(OFP_TABLE_DESC_PACK_STR) == OFP_TABLE_DESC_SIZE
+
+# struct ofp_port_multipart_request
+OFP_PORT_MULTIPART_REQUEST_PACK_STR = '!I4x'
+OFP_PORT_MULTIPART_REQUEST_SIZE = 8
+assert (calcsize(OFP_PORT_MULTIPART_REQUEST_PACK_STR) ==
+ OFP_PORT_MULTIPART_REQUEST_SIZE)
+
+# enum ofp_port_stats_prop_type
+OFPPSPT_ETHERNET = 0 # Ethernet property.
+OFPPSPT_OPTICAL = 1 # Optical property.
+OFPPSPT_EXPERIMENTER = 0xFFFF # Experimenter property.
+
+# struct ofp_port_stats_prop_ethernet
+OFP_PORT_STATS_PROP_ETHERNET_PACK_STR = '!HH4xQQQQ'
+OFP_PORT_STATS_PROP_ETHERNET_SIZE = 40
+assert (calcsize(OFP_PORT_STATS_PROP_ETHERNET_PACK_STR) ==
+ OFP_PORT_STATS_PROP_ETHERNET_SIZE)
+
+# struct ofp_port_stats_prop_optical
+OFP_PORT_STATS_PROP_OPTICAL_PACK_STR = '!HH4xIIIIIIIHHHH'
+OFP_PORT_STATS_PROP_OPTICAL_SIZE = 44
+assert (calcsize(OFP_PORT_STATS_PROP_OPTICAL_PACK_STR) ==
+ OFP_PORT_STATS_PROP_OPTICAL_SIZE)
+
+# enum ofp_port_stats_optical_flags
+OFPOSF_RX_TUNE = 1 << 0 # Receiver tune info valid
+OFPOSF_TX_TUNE = 1 << 1 # Transmit tune info valid
+OFPOSF_TX_PWR = 1 << 2 # TX Power is valid
+OFPOSF_RX_PWR = 1 << 4 # RX power is valid
+OFPOSF_TX_BIAS = 1 << 5 # Transmit bias is valid
+OFPOSF_TX_TEMP = 1 << 6 # TX Temp is valid
+
+# struct ofp_port_stats_prop_experimenter
+OFP_PORT_STATS_PROP_EXPERIMENTER_PACK_STR = '!HHII'
+OFP_PORT_STATS_PROP_EXPERIMENTER_SIZE = 12
+assert (calcsize(OFP_PORT_STATS_PROP_EXPERIMENTER_PACK_STR) ==
+ OFP_PORT_STATS_PROP_EXPERIMENTER_SIZE)
+
+# struct ofp_port_stats
+OFP_PORT_STATS_PACK_STR = '!H2xIIIQQQQQQQQ'
+OFP_PORT_STATS_SIZE = 80
+assert calcsize(OFP_PORT_STATS_PACK_STR) == OFP_PORT_STATS_SIZE
+
+# struct ofp_group_multipart_request
+OFP_GROUP_MULTIPART_REQUEST_PACK_STR = '!I4x'
+OFP_GROUP_MULTIPART_REQUEST_SIZE = 8
+assert (calcsize(OFP_GROUP_MULTIPART_REQUEST_PACK_STR) ==
+ OFP_GROUP_MULTIPART_REQUEST_SIZE)
+
+# struct ofp_bucket_counter
+OFP_BUCKET_COUNTER_PACK_STR = '!QQ'
+OFP_BUCKET_COUNTER_SIZE = 16
+assert calcsize(OFP_BUCKET_COUNTER_PACK_STR) == OFP_BUCKET_COUNTER_SIZE
+
+# struct ofp_group_desc_stats
+OFP_GROUP_DESC_STATS_PACK_STR = '!HBxI'
+OFP_GROUP_DESC_STATS_SIZE = 8
+assert calcsize(OFP_GROUP_DESC_STATS_PACK_STR) == OFP_GROUP_DESC_STATS_SIZE
+
+# struct ofp_group_stats
+OFP_GROUP_STATS_PACK_STR = '!H2xII4xQQII'
+OFP_GROUP_STATS_SIZE = 40
+assert calcsize(OFP_GROUP_STATS_PACK_STR) == OFP_GROUP_STATS_SIZE
+
+# struct ofp_group_desc
+OFP_GROUP_DESC_PACK_STR = '!HBxIH6x'
+OFP_GROUP_DESC_SIZE = 16
+assert calcsize(OFP_GROUP_DESC_PACK_STR) == OFP_GROUP_DESC_SIZE
+
+# enum ofp_group_capabilities
+OFPGFC_SELECT_WEIGHT = 1 << 0 # Support weight for select groups.
+OFPGFC_SELECT_LIVENESS = 1 << 1 # Support liveness for select groups.
+OFPGFC_CHAINING = 1 << 2 # Support chaining groups.
+OFPGFC_CHAINING_CHECKS = 1 << 3 # Check chaining for loops and delete
+
+# struct ofp_group_features
+OFP_GROUP_FEATURES_PACK_STR = '!II4I4I'
+OFP_GROUP_FEATURES_SIZE = 40
+assert calcsize(OFP_GROUP_FEATURES_PACK_STR) == OFP_GROUP_FEATURES_SIZE
+
+# struct ofp_meter_multipart_request
+OFP_METER_MULTIPART_REQUEST_PACK_STR = '!I4x'
+OFP_METER_MULTIPART_REQUEST_SIZE = 8
+assert (calcsize(OFP_METER_MULTIPART_REQUEST_PACK_STR) ==
+ OFP_METER_MULTIPART_REQUEST_SIZE)
+
+# struct ofp_meter_stats
+OFP_METER_STATS_PACK_STR = '!IH6xIQQII'
+OFP_METER_STATS_SIZE = 40
+assert calcsize(OFP_METER_STATS_PACK_STR) == OFP_METER_STATS_SIZE
+
+# struct ofp_meter_band_stats
+OFP_METER_BAND_STATS_PACK_STR = '!QQ'
+OFP_METER_BAND_STATS_SIZE = 16
+assert (calcsize(OFP_METER_BAND_STATS_PACK_STR) ==
+ OFP_METER_BAND_STATS_SIZE)
+
+# struct ofp_meter_desc
+OFP_METER_DESC_PACK_STR = '!HHI'
+OFP_METER_DESC_SIZE = 8
+assert calcsize(OFP_METER_DESC_PACK_STR) == OFP_METER_DESC_SIZE
+
+# enum ofp_meter_feature_flags
+OFPMFF_ACTION_SET = 1 << 0 # Support meter action in action set.
+OFPMFF_ANY_POSITION = 1 << 1 # Support any position in action list.
+OFPMFF_MULTI_LIST = 1 << 2 # Support multiple actions in action list.
+
+# struct ofp_meter_features
+OFP_METER_FEATURES_PACK_STR = '!IIIBB2xI4x'
+OFP_METER_FEATURES_SIZE = 24
+assert (calcsize(OFP_METER_FEATURES_PACK_STR) ==
+ OFP_METER_FEATURES_SIZE)
+
+# All ones is used to indicate all queues in a port (for stats retrieval).
+OFPQ_ALL = 0xffffffff
+
+# Min rate > 1000 means not configured.
+OFPQ_MIN_RATE_UNCFG = 0xffff
+
+# Max rate > 1000 means not configured.
+OFPQ_MAX_RATE_UNCFG = 0xffff
+
+# enum ofp_queue_desc_prop_type
+OFPQDPT_MIN_RATE = 1 # Minimum datarate guaranteed.
+OFPQDPT_MAX_RATE = 2 # Maximum datarate.
+OFPQDPT_EXPERIMENTER = 0xffff # Experimenter defined property.
+
+# struct ofp_queue_desc_prop_min_rate
+OFP_QUEUE_DESC_PROP_MIN_RATE_PACK_STR = '!HHH2x'
+OFP_QUEUE_DESC_PROP_MIN_RATE_SIZE = 8
+assert (calcsize(OFP_QUEUE_DESC_PROP_MIN_RATE_PACK_STR) ==
+ OFP_QUEUE_DESC_PROP_MIN_RATE_SIZE)
+
+# ofp_queue_desc_prop_max_rate
+OFP_QUEUE_DESC_PROP_MAX_RATE_PACK_STR = '!HHH2x'
+OFP_QUEUE_DESC_PROP_MAX_RATE_SIZE = 8
+assert (calcsize(OFP_QUEUE_DESC_PROP_MAX_RATE_PACK_STR) ==
+ OFP_QUEUE_DESC_PROP_MAX_RATE_SIZE)
+
+# struct ofp_queue_desc_prop_experimenter
+OFP_QUEUE_DESC_PROP_EXPERIMENTER_PACK_STR = '!HHII'
+OFP_QUEUE_DESC_PROP_EXPERIMENTER_SIZE = 12
+assert (calcsize(OFP_QUEUE_DESC_PROP_EXPERIMENTER_PACK_STR) ==
+ OFP_QUEUE_DESC_PROP_EXPERIMENTER_SIZE)
+
+# struct ofp_queue_multipart_request
+OFP_QUEUE_MULTIPART_REQUEST_PACK_STR = '!II'
+OFP_QUEUE_MULTIPART_REQUEST_SIZE = 8
+assert (calcsize(OFP_QUEUE_MULTIPART_REQUEST_PACK_STR) ==
+ OFP_QUEUE_MULTIPART_REQUEST_SIZE)
+
+# struct ofp_queue_desc
+OFP_QUEUE_DESC_PACK_STR = '!IIH6x'
+OFP_QUEUE_DESC_SIZE = 16
+assert calcsize(OFP_QUEUE_DESC_PACK_STR) == OFP_QUEUE_DESC_SIZE
+
+# enum ofp_queue_stats_prop_type
+OFPQSPT_EXPERIMENTER = 0xffff # Experimenter defined property.
+
+# struct ofp_queue_stats_prop_experimenter
+OFP_QUEUE_STATS_PROP_EXPERIMENTER_PACK_STR = '!HHII'
+OFP_QUEUE_STATS_PROP_EXPERIMENTER_SIZE = 12
+assert (calcsize(OFP_QUEUE_STATS_PROP_EXPERIMENTER_PACK_STR) ==
+ OFP_QUEUE_STATS_PROP_EXPERIMENTER_SIZE)
+
+# struct ofp_queue_stats
+OFP_QUEUE_STATS_PACK_STR = '!H6xIIQQQII'
+OFP_QUEUE_STATS_SIZE = 48
+assert calcsize(OFP_QUEUE_STATS_PACK_STR) == OFP_QUEUE_STATS_SIZE
+
+# struct ofp_flow_monitor_request
+_OFP_FLOW_MONITOR_REQUEST_0_PACK_STR = 'IIIHBB'
+OFP_FLOW_MONITOR_REQUEST_0_PACK_STR = ('!' +
+ _OFP_FLOW_MONITOR_REQUEST_0_PACK_STR)
+OFP_FLOW_MONITOR_REQUEST_0_SIZE = 16
+OFP_FLOW_MONITOR_REQUEST_PACK_STR = (OFP_FLOW_MONITOR_REQUEST_0_PACK_STR +
+ _OFP_MATCH_PACK_STR)
+OFP_FLOW_MONITOR_REQUEST_SIZE = 24
+assert (calcsize(OFP_FLOW_MONITOR_REQUEST_PACK_STR) ==
+ OFP_FLOW_MONITOR_REQUEST_SIZE)
+
+# enum ofp_flow_monitor_command
+OFPFMC_ADD = 0 # New flow monitor.
+OFPFMC_MODIFY = 1 # Modify existing flow monitor.
+OFPFMC_DELETE = 2 # Delete/cancel existing flow monitor.
+
+# enum ofp_flow_monitor_flags
+# When to send updates.
+OFPFMF_INITIAL = 1 << 0 # Initially matching flows.
+OFPFMF_ADD = 1 << 1 # New matching flows as they are added.
+OFPFMF_REMOVED = 1 << 2 # Old matching flows as they are removed.
+OFPFMF_MODIFY = 1 << 3 # Matching flows as they are changed.
+# What to include in updates.
+OFPFMF_INSTRUCTIONS = 1 << 4 # If set, instructions are included.
+OFPFMF_NO_ABBREV = 1 << 5 # If set, include own changes in full.
+OFPFMF_ONLY_OWN = 1 << 6 # If set, don't include other controllers.
+
+# struct ofp_flow_update_header
+OFP_FLOW_UPDATE_HEADER_PACK_STR = '!HH'
+OFP_FLOW_UPDATE_HEADER_SIZE = 4
+assert (calcsize(OFP_FLOW_UPDATE_HEADER_PACK_STR) ==
+ OFP_FLOW_UPDATE_HEADER_SIZE)
+
+# enum ofp_flow_update_event
+# struct ofp_flow_update_full.
+OFPFME_INITIAL = 0 # Flow present when flow monitor created.
+OFPFME_ADDED = 1 # Flow was added.
+OFPFME_REMOVED = 2 # Flow was removed.
+OFPFME_MODIFIED = 3 # Flow instructions were changed.
+# struct ofp_flow_update_abbrev.
+OFPFME_ABBREV = 4 # Abbreviated reply.
+# struct ofp_flow_update_header.
+OFPFME_PAUSED = 5 # Monitoring paused (out of buffer space).
+OFPFME_RESUMED = 6 # Monitoring resumed.
+
+# struct ofp_flow_update_full
+_OFP_FLOW_UPDATE_FULL_0_PACK_STR = 'HHBBHHH4xQ'
+OFP_FLOW_UPDATE_FULL_0_PACK_STR = '!' + _OFP_FLOW_UPDATE_FULL_0_PACK_STR
+OFP_FLOW_UPDATE_FULL_0_SIZE = 24
+OFP_FLOW_UPDATE_FULL_PACK_STR = (OFP_FLOW_UPDATE_FULL_0_PACK_STR +
+ _OFP_MATCH_PACK_STR)
+OFP_FLOW_UPDATE_FULL_SIZE = 32
+assert (calcsize(OFP_FLOW_UPDATE_FULL_PACK_STR) ==
+ OFP_FLOW_UPDATE_FULL_SIZE)
+
+# struct ofp_flow_update_abbrev
+OFP_FLOW_UPDATE_ABBREV_PACK_STR = '!HHI'
+OFP_FLOW_UPDATE_ABBREV_SIZE = 8
+assert (calcsize(OFP_FLOW_UPDATE_ABBREV_PACK_STR) ==
+ OFP_FLOW_UPDATE_ABBREV_SIZE)
+
+# struct ofp_flow_update_paused
+OFP_FLOW_UPDATE_PAUSED_PACK_STR = '!HH4x'
+OFP_FLOW_UPDATE_PAUSED_SIZE = 8
+assert (calcsize(OFP_FLOW_UPDATE_PAUSED_PACK_STR) ==
+ OFP_FLOW_UPDATE_PAUSED_SIZE)
+
+# enum ofp_controller_status_prop_type
+OFPCSPT_URI = 0 # Connection URI property.
+OFPCSPT_EXPERIMENTER = 0xFFFF # Experimenter property.
+
+# struct ofp_controller_status_prop_header
+_OFP_CONTROLLER_STATUS_PROP_HEADER_PACK_STR = 'HH'
+OFP_CONTROLLER_STATUS_PROP_HEADER_PACK_STR = (
+ '!' + _OFP_CONTROLLER_STATUS_PROP_HEADER_PACK_STR)
+OFP_CONTROLLER_STATUS_PROP_HEADER_SIZE = 4
+assert (calcsize(OFP_CONTROLLER_STATUS_PROP_HEADER_PACK_STR) ==
+ OFP_CONTROLLER_STATUS_PROP_HEADER_SIZE)
+
+# struct ofp_controller_status_prop_uri
+OFP_CONTROLLER_STATUS_PROP_URI_PACK_STR = '!HH'
+OFP_CONTROLLER_STATUS_PROP_URI_SIZE = 4
+assert (calcsize(OFP_CONTROLLER_STATUS_PROP_URI_PACK_STR) ==
+ OFP_CONTROLLER_STATUS_PROP_URI_SIZE)
+
+# struct ofp_controller_status_prop_experimenter
+OFP_CONTROLLER_STATUS_PROP_EXPERIMENTER_PACK_STR = '!HHII'
+OFP_CONTROLLER_STATUS_PROP_EXPERIMENTER_SIZE = 12
+assert (calcsize(OFP_CONTROLLER_STATUS_PROP_EXPERIMENTER_PACK_STR) ==
+ OFP_CONTROLLER_STATUS_PROP_EXPERIMENTER_SIZE)
+
+# enum ofp_controller_status_reason
+OFPCSR_REQUEST = 0 # Controller requested status.
+OFPCSR_CHANNEL_STATUS = 1 # Oper status of channel changed.
+OFPCSR_ROLE = 2 # Controller role changed.
+OFPCSR_CONTROLLER_ADDED = 3 # New controller added.
+OFPCSR_CONTROLLER_REMOVED = 4 # Controller removed from config.
+OFPCSR_SHORT_ID = 5 # Controller ID changed.
+OFPCSR_EXPERIMENTER = 6 # Experimenter data changed.
+
+# struct ofp_controller_status
+OFP_CONTROLLER_STATUS_PACK_STR = '!HHIBB6x'
+OFP_CONTROLLER_STATUS_SIZE = 16
+assert (calcsize(OFP_CONTROLLER_STATUS_PACK_STR) ==
+ OFP_CONTROLLER_STATUS_SIZE)
+
+# struct ofp_controller_status_header
+OFP_CONTROLLER_STATUS_HEADER_PACK_STR = OFP_CONTROLLER_STATUS_PACK_STR
+OFP_CONTROLLER_STATUS_HEADER_SIZE = OFP_CONTROLLER_STATUS_SIZE + OFP_HEADER_SIZE
+
+# enum ofp_control_channel_status
+OFPCT_STATUS_UP = 0 # Control channel is operational.
+OFPCT_STATUS_DOWN = 1 # Control channel is not operational.
+
+# struct ofp_bundle_features_prop_header
+OFP_BUNDLE_FEATURES_PROP_HEADER_PACK_STR = '!HH'
+OFP_BUNDLE_FEATURES_PROP_HEADER_SIZE = 4
+assert (calcsize(OFP_BUNDLE_FEATURES_PROP_HEADER_PACK_STR) ==
+ OFP_BUNDLE_FEATURES_PROP_HEADER_SIZE)
+
+# struct ofp_bundle_features_request
+OFP_BUNDLE_FEATURES_REQUEST_PACK_STR = '!I4x'
+OFP_BUNDLE_FEATURES_REQUEST_SIZE = 8
+assert (calcsize(OFP_BUNDLE_FEATURES_REQUEST_PACK_STR) ==
+ OFP_BUNDLE_FEATURES_REQUEST_SIZE)
+
+# enum ofp_bundle_features_prop_type
+OFPTMPBF_TIME_CAPABILITY = 0x1 # Time feature property.
+OFPTMPBF_EXPERIMENTER = 0xFFFF # Experimenter property.
+
+# struct ofp_time
+_OFP_TIME_PACK_STR = 'QI4x'
+OFP_TIME_PACK_STR = '!' + _OFP_TIME_PACK_STR
+OFP_TIME_SIZE = 16
+assert calcsize(OFP_TIME_PACK_STR) == OFP_TIME_SIZE
+
+# struct ofp_bundle_features_prop_time
+OFP_BUNDLE_FEATURES_PROP_TIME_PACK_STR = ('!HH4x' +
+ _OFP_TIME_PACK_STR +
+ _OFP_TIME_PACK_STR +
+ _OFP_TIME_PACK_STR +
+ _OFP_TIME_PACK_STR)
+OFP_BUNDLE_FEATURES_PROP_TIME_SIZE = 72
+assert (calcsize(OFP_BUNDLE_FEATURES_PROP_TIME_PACK_STR) ==
+ OFP_BUNDLE_FEATURES_PROP_TIME_SIZE)
+
+# enum ofp_bundle_feature_flags
+OFPBF_TIMESTAMP = 1 << 0 # Request includes a timestamp.
+OFPBF_TIME_SET_SCHED = 1 << 1 # Request includes the sched_max_future and
+ # sched_max_past parameters.
+
+# struct ofp_bundle_features
+OFP_BUNDLE_FEATURES_PACK_STR = '!H6x'
+OFP_BUNDLE_FEATURES_SIZE = 8
+assert (calcsize(OFP_BUNDLE_FEATURES_PACK_STR) ==
+ OFP_BUNDLE_FEATURES_SIZE)
+
+# struct ofp_experimenter_multipart_header
+OFP_EXPERIMENTER_MULTIPART_HEADER_PACK_STR = '!II'
+OFP_EXPERIMENTER_MULTIPART_HEADER_SIZE = 8
+assert (calcsize(OFP_EXPERIMENTER_MULTIPART_HEADER_PACK_STR) ==
+ OFP_EXPERIMENTER_MULTIPART_HEADER_SIZE)
+
+# struct ofp_experimenter_structure
+OFP_EXPERIMENTER_STRUCTURE_PACK_STR = '!II'
+OFP_EXPERIMENTER_STRUCTURE_SIZE = 8
+assert (calcsize(OFP_EXPERIMENTER_STRUCTURE_PACK_STR) ==
+ OFP_EXPERIMENTER_STRUCTURE_SIZE)
+
+# struct ofp_error_experimenter_msg
+OFP_ERROR_EXPERIMENTER_MSG_PACK_STR = '!HHI'
+OFP_ERROR_EXPERIMENTER_MSG_SIZE = 16
+assert (calcsize(OFP_ERROR_EXPERIMENTER_MSG_PACK_STR) +
+ OFP_HEADER_SIZE) == OFP_ERROR_EXPERIMENTER_MSG_SIZE
+
+# enum ofp_controller_role
+OFPCR_ROLE_NOCHANGE = 0 # Don't change current role.
+OFPCR_ROLE_EQUAL = 1 # Default role, full access.
+OFPCR_ROLE_MASTER = 2 # Full access, at most one master.
+OFPCR_ROLE_SLAVE = 3 # Read-only access.
+
+# If the switch has not requested an identifier, the short_id should be set to
+# OFPCID_UNDEFINED.
+OFPCID_UNDEFINED = 0
+
+# struct ofp_role_request
+OFP_ROLE_REQUEST_PACK_STR = '!IH2xQ'
+OFP_ROLE_REQUEST_SIZE = 24
+assert (calcsize(OFP_ROLE_REQUEST_PACK_STR) + OFP_HEADER_SIZE ==
+ OFP_ROLE_REQUEST_SIZE)
+
+# enum ofp_role_prop_type
+OFPRPT_EXPERIMENTER = 0xFFFF # Experimenter property.
+
+# struct ofp_role_prop_header
+_OFP_ROLE_PROP_HEADER_PACK_STR = 'HH'
+OFP_ROLE_PROP_HEADER_PACK_STR = '!' + _OFP_ROLE_PROP_HEADER_PACK_STR
+OFP_ROLE_PROP_HEADER_SIZE = 4
+assert (calcsize(OFP_ROLE_PROP_HEADER_PACK_STR) ==
+ OFP_ROLE_PROP_HEADER_SIZE)
+
+# struct ofp_role_prop_experimenter
+OFP_ROLE_PROP_EXPERIMENTER_PACK_STR = '!HHII'
+OFP_ROLE_PROP_EXPERIMENTER_SIZE = 12
+assert (calcsize(OFP_ROLE_PROP_EXPERIMENTER_PACK_STR) ==
+ OFP_ROLE_PROP_EXPERIMENTER_SIZE)
+
+# enum ofp_controller_role_reason
+OFPCRR_MASTER_REQUEST = 0 # Another controller asked to be master.
+OFPCRR_CONFIG = 1 # Configuration changed on the switch.
+OFPCRR_EXPERIMENTER = 2 # Experimenter data changed.
+
+# struct ofp_role_status
+OFP_ROLE_STATUS_PACK_STR = '!IB3xQ'
+OFP_ROLE_STATUS_SIZE = 24
+assert (calcsize(OFP_ROLE_STATUS_PACK_STR) + OFP_HEADER_SIZE ==
+ OFP_ROLE_STATUS_SIZE)
+
+# enum ofp_async_config_prop_type
+OFPACPT_PACKET_IN_SLAVE = 0 # Packet-in mask for slave.
+OFPACPT_PACKET_IN_MASTER = 1 # Packet-in mask for master.
+OFPACPT_PORT_STATUS_SLAVE = 2 # Port-status mask for slave.
+OFPACPT_PORT_STATUS_MASTER = 3 # Port-status mask for master.
+OFPACPT_FLOW_REMOVED_SLAVE = 4 # Flow removed mask for slave.
+OFPACPT_FLOW_REMOVED_MASTER = 5 # Flow removed mask for master.
+OFPACPT_ROLE_STATUS_SLAVE = 6 # Role status mask for slave.
+OFPACPT_ROLE_STATUS_MASTER = 7 # Role status mask for master.
+OFPACPT_TABLE_STATUS_SLAVE = 8 # Table status mask for slave.
+OFPACPT_TABLE_STATUS_MASTER = 9 # Table status mask for master.
+OFPACPT_REQUESTFORWARD_SLAVE = 10 # RequestForward mask for slave.
+OFPACPT_REQUESTFORWARD_MASTER = 11 # RequestForward mask for master.
+OFPACPT_FLOW_STATS_SLAVE = 12 # Flow stats mask for slave.
+OFPACPT_FLOW_STATS_MASTER = 13 # Flow stats mask for master.
+OFPACPT_CONT_STATUS_SLAVE = 14 # Controller status mask for slave.
+OFPACPT_CONT_STATUS_MASTER = 15 # Controller status mask for master.
+OFPACPT_EXPERIMENTER_SLAVE = 0xFFFE # Experimenter for slave.
+OFPACPT_EXPERIMENTER_MASTER = 0xFFFF # Experimenter for master.
+
+# struct ofp_async_config_prop_reasons
+OFP_ASYNC_CONFIG_PROP_REASONS_PACK_STR = '!HHI'
+OFP_ASYNC_CONFIG_PROP_REASONS_SIZE = 8
+assert (calcsize(OFP_ASYNC_CONFIG_PROP_REASONS_PACK_STR) ==
+ OFP_ASYNC_CONFIG_PROP_REASONS_SIZE)
+
+# struct ofp_async_config_prop_experimenter
+OFP_ASYNC_CONFIG_PROP_EXPERIMENTER_PACK_STR = '!HHII'
+OFP_ASYNC_CONFIG_PROP_EXPERIMENTER_SIZE = 12
+assert (calcsize(OFP_ASYNC_CONFIG_PROP_EXPERIMENTER_PACK_STR) ==
+ OFP_ASYNC_CONFIG_PROP_EXPERIMENTER_SIZE)
+
+# enum ofp_table_reason
+OFPTR_VACANCY_DOWN = 3 # Vacancy down threshold event.
+OFPTR_VACANCY_UP = 4 # Vacancy up threshold event.
+
+# struct ofp_table_status
+_OFP_TABLE_STATUS_0_PACK_STR = 'B7x'
+OFP_TABLE_STATUS_0_PACK_STR = '!' + _OFP_TABLE_STATUS_0_PACK_STR
+OFP_TABLE_STATUS_0_SIZE = 16
+OFP_TABLE_STATUS_PACK_STR = (OFP_TABLE_STATUS_0_PACK_STR +
+ _OFP_TABLE_DESC_PACK_STR)
+OFP_TABLE_STATUS_SIZE = 24
+assert (calcsize(OFP_TABLE_STATUS_PACK_STR) + OFP_HEADER_SIZE ==
+ OFP_TABLE_STATUS_SIZE)
+
+# enum ofp_requestforward_reason
+OFPRFR_GROUP_MOD = 0 # Forward group mod requests.
+OFPRFR_METER_MOD = 1 # Forward meter mod requests.
+
+# enum ofp_bundle_prop_type
+OFPBPT_TIME = 1 # Time property.
+OFPBPT_EXPERIMENTER = 0xFFFF # Experimenter property.
+
+# struct ofp_bundle_prop_experimenter
+OFP_BUNDLE_PROP_EXPERIMENTER_PACK_STR = '!HHII'
+OFP_BUNDLE_PROP_EXPERIMENTER_SIZE = 12
+assert (calcsize(OFP_BUNDLE_PROP_EXPERIMENTER_PACK_STR) ==
+ OFP_BUNDLE_PROP_EXPERIMENTER_SIZE)
+
+# struct ofp_bundle_prop_time
+OFP_BUNDLE_PROP_TIME_PACK_STR0 = '!HH4x'
+OFP_BUNDLE_PROP_TIME_PACK_STR0_SIZE = 8
+assert (calcsize(OFP_BUNDLE_PROP_TIME_PACK_STR0) ==
+ OFP_BUNDLE_PROP_TIME_PACK_STR0_SIZE)
+OFP_BUNDLE_PROP_TIME_PACK_STR = (OFP_BUNDLE_PROP_TIME_PACK_STR0 +
+ _OFP_TIME_PACK_STR)
+OFP_BUNDLE_PROP_TIME_PACK_STR_SIZE = 24
+assert (calcsize(OFP_BUNDLE_PROP_TIME_PACK_STR) ==
+ OFP_BUNDLE_PROP_TIME_PACK_STR_SIZE)
+
+# enum ofp_bundle_ctrl_type
+OFPBCT_OPEN_REQUEST = 0
+OFPBCT_OPEN_REPLY = 1
+OFPBCT_CLOSE_REQUEST = 2
+OFPBCT_CLOSE_REPLY = 3
+OFPBCT_COMMIT_REQUEST = 4
+OFPBCT_COMMIT_REPLY = 5
+OFPBCT_DISCARD_REQUEST = 6
+OFPBCT_DISCARD_REPLY = 7
+
+# enum ofp_bundle_flags
+OFPBF_ATOMIC = 1 << 0 # Execute atomically.
+OFPBF_ORDERED = 1 << 1 # Execute in specified order.
+OFPBF_TIME = 1 << 2 # Execute in specified time.
+
+# struct ofp_bundle_ctrl_msg
+OFP_BUNDLE_CTRL_MSG_PACK_STR = '!IHH'
+OFP_BUNDLE_CTRL_MSG_SIZE = 16
+assert (calcsize(OFP_BUNDLE_CTRL_MSG_PACK_STR) + OFP_HEADER_SIZE ==
+ OFP_BUNDLE_CTRL_MSG_SIZE)
+
+# struct ofp_bundle_add_msg
+_OFP_BUNDLE_ADD_MSG_0_PACK_STR = 'I2xH'
+OFP_BUNDLE_ADD_MSG_0_PACK_STR = '!' + _OFP_BUNDLE_ADD_MSG_0_PACK_STR
+OFP_BUNDLE_ADD_MSG_PACK_STR = (OFP_BUNDLE_ADD_MSG_0_PACK_STR +
+ _OFP_HEADER_PACK_STR)
+OFP_BUNDLE_ADD_MSG_SIZE = 24
+assert (calcsize(OFP_BUNDLE_ADD_MSG_PACK_STR) + OFP_HEADER_SIZE ==
+ OFP_BUNDLE_ADD_MSG_SIZE)
+
+# define constants
+OFP_VERSION = 0x06
+OFP_TCP_PORT = 6653
+OFP_SSL_PORT = 6653
+MAX_XID = 0xffffffff
diff --git a/ryu/ofproto/ofproto_v1_5_parser.py b/ryu/ofproto/ofproto_v1_5_parser.py
new file mode 100644
index 00000000..4bd9db6b
--- /dev/null
+++ b/ryu/ofproto/ofproto_v1_5_parser.py
@@ -0,0 +1,6083 @@
+# 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.5.
+"""
+
+import struct
+import itertools
+
+from ryu.lib import addrconv
+from ryu.lib import mac
+from ryu import utils
+from ofproto_parser import (StringifyMixin, MsgBase, MsgInMsgBase,
+ msg_pack_into, msg_str_attr)
+from . import ether
+from . import ofproto_parser
+from . import ofproto_common
+from . import ofproto_v1_5 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=[]):
+ 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
+ ============================= ===========
+
+ 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):
+ super(OFPErrorMsg, self).__init__(datapath)
+ self.type = type_
+ self.code = code
+ self.data = data
+
+ @classmethod
+ def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+ type_, = struct.unpack_from('!H', buffer(buf),
+ ofproto.OFP_HEADER_SIZE)
+ if type_ == ofproto.OFPET_EXPERIMENTER:
+ return OFPErrorExperimenterMsg.parser(datapath, version, msg_type,
+ msg_len, xid, buf)
+ msg = super(OFPErrorMsg, cls).parser(datapath, version, msg_type,
+ msg_len, xid, buf)
+ msg.type, msg.code = struct.unpack_from(
+ ofproto.OFP_ERROR_MSG_PACK_STR, msg.buf,
+ ofproto.OFP_HEADER_SIZE)
+ msg.data = msg.buf[ofproto.OFP_ERROR_MSG_SIZE:]
+ return msg
+
+ def _serialize_body(self):
+ assert self.data is not None
+ msg_pack_into(ofproto.OFP_ERROR_MSG_PACK_STR, self.buf,
+ ofproto.OFP_HEADER_SIZE, self.type, self.code)
+ self.buf += self.data
+
+
+class OFPErrorExperimenterMsg(MsgBase):
+ def __init__(self, datapath, type_=None, exp_type=None, experimenter=None,
+ data=None):
+ super(OFPErrorExperimenterMsg, self).__init__(datapath)
+ self.type = ofproto.OFPET_EXPERIMENTER
+ self.exp_type = exp_type
+ self.experimenter = experimenter
+ self.data = data
+
+ @classmethod
+ def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
+ cls.cls_msg_type = msg_type
+ msg = super(OFPErrorExperimenterMsg, cls).parser(
+ datapath, version, msg_type, msg_len, xid, buf)
+ msg.type, msg.exp_type, msg.experimenter = struct.unpack_from(
+ ofproto.OFP_ERROR_EXPERIMENTER_MSG_PACK_STR, msg.buf,
+ ofproto.OFP_HEADER_SIZE)
+ msg.data = msg.buf[ofproto.OFP_ERROR_EXPERIMENTER_MSG_SIZE:]
+ return msg
+
+ def _serialize_body(self):
+ assert self.data is not None
+ 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
+
+
+@_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 = datapath.ofproto
+ 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
+ ================ =============== ==================================
+
+ 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 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.iteritems())
+ fields = [ofproto.oxm_from_user(k, v) for (k, v)
+ in kwargs.iteritems()]
+ # assumption: sorting by OXM type values makes fields
+ # meet ordering requirements (eg. eth_type before ipv4_src)
+ fields.sort()
+ 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
+ ofproto_parser.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 dict(self._fields2).iteritems()
+
+ 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
+
+
+class OFPPropCommonExperimenter4ByteData(StringifyMixin):
+ _PACK_STR = '!HHII'
+
+ 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_TABLE_MOD_PROP_EXPERIMENTER_PACK_STR, buf, 0)
+ data = buf[ofproto.OFP_TABLE_MOD_PROP_EXPERIMENTER_SIZE:length]
+ return cls(type_, length, experimenter, exp_type, data)
+
+ def serialize(self):
+ # fixup
+ self.length = struct.calcsize(self._PACK_STR)
+ self.length += len(self.data)
+
+ buf = bytearray()
+ msg_pack_into(self._PACK_STR, buf,
+ 0, self.type, self.length, self.experimenter,
+ self.exp_type)
+ buf += self.data
+
+ # Pad
+ pad_len = utils.round_up(self.length, 8) - self.length
+ ofproto_parser.msg_pack_into("%dx" % pad_len, buf, len(buf))
+
+ return buf
+
+
+class OFPPortProp(OFPPropBase):
+ _TYPES = {}
+
+
+@OFPPortProp.register_type(ofproto.OFPPDPT_ETHERNET)
+class OFPPortDescPropEthernet(StringifyMixin):
+ 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
+
+
+@OFPPortProp.register_type(ofproto.OFPPDPT_OPTICAL)
+class OFPPortDescPropOptical(StringifyMixin):
+ 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
+
+
+@OFPPortProp.register_type(ofproto.OFPPDPT_EXPERIMENTER)
+class OFPPortDescPropExperimenter(OFPPropCommonExperimenter4ByteData):
+ pass
+
+
+class OFPTableModProp(OFPPropBase):
+ _TYPES = {}
+
+
+@OFPTableModProp.register_type(ofproto.OFPTMPT_EVICTION)
+class OFPTableModPropEviction(StringifyMixin):
+ 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(StringifyMixin):
+ 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(StringifyMixin):
+ 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(StringifyMixin):
+ 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
+
+
+class OFPMatchField(StringifyMixin):
+ _FIELDS_HEADERS = {}
+
+ @staticmethod
+ def register_field_header(headers):
+ def _register_field_header(cls):
+ for header in headers:
+ OFPMatchField._FIELDS_HEADERS[header] = cls
+ return cls
+ return _register_field_header
+
+ def __init__(self, header):
+ self.header = header
+ self.n_bytes = ofproto.oxm_tlv_header_extract_length(header)
+ self.length = 0
+
+ @classmethod
+ def cls_to_header(cls, cls_, hasmask):
+ # XXX efficiency
+ inv = dict((v, k) for k, v in cls._FIELDS_HEADERS.iteritems()
+ if (((k >> 8) & 1) != 0) == hasmask)
+ return inv[cls_]
+
+ @staticmethod
+ def make(header, value, mask=None):
+ cls_ = OFPMatchField._FIELDS_HEADERS.get(header)
+ return cls_(header, value, mask)
+
+ @classmethod
+ def parser(cls, buf, offset):
+ (header,) = struct.unpack_from('!I', buf, offset)
+ cls_ = OFPMatchField._FIELDS_HEADERS.get(header)
+ if cls_:
+ field = cls_.field_parser(header, buf, offset)
+ else:
+ field = OFPMatchField(header)
+ field.length = (header & 0xff) + 4
+ return field
+
+ @classmethod
+ def field_parser(cls, header, buf, offset):
+ hasmask = (header >> 8) & 1
+ mask = None
+ if ofproto.oxm_tlv_header_extract_hasmask(header):
+ pack_str = '!' + cls.pack_str[1:] * 2
+ (value, mask) = struct.unpack_from(pack_str, buf, offset + 4)
+ else:
+ (value,) = struct.unpack_from(cls.pack_str, buf, offset + 4)
+ return cls(header, value, mask)
+
+ def serialize(self, buf, offset):
+ if ofproto.oxm_tlv_header_extract_hasmask(self.header):
+ self.put_w(buf, offset, self.value, self.mask)
+ else:
+ self.put(buf, offset, self.value)
+
+ def _put_header(self, buf, offset):
+ ofproto_parser.msg_pack_into('!I', buf, offset, self.header)
+ self.length = 4
+
+ def _put(self, buf, offset, value):
+ ofproto_parser.msg_pack_into(self.pack_str, buf, offset, value)
+ self.length += self.n_bytes
+
+ def put_w(self, buf, offset, value, mask):
+ self._put_header(buf, offset)
+ self._put(buf, offset + self.length, value)
+ self._put(buf, offset + self.length, mask)
+
+ def put(self, buf, offset, value):
+ self._put_header(buf, offset)
+ self._put(buf, offset + self.length, value)
+
+ def _putv6(self, buf, offset, value):
+ ofproto_parser.msg_pack_into(self.pack_str, buf, offset,
+ *value)
+ self.length += self.n_bytes
+
+ def putv6(self, buf, offset, value, mask=None):
+ self._put_header(buf, offset)
+ self._putv6(buf, offset + self.length, value)
+ if mask and len(mask):
+ self._putv6(buf, offset + self.length, mask)
+
+ def oxm_len(self):
+ return self.header & 0xff
+
+ def to_jsondict(self):
+ # remove some redundant attributes
+ d = super(OFPMatchField, self).to_jsondict()
+ v = d[self.__class__.__name__]
+ del v['header']
+ del v['length']
+ del v['n_bytes']
+ return d
+
+ @classmethod
+ def from_jsondict(cls, dict_):
+ # just pass the dict around.
+ # it will be converted by OFPMatch.__init__().
+ return {cls.__name__: dict_}
+
+ def stringify_attrs(self):
+ f = super(OFPMatchField, self).stringify_attrs
+ if not ofproto.oxm_tlv_header_extract_hasmask(self.header):
+ # something like the following, but yield two values (k,v)
+ # return itertools.ifilter(lambda k, v: k != 'mask', iter())
+ def g():
+ for k, v in f():
+ if k != 'mask':
+ yield (k, v)
+ return g()
+ else:
+ return f()
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_IN_PORT])
+class MTInPort(OFPMatchField):
+ pack_str = '!I'
+
+ def __init__(self, header, value, mask=None):
+ super(MTInPort, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_METADATA,
+ ofproto.OXM_OF_METADATA_W])
+class MTMetadata(OFPMatchField):
+ pack_str = '!Q'
+
+ def __init__(self, header, value, mask=None):
+ super(MTMetadata, self).__init__(header)
+ self.value = value
+ self.mask = mask
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_IN_PHY_PORT])
+class MTInPhyPort(OFPMatchField):
+ pack_str = '!I'
+
+ def __init__(self, header, value, mask=None):
+ super(MTInPhyPort, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_ETH_DST,
+ ofproto.OXM_OF_ETH_DST_W])
+class MTEthDst(OFPMatchField):
+ pack_str = '!6s'
+
+ def __init__(self, header, value, mask=None):
+ super(MTEthDst, self).__init__(header)
+ self.value = value
+ self.mask = mask
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_ETH_SRC,
+ ofproto.OXM_OF_ETH_SRC_W])
+class MTEthSrc(OFPMatchField):
+ pack_str = '!6s'
+
+ def __init__(self, header, value, mask=None):
+ super(MTEthSrc, self).__init__(header)
+ self.value = value
+ self.mask = mask
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_ETH_TYPE])
+class MTEthType(OFPMatchField):
+ pack_str = '!H'
+
+ def __init__(self, header, value, mask=None):
+ super(MTEthType, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_VLAN_VID,
+ ofproto.OXM_OF_VLAN_VID_W])
+class MTVlanVid(OFPMatchField):
+ pack_str = '!H'
+
+ def __init__(self, header, value, mask=None):
+ super(MTVlanVid, self).__init__(header)
+ self.value = value
+ self.mask = mask
+
+ @classmethod
+ def field_parser(cls, header, buf, offset):
+ m = super(MTVlanVid, cls).field_parser(header, buf, offset)
+ m.value &= ~ofproto.OFPVID_PRESENT
+ return m
+
+ def serialize(self, buf, offset):
+ self.value |= ofproto.OFPVID_PRESENT
+ super(MTVlanVid, self).serialize(buf, offset)
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_VLAN_PCP])
+class MTVlanPcp(OFPMatchField):
+ pack_str = '!B'
+
+ def __init__(self, header, value, mask=None):
+ super(MTVlanPcp, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_IP_DSCP])
+class MTIPDscp(OFPMatchField):
+ pack_str = '!B'
+
+ def __init__(self, header, value, mask=None):
+ super(MTIPDscp, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_IP_ECN])
+class MTIPECN(OFPMatchField):
+ pack_str = '!B'
+
+ def __init__(self, header, value, mask=None):
+ super(MTIPECN, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_IP_PROTO])
+class MTIPProto(OFPMatchField):
+ pack_str = '!B'
+
+ def __init__(self, header, value, mask=None):
+ super(MTIPProto, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_IPV4_SRC,
+ ofproto.OXM_OF_IPV4_SRC_W])
+class MTIPV4Src(OFPMatchField):
+ pack_str = '!I'
+
+ def __init__(self, header, value, mask=None):
+ super(MTIPV4Src, self).__init__(header)
+ self.value = value
+ self.mask = mask
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_IPV4_DST,
+ ofproto.OXM_OF_IPV4_DST_W])
+class MTIPV4Dst(OFPMatchField):
+ pack_str = '!I'
+
+ def __init__(self, header, value, mask=None):
+ super(MTIPV4Dst, self).__init__(header)
+ self.value = value
+ self.mask = mask
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_TCP_SRC])
+class MTTCPSrc(OFPMatchField):
+ pack_str = '!H'
+
+ def __init__(self, header, value, mask=None):
+ super(MTTCPSrc, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_TCP_DST])
+class MTTCPDst(OFPMatchField):
+ pack_str = '!H'
+
+ def __init__(self, header, value, mask=None):
+ super(MTTCPDst, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_UDP_SRC])
+class MTUDPSrc(OFPMatchField):
+ pack_str = '!H'
+
+ def __init__(self, header, value, mask=None):
+ super(MTUDPSrc, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_UDP_DST])
+class MTUDPDst(OFPMatchField):
+ pack_str = '!H'
+
+ def __init__(self, header, value, mask=None):
+ super(MTUDPDst, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_SCTP_SRC])
+class MTSCTPSrc(OFPMatchField):
+ pack_str = '!H'
+
+ def __init__(self, header, value, mask=None):
+ super(MTSCTPSrc, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_SCTP_DST])
+class MTSCTPDst(OFPMatchField):
+ pack_str = '!H'
+
+ def __init__(self, header, value, mask=None):
+ super(MTSCTPDst, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_ICMPV4_TYPE])
+class MTICMPV4Type(OFPMatchField):
+ pack_str = '!B'
+
+ def __init__(self, header, value, mask=None):
+ super(MTICMPV4Type, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_ICMPV4_CODE])
+class MTICMPV4Code(OFPMatchField):
+ pack_str = '!B'
+
+ def __init__(self, header, value, mask=None):
+ super(MTICMPV4Code, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_ARP_OP])
+class MTArpOp(OFPMatchField):
+ pack_str = '!H'
+
+ def __init__(self, header, value, mask=None):
+ super(MTArpOp, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_ARP_SPA,
+ ofproto.OXM_OF_ARP_SPA_W])
+class MTArpSpa(OFPMatchField):
+ pack_str = '!I'
+
+ def __init__(self, header, value, mask=None):
+ super(MTArpSpa, self).__init__(header)
+ self.value = value
+ self.mask = mask
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_ARP_TPA,
+ ofproto.OXM_OF_ARP_TPA_W])
+class MTArpTpa(OFPMatchField):
+ pack_str = '!I'
+
+ def __init__(self, header, value, mask=None):
+ super(MTArpTpa, self).__init__(header)
+ self.value = value
+ self.mask = mask
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_ARP_SHA,
+ ofproto.OXM_OF_ARP_SHA_W])
+class MTArpSha(OFPMatchField):
+ pack_str = '!6s'
+
+ def __init__(self, header, value, mask=None):
+ super(MTArpSha, self).__init__(header)
+ self.value = value
+ self.mask = mask
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_ARP_THA,
+ ofproto.OXM_OF_ARP_THA_W])
+class MTArpTha(OFPMatchField):
+ pack_str = '!6s'
+
+ def __init__(self, header, value, mask=None):
+ super(MTArpTha, self).__init__(header)
+ self.value = value
+ self.mask = mask
+
+
+class MTIPv6(StringifyMixin):
+ @classmethod
+ def field_parser(cls, header, buf, offset):
+ if ofproto.oxm_tlv_header_extract_hasmask(header):
+ pack_str = '!' + cls.pack_str[1:] * 2
+ value = struct.unpack_from(pack_str, buf, offset + 4)
+ return cls(header, list(value[:8]), list(value[8:]))
+ else:
+ value = struct.unpack_from(cls.pack_str, buf, offset + 4)
+ return cls(header, list(value))
+
+ def serialize(self, buf, offset):
+ self.putv6(buf, offset, self.value, self.mask)
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_IPV6_SRC,
+ ofproto.OXM_OF_IPV6_SRC_W])
+class MTIPv6Src(MTIPv6, OFPMatchField):
+ pack_str = '!8H'
+
+ def __init__(self, header, value, mask=None):
+ super(MTIPv6Src, self).__init__(header)
+ self.value = value
+ self.mask = mask
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_IPV6_DST,
+ ofproto.OXM_OF_IPV6_DST_W])
+class MTIPv6Dst(MTIPv6, OFPMatchField):
+ pack_str = '!8H'
+
+ def __init__(self, header, value, mask=None):
+ super(MTIPv6Dst, self).__init__(header)
+ self.value = value
+ self.mask = mask
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_IPV6_FLABEL,
+ ofproto.OXM_OF_IPV6_FLABEL_W])
+class MTIPv6Flabel(OFPMatchField):
+ pack_str = '!I'
+
+ def __init__(self, header, value, mask=None):
+ super(MTIPv6Flabel, self).__init__(header)
+ self.value = value
+ self.mask = mask
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_MPLS_LABEL])
+class MTMplsLabel(OFPMatchField):
+ pack_str = '!I'
+
+ def __init__(self, header, value, mask=None):
+ super(MTMplsLabel, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_ICMPV6_TYPE])
+class MTICMPV6Type(OFPMatchField):
+ pack_str = '!B'
+
+ def __init__(self, header, value, mask=None):
+ super(MTICMPV6Type, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_ICMPV6_CODE])
+class MTICMPV6Code(OFPMatchField):
+ pack_str = '!B'
+
+ def __init__(self, header, value, mask=None):
+ super(MTICMPV6Code, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_IPV6_ND_TARGET])
+class MTIPv6NdTarget(MTIPv6, OFPMatchField):
+ pack_str = '!8H'
+
+ def __init__(self, header, value, mask=None):
+ super(MTIPv6NdTarget, self).__init__(header)
+ self.value = value
+
+ def serialize(self, buf, offset):
+ self.putv6(buf, offset, self.value)
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_IPV6_ND_SLL])
+class MTIPv6NdSll(OFPMatchField):
+ pack_str = '!6s'
+
+ def __init__(self, header, value, mask=None):
+ super(MTIPv6NdSll, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_IPV6_ND_TLL])
+class MTIPv6NdTll(OFPMatchField):
+ pack_str = '!6s'
+
+ def __init__(self, header, value, mask=None):
+ super(MTIPv6NdTll, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_MPLS_TC])
+class MTMplsTc(OFPMatchField):
+ pack_str = '!B'
+
+ def __init__(self, header, value, mask=None):
+ super(MTMplsTc, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_MPLS_BOS])
+class MTMplsBos(OFPMatchField):
+ pack_str = '!B'
+
+ def __init__(self, header, value, mask=None):
+ super(MTMplsBos, self).__init__(header)
+ self.value = value
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_PBB_ISID,
+ ofproto.OXM_OF_PBB_ISID_W])
+class MTPbbIsid(OFPMatchField):
+ pack_str = '!3B'
+
+ def __init__(self, header, value, mask=None):
+ super(MTPbbIsid, self).__init__(header)
+ self.value = value
+ self.mask = mask
+
+ @classmethod
+ def field_parser(cls, header, buf, offset):
+ hasmask = (header >> 8) & 1
+ mask = None
+ if ofproto.oxm_tlv_header_extract_hasmask(header):
+ pack_str = '!' + cls.pack_str[1:] * 2
+ (v1, v2, v3, m1, m2, m3) = struct.unpack_from(pack_str, buf,
+ offset + 4)
+ value = v1 << 16 | v2 << 8 | v3
+ mask = m1 << 16 | m2 << 8 | m3
+ else:
+ (v1, v2, v3,) = struct.unpack_from(cls.pack_str, buf, offset + 4)
+ value = v1 << 16 | v2 << 8 | v3
+ return cls(header, value, mask)
+
+ def _put(self, buf, offset, value):
+ ofproto_parser.msg_pack_into(self.pack_str, buf, offset,
+ (value >> 16) & 0xff,
+ (value >> 8) & 0xff,
+ (value >> 0) & 0xff)
+ self.length += self.n_bytes
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_TUNNEL_ID,
+ ofproto.OXM_OF_TUNNEL_ID_W])
+class MTTunnelId(OFPMatchField):
+ pack_str = '!Q'
+
+ def __init__(self, header, value, mask=None):
+ super(MTTunnelId, self).__init__(header)
+ self.value = value
+ self.mask = mask
+
+
+@OFPMatchField.register_field_header([ofproto.OXM_OF_IPV6_EXTHDR,
+ ofproto.OXM_OF_IPV6_EXTHDR_W])
+class MTIPv6ExtHdr(OFPMatchField):
+ pack_str = '!H'
+
+ def __init__(self, header, value, mask=None):
+ super(MTIPv6ExtHdr, self).__init__(header)
+ self.value = value
+ self.mask = mask
+
+
+@_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
+ 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):
+ _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('\0')
+ props = []
+ rest = buf[offset + ofproto.OFP_PORT_SIZE:offset + length]
+ while rest:
+ p, rest = OFPPortProp.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()
+
+
+@_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=[]):
+ super(OFPMeterMod, self).__init__(datapath)
+ self.command = command
+ self.flags = flags
+ self.meter_id = meter_id
+ self.bands = bands
+
+ 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 = ofproto.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, buffer(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 = map(lambda x: x.rstrip('\0'), 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 = datapath.ofproto
+ 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('\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 = {}
+
+ @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
+ ofproto_parser.msg_pack_into("%dx" % pad_len, buf, len(buf))
+
+ return buf
+
+
+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, buffer(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=[]):
+ 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, buffer(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=[]):
+ 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=[]):
+ 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, buffer(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, buffer(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,
+ buffer(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=[]):
+ 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)
+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=[], type_=None):
+ 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 ``OFPPortDescStats`` 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_tablet_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 ``OFPTableDescStats`` 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', ports)
+ """
+ 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_tablet_desc_stats_request(self, datapath):
+ 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 ``OFPQueueDescStats`` 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' %
+ (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_STATS, 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_STATS, 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', groups)
+ """
+ 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 = datapath.ofproto
+ 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_STATS, 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_STATS, 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_DESC, 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_DESC, 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', configs)
+ """
+ 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=[]):
+ 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_stats_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' %
+ (stat.table_id, stat.reason,
+ stat.idle_timeout, stat.hard_timeout,
+ stat.priority, stat.cookie,
+ stat.match, stat.instructions)
+ elif update.event == ofp.OFPFME_ABBREV:
+ update_str += 'xid=%d' % (stat.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.length = 0
+ 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
+
+ @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_STATS, 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_STATS, 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_STATS, 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_STATS, 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
+
+
+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_STATS, 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 = datapath.ofproto
+ 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_STATS, 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(StringifyMixin):
+ 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(StringifyMixin):
+ 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
+
+
+@_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::
+
+ def send_bundle_add_message(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
+ msg = ofp_parser.OFPGroupMod(datapath, ofp.OFPGC_ADD,
+ ofp.OFPGT_SELECT, group_id, buckets)
+
+ req = ofp_parser.OFPRequestForward(datapath, msg)
+ datapath.send_msg(req)
+ """
+ def __init__(self, datapath, request):
+ super(OFPRequestForward, self).__init__(datapath)
+ assert(isinstance(request, OFPGroupMod) or
+ isinstance(request, OFPMeterMod))
+ self.request = request
+
+ def _serialize_body(self):
+ tail_buf = 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
+ ================ ======================================================
+
+ 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
+ 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)
+
+
+@_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,
+ imporotance,
+ 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=[]):
+ 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
+
+
+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
+ ofproto_parser.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)
+
+
+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")
+ """
+ def __init__(self, field=None, **kwargs):
+ super(OFPActionSetField, self).__init__()
+ assert len(kwargs) == 1
+ key = kwargs.keys()[0]
+ value = kwargs[key]
+ assert isinstance(key, (str, unicode))
+ 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_)
+ ofproto_parser.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)
+ }
+ }
+
+ @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()
+
+ @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_METER,
+ ofproto.OFP_ACTION_METER_SIZE)
+class OFPActionMeter(OFPAction):
+ """
+ Meter action
+
+ This action applies meter (rate limiter)
+
+ ================ ======================================================
+ Attribute Description
+ ================ ======================================================
+ meter_id Meter instance
+ ================ ======================================================
+ """
+ def __init__(self, meter_id,
+ type_=None, len_=None):
+ super(OFPActionMeter, self).__init__()
+ self.meter_id = meter_id
+
+ @classmethod
+ def parser(cls, buf, offset):
+ type_, len_, meter_id = struct.unpack_from(
+ ofproto.OFP_ACTION_METER_PACK_STR, buf, offset)
+ return cls(meter_id)
+
+ def serialize(self, buf, offset):
+ msg_pack_into(ofproto.OFP_ACTION_METER_PACK_STR, buf,
+ offset, self.type, self.len, self.meter_id)
+
+
+@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
+ ================ ======================================================
+ """
+ def __init__(self, experimenter, data=None, type_=None, len_=None):
+ super(OFPActionExperimenter, self).__init__()
+ self.experimenter = experimenter
+ self.data = data
+ self.len = (utils.round_up(len(data), 8) +
+ ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE)
+
+ @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_]
+ return cls(experimenter, data)
+
+ def serialize(self, buf, offset):
+ msg_pack_into(ofproto.OFP_ACTION_EXPERIMENTER_HEADER_PACK_STR,
+ buf, offset, self.type, self.len, self.experimenter)
+ if self.data:
+ buf += self.data
+
+
+@_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=[]):
+ super(OFPGroupMod, self).__init__(datapath)
+ self.command = command
+ self.type = type_
+ self.group_id = group_id
+ self.buckets = buckets
+
+ 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 OFPPortModPropEthernet(StringifyMixin):
+ 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(StringifyMixin):
+ 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 ``OFPPortProp`` 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
+ 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(StringifyMixin):
+ 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(
+ 8, ofp_parser.OFPACPT_PACKET_IN_SLAVE,
+ (ofp_parser.OFPR_APPLY_ACTION |
+ ofp_parser.OFPR_INVALID_TTL)),
+ ofp_parser.OFPAsyncConfigPropExperimenter(
+ ofproto.OFPTFPT_EXPERIMENTER_MASTER,
+ 16, 100, 2, bytearray())]
+ 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
+
+
+@_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, type_, flags, properties):
+ 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
+
+
+@_set_msg_type(ofproto.OFPT_BUNDLE_ADD_MESSAGE)
+class OFPBundleAddMsg(MsgInMsgBase):
+ """
+ Bundle control message
+
+ The controller uses this message to create, destroy and commit bundles
+
+ ================ ======================================================
+ 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
+ ofproto_parser.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
diff --git a/ryu/ofproto/oxm_fields.py b/ryu/ofproto/oxm_fields.py
index ed7f821d..d8ea8fda 100644
--- a/ryu/ofproto/oxm_fields.py
+++ b/ryu/ofproto/oxm_fields.py
@@ -70,6 +70,7 @@ from ryu.lib import type_desc
OFPXMC_NXM_0 = 0 # Nicira Extended Match (NXM_OF_)
OFPXMC_NXM_1 = 1 # Nicira Extended Match (NXM_NX_)
OFPXMC_OPENFLOW_BASIC = 0x8000
+OFPXMC_PACKET_REGS = 0x8001
OFPXMC_EXPERIMENTER = 0xffff
@@ -87,6 +88,10 @@ class OpenFlowBasic(_OxmClass):
_class = OFPXMC_OPENFLOW_BASIC
+class PacketRegs(_OxmClass):
+ _class = OFPXMC_PACKET_REGS
+
+
class _Experimenter(_OxmClass):
_class = OFPXMC_EXPERIMENTER
diff --git a/ryu/tests/switch/tester.py b/ryu/tests/switch/tester.py
index 02a1de10..7ce4277f 100644
--- a/ryu/tests/switch/tester.py
+++ b/ryu/tests/switch/tester.py
@@ -51,6 +51,7 @@ from ryu.ofproto import ofproto_protocol
from ryu.ofproto import ofproto_v1_3
from ryu.ofproto import ofproto_v1_3_parser
from ryu.ofproto import ofproto_v1_4
+from ryu.ofproto import ofproto_v1_5
""" Required test network:
@@ -287,13 +288,15 @@ class OfTester(app_manager.RyuApp):
def __get_version(opt):
vers = {
'openflow13': ofproto_v1_3.OFP_VERSION,
- 'openflow14': ofproto_v1_4.OFP_VERSION
+ 'openflow14': ofproto_v1_4.OFP_VERSION,
+ 'openflow15': ofproto_v1_5.OFP_VERSION
}
ver = vers.get(opt.lower())
if ver is None:
self.logger.error(
'%s is not supported. '
- 'Supported versions are openflow13 and openflow14.',
+ 'Supported versions are openflow13, '
+ 'openflow14 and openflow15.',
opt)
self._test_end()
return ver
@@ -360,7 +363,8 @@ class OfTester(app_manager.RyuApp):
def _register_sw(self, dp):
vers = {
ofproto_v1_3.OFP_VERSION: 'openflow13',
- ofproto_v1_4.OFP_VERSION: 'openflow14'
+ ofproto_v1_4.OFP_VERSION: 'openflow14',
+ ofproto_v1_5.OFP_VERSION: 'openflow15'
}
if dp.id == self.target_dpid:
if dp.ofproto.OFP_VERSION != OfTester.target_ver:
diff --git a/ryu/tests/unit/ofproto/test_ofproto.py b/ryu/tests/unit/ofproto/test_ofproto.py
index 9ab5eef5..272747df 100644
--- a/ryu/tests/unit/ofproto/test_ofproto.py
+++ b/ryu/tests/unit/ofproto/test_ofproto.py
@@ -45,16 +45,19 @@ class TestOfprotCommon(unittest.TestCase):
import ryu.ofproto.ofproto_v1_2
import ryu.ofproto.ofproto_v1_3
import ryu.ofproto.ofproto_v1_4
+ import ryu.ofproto.ofproto_v1_5
eq_(set(ofp_modules.keys()), set([ryu.ofproto.ofproto_v1_0.OFP_VERSION,
ryu.ofproto.ofproto_v1_2.OFP_VERSION,
ryu.ofproto.ofproto_v1_3.OFP_VERSION,
ryu.ofproto.ofproto_v1_4.OFP_VERSION,
+ ryu.ofproto.ofproto_v1_5.OFP_VERSION,
]))
consts_mods = set([ofp_mod[0] for ofp_mod in ofp_modules.values()])
eq_(consts_mods, set([ryu.ofproto.ofproto_v1_0,
ryu.ofproto.ofproto_v1_2,
ryu.ofproto.ofproto_v1_3,
ryu.ofproto.ofproto_v1_4,
+ ryu.ofproto.ofproto_v1_5,
]))
parser_mods = set([ofp_mod[1] for ofp_mod in ofp_modules.values()])
@@ -62,8 +65,10 @@ class TestOfprotCommon(unittest.TestCase):
import ryu.ofproto.ofproto_v1_2_parser
import ryu.ofproto.ofproto_v1_3_parser
import ryu.ofproto.ofproto_v1_4_parser
+ import ryu.ofproto.ofproto_v1_5_parser
eq_(parser_mods, set([ryu.ofproto.ofproto_v1_0_parser,
ryu.ofproto.ofproto_v1_2_parser,
ryu.ofproto.ofproto_v1_3_parser,
ryu.ofproto.ofproto_v1_4_parser,
+ ryu.ofproto.ofproto_v1_5_parser,
]))
diff --git a/ryu/tests/unit/ofproto/test_parser.py b/ryu/tests/unit/ofproto/test_parser.py
index 0dc2398c..4a9c83a9 100644
--- a/ryu/tests/unit/ofproto/test_parser.py
+++ b/ryu/tests/unit/ofproto/test_parser.py
@@ -26,6 +26,7 @@ from ryu.ofproto import ofproto_v1_0
from ryu.ofproto import ofproto_v1_2
from ryu.ofproto import ofproto_v1_3
from ryu.ofproto import ofproto_v1_4
+from ryu.ofproto import ofproto_v1_5
import json
@@ -117,6 +118,36 @@ implemented = {
ofproto_v1_4.OFPT_BUNDLE_CONTROL: (False, True),
ofproto_v1_4.OFPT_BUNDLE_ADD_MESSAGE: (False, True),
},
+ 6: {
+ ofproto_v1_5.OFPT_HELLO: (True, False),
+ ofproto_v1_5.OFPT_FEATURES_REQUEST: (False, True),
+ ofproto_v1_5.OFPT_FEATURES_REPLY: (True, False),
+ ofproto_v1_5.OFPT_GET_CONFIG_REQUEST: (False, True),
+ ofproto_v1_5.OFPT_GET_CONFIG_REPLY: (True, False),
+ ofproto_v1_5.OFPT_SET_CONFIG: (False, True),
+ ofproto_v1_5.OFPT_PACKET_IN: (True, False),
+ ofproto_v1_5.OFPT_FLOW_REMOVED: (True, False),
+ ofproto_v1_5.OFPT_PORT_STATUS: (True, False),
+ ofproto_v1_5.OFPT_PACKET_OUT: (False, True),
+ ofproto_v1_5.OFPT_FLOW_MOD: (False, True),
+ ofproto_v1_5.OFPT_GROUP_MOD: (False, True),
+ ofproto_v1_5.OFPT_PORT_MOD: (False, True),
+ ofproto_v1_5.OFPT_METER_MOD: (False, True),
+ ofproto_v1_5.OFPT_TABLE_MOD: (False, True),
+ ofproto_v1_5.OFPT_MULTIPART_REQUEST: (False, True),
+ ofproto_v1_5.OFPT_MULTIPART_REPLY: (True, False),
+ ofproto_v1_5.OFPT_BARRIER_REQUEST: (False, True),
+ ofproto_v1_5.OFPT_ROLE_REQUEST: (False, True),
+ ofproto_v1_5.OFPT_ROLE_REPLY: (True, False),
+ ofproto_v1_5.OFPT_GET_ASYNC_REQUEST: (False, True),
+ ofproto_v1_5.OFPT_GET_ASYNC_REPLY: (True, False),
+ ofproto_v1_5.OFPT_SET_ASYNC: (False, True),
+ ofproto_v1_5.OFPT_ROLE_STATUS: (True, False),
+ ofproto_v1_5.OFPT_TABLE_STATUS: (True, False),
+ ofproto_v1_5.OFPT_REQUESTFORWARD: (False, True),
+ ofproto_v1_5.OFPT_BUNDLE_CONTROL: (False, True),
+ ofproto_v1_5.OFPT_BUNDLE_ADD_MESSAGE: (False, True),
+ },
}