diff options
author | Shu Shen <shu.shen@gmail.com> | 2015-02-11 16:22:20 -0800 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2015-02-15 09:06:20 +0900 |
commit | 2889711e4670b08d5afbe2f408a511d9acbb5f52 (patch) | |
tree | af9cf36e15a976ff477cd47e64234b4e32842a22 | |
parent | 45e37843b9f38192a9440f62803abbdc1df7a400 (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.py | 3 | ||||
-rw-r--r-- | ryu/ofproto/ofproto_v1_5.py | 1798 | ||||
-rw-r--r-- | ryu/ofproto/ofproto_v1_5_parser.py | 6083 | ||||
-rw-r--r-- | ryu/ofproto/oxm_fields.py | 5 | ||||
-rw-r--r-- | ryu/tests/switch/tester.py | 10 | ||||
-rw-r--r-- | ryu/tests/unit/ofproto/test_ofproto.py | 5 | ||||
-rw-r--r-- | ryu/tests/unit/ofproto/test_parser.py | 31 |
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), + }, } |