os-ken/os_ken/ofproto/ofproto_v1_5_parser.py
elajkat 5c8aea475a Raise ValueError in case unpack_from returns zero length
Merge-conflicts:
os_ken/ofproto/ofproto_v1_3_parser.py
os_ken/ofproto/ofproto_v1_4_parser.py
os_ken/ofproto/ofproto_v1_5_parser.py

Closes-Bug: #2067973
Closes-Bug: #2067970
Change-Id: If3327be6c0a4c25173473fb8879d111544d77af5
(cherry picked from commit 2f30f44406)
2024-06-26 12:46:53 +00:00

6943 lines
246 KiB
Python

# 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 base64
import six
from os_ken.lib import addrconv
from os_ken.lib.pack_utils import msg_pack_into
from os_ken.lib.packet import packet
from os_ken import exception
from os_ken import utils
from os_ken.ofproto.ofproto_parser import StringifyMixin, MsgBase, MsgInMsgBase
from os_ken.ofproto import ether
from os_ken.ofproto import nx_actions
from os_ken.ofproto import ofproto_parser
from os_ken.ofproto import ofproto_common
from os_ken.ofproto 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 OSKen framework, so the OSKen application
do not need to process this typically.
========== =========================================================
Attribute Description
========== =========================================================
elements list of ``OFPHelloElemVersionBitmap`` instance
========== =========================================================
"""
def __init__(self, datapath, elements=None):
elements = elements if elements else []
super(OFPHello, self).__init__(datapath)
self.elements = elements
@classmethod
def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
msg = super(OFPHello, cls).parser(datapath, version, msg_type,
msg_len, xid, buf)
offset = ofproto.OFP_HELLO_HEADER_SIZE
elems = []
while offset < msg.msg_len:
type_, length = struct.unpack_from(
ofproto.OFP_HELLO_ELEM_HEADER_PACK_STR, msg.buf, offset)
# better to register Hello Element classes but currently
# Only VerisonBitmap is supported so let's be simple.
if type_ == ofproto.OFPHET_VERSIONBITMAP:
elem = OFPHelloElemVersionBitmap.parser(msg.buf, offset)
elems.append(elem)
offset += length
msg.elements = elems
return msg
class OFPHelloElemVersionBitmap(StringifyMixin):
"""
Version bitmap Hello Element
========== =========================================================
Attribute Description
========== =========================================================
versions list of versions of OpenFlow protocol a device supports
========== =========================================================
"""
def __init__(self, versions, type_=None, length=None):
super(OFPHelloElemVersionBitmap, self).__init__()
self.type = ofproto.OFPHET_VERSIONBITMAP
self.length = None
self._bitmaps = None
self.versions = versions
@classmethod
def parser(cls, buf, offset):
type_, length = struct.unpack_from(
ofproto.OFP_HELLO_ELEM_VERSIONBITMAP_HEADER_PACK_STR,
buf, offset)
assert type_ == ofproto.OFPHET_VERSIONBITMAP
bitmaps_len = (length -
ofproto.OFP_HELLO_ELEM_VERSIONBITMAP_HEADER_SIZE)
offset += ofproto.OFP_HELLO_ELEM_VERSIONBITMAP_HEADER_SIZE
bitmaps = []
while bitmaps_len >= 4:
bitmap = struct.unpack_from('!I', buf, offset)
bitmaps.append(bitmap[0])
offset += 4
bitmaps_len -= 4
versions = [i * 32 + shift
for i, bitmap in enumerate(bitmaps)
for shift in range(31) if bitmap & (1 << shift)]
elem = cls(versions)
elem.length = length
elem._bitmaps = bitmaps
return elem
@_register_parser
@_set_msg_type(ofproto.OFPT_ECHO_REQUEST)
class OFPEchoRequest(MsgBase):
"""
Echo request message
This message is handled by the OSKen framework, so the OSKen application
do not need to process this typically.
========== =========================================================
Attribute Description
========== =========================================================
data An arbitrary length data
========== =========================================================
Example::
def send_echo_request(self, datapath, data):
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 ``os_ken.ofproto.ofproto``.
============================= ===========
Type Code
============================= ===========
OFPET_HELLO_FAILED OFPHFC_*
OFPET_BAD_REQUEST OFPBRC_*
OFPET_BAD_ACTION OFPBAC_*
OFPET_BAD_INSTRUCTION OFPBIC_*
OFPET_BAD_MATCH OFPBMC_*
OFPET_FLOW_MOD_FAILED OFPFMFC_*
OFPET_GROUP_MOD_FAILED OFPGMFC_*
OFPET_PORT_MOD_FAILED OFPPMFC_*
OFPET_TABLE_MOD_FAILED OFPTMFC_*
OFPET_QUEUE_OP_FAILED OFPQOFC_*
OFPET_SWITCH_CONFIG_FAILED OFPSCFC_*
OFPET_ROLE_REQUEST_FAILED OFPRRFC_*
OFPET_METER_MOD_FAILED OFPMMFC_*
OFPET_TABLE_FEATURES_FAILED OFPTFFC_*
OFPET_EXPERIMENTER N/A
============================= ===========
If ``type == OFPET_EXPERIMENTER``, this message has also the following
attributes.
============= ======================================================
Attribute Description
============= ======================================================
exp_type Experimenter defined type
experimenter Experimenter ID
============= ======================================================
Example::
@set_ev_cls(ofp_event.EventOFPErrorMsg,
[HANDSHAKE_DISPATCHER, CONFIG_DISPATCHER, MAIN_DISPATCHER])
def error_msg_handler(self, ev):
msg = ev.msg
self.logger.debug('OFPErrorMsg received: type=0x%02x code=0x%02x '
'message=%s',
msg.type, msg.code, utils.hex_array(msg.data))
"""
def __init__(self, datapath, type_=None, code=None, data=None, **kwargs):
super(OFPErrorMsg, self).__init__(datapath)
self.type = type_
self.code = code
if isinstance(data, six.string_types):
data = data.encode('ascii')
self.data = data
if self.type == ofproto.OFPET_EXPERIMENTER:
self.exp_type = kwargs.get('exp_type', None)
self.experimenter = kwargs.get('experimenter', None)
@classmethod
def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
type_, = struct.unpack_from('!H', six.binary_type(buf),
ofproto.OFP_HEADER_SIZE)
msg = super(OFPErrorMsg, cls).parser(datapath, version, msg_type,
msg_len, xid, buf)
if type_ == ofproto.OFPET_EXPERIMENTER:
(msg.type, msg.exp_type, msg.experimenter,
msg.data) = cls.parse_experimenter_body(buf)
else:
(msg.type, msg.code,
msg.data) = cls.parse_body(buf)
return msg
@classmethod
def parse_body(cls, buf):
type_, code = struct.unpack_from(
ofproto.OFP_ERROR_MSG_PACK_STR, buf,
ofproto.OFP_HEADER_SIZE)
data = buf[ofproto.OFP_ERROR_MSG_SIZE:]
return type_, code, data
@classmethod
def parse_experimenter_body(cls, buf):
type_, exp_type, experimenter = struct.unpack_from(
ofproto.OFP_ERROR_EXPERIMENTER_MSG_PACK_STR, buf,
ofproto.OFP_HEADER_SIZE)
data = buf[ofproto.OFP_ERROR_EXPERIMENTER_MSG_SIZE:]
return type_, exp_type, experimenter, data
def _serialize_body(self):
assert self.data is not None
if self.type == ofproto.OFPET_EXPERIMENTER:
msg_pack_into(ofproto.OFP_ERROR_EXPERIMENTER_MSG_PACK_STR,
self.buf, ofproto.OFP_HEADER_SIZE,
self.type, self.exp_type, self.experimenter)
self.buf += self.data
else:
msg_pack_into(ofproto.OFP_ERROR_MSG_PACK_STR,
self.buf, ofproto.OFP_HEADER_SIZE,
self.type, self.code)
self.buf += self.data
# For the backward compatibility
def OFPErrorExperimenterMsg(datapath, type_=None, exp_type=None,
experimenter=None, data=None):
msg = OFPErrorMsg(datapath, data=data)
msg.type = ofproto.OFPET_EXPERIMENTER
msg.exp_type = exp_type
msg.experimenter = experimenter
return msg
@_register_parser
@_set_msg_type(ofproto.OFPT_ECHO_REPLY)
class OFPEchoReply(MsgBase):
"""
Echo reply message
This message is handled by the OSKen framework, so the OSKen application
do not need to process this typically.
========== =========================================================
Attribute Description
========== =========================================================
data An arbitrary length data
========== =========================================================
Example::
def send_echo_reply(self, datapath, data):
ofp_parser = datapath.ofproto_parser
reply = ofp_parser.OFPEchoReply(datapath, data)
datapath.send_msg(reply)
@set_ev_cls(ofp_event.EventOFPEchoReply,
[HANDSHAKE_DISPATCHER, CONFIG_DISPATCHER, MAIN_DISPATCHER])
def echo_reply_handler(self, ev):
self.logger.debug('OFPEchoReply received: data=%s',
utils.hex_array(ev.msg.data))
"""
def __init__(self, datapath, data=None):
super(OFPEchoReply, self).__init__(datapath)
self.data = data
@classmethod
def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
msg = super(OFPEchoReply, cls).parser(datapath, version, msg_type,
msg_len, xid, buf)
msg.data = msg.buf[ofproto.OFP_HEADER_SIZE:]
return msg
def _serialize_body(self):
assert self.data is not None
self.buf += self.data
@_set_msg_type(ofproto.OFPT_FEATURES_REQUEST)
class OFPFeaturesRequest(MsgBase):
"""
Features request message
The controller sends a feature request to the switch upon session
establishment.
This message is handled by the OSKen framework, so the OSKen 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 OSKen framework, so the OSKen application
do not need to process this typically.
Example::
@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def switch_features_handler(self, ev):
msg = ev.msg
self.logger.debug('OFPSwitchFeatures received: '
'datapath_id=0x%016x n_buffers=%d '
'n_tables=%d auxiliary_id=%d '
'capabilities=0x%08x',
msg.datapath_id, msg.n_buffers, msg.n_tables,
msg.auxiliary_id, msg.capabilities)
"""
def __init__(self, datapath, datapath_id=None, n_buffers=None,
n_tables=None, auxiliary_id=None, capabilities=None):
super(OFPSwitchFeatures, self).__init__(datapath)
self.datapath_id = datapath_id
self.n_buffers = n_buffers
self.n_tables = n_tables
self.auxiliary_id = auxiliary_id
self.capabilities = capabilities
@classmethod
def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
msg = super(OFPSwitchFeatures, cls).parser(datapath, version, msg_type,
msg_len, xid, buf)
(msg.datapath_id,
msg.n_buffers,
msg.n_tables,
msg.auxiliary_id,
msg.capabilities,
msg._reserved) = struct.unpack_from(
ofproto.OFP_SWITCH_FEATURES_PACK_STR, msg.buf,
ofproto.OFP_HEADER_SIZE)
return msg
@_set_msg_type(ofproto.OFPT_GET_CONFIG_REQUEST)
class OFPGetConfigRequest(MsgBase):
"""
Get config request message
The controller sends a get config request to query configuration
parameters in the switch.
Example::
def send_get_config_request(self, datapath):
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPGetConfigRequest(datapath)
datapath.send_msg(req)
"""
def __init__(self, datapath):
super(OFPGetConfigRequest, self).__init__(datapath)
@_register_parser
@_set_msg_type(ofproto.OFPT_GET_CONFIG_REPLY)
class OFPGetConfigReply(MsgBase):
"""
Get config reply message
The switch responds to a configuration request with a get config reply
message.
============= =========================================================
Attribute Description
============= =========================================================
flags Bitmap of the following flags.
| OFPC_FRAG_NORMAL
| OFPC_FRAG_DROP
| OFPC_FRAG_REASM
miss_send_len Max bytes of new flow that datapath should send to the
controller
============= =========================================================
Example::
@set_ev_cls(ofp_event.EventOFPGetConfigReply, MAIN_DISPATCHER)
def get_config_reply_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
flags = []
if msg.flags & ofp.OFPC_FRAG_NORMAL:
flags.append('NORMAL')
if msg.flags & ofp.OFPC_FRAG_DROP:
flags.append('DROP')
if msg.flags & ofp.OFPC_FRAG_REASM:
flags.append('REASM')
self.logger.debug('OFPGetConfigReply received: '
'flags=%s miss_send_len=%d',
','.join(flags), msg.miss_send_len)
"""
def __init__(self, datapath, flags=None, miss_send_len=None):
super(OFPGetConfigReply, self).__init__(datapath)
self.flags = flags
self.miss_send_len = miss_send_len
@classmethod
def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
msg = super(OFPGetConfigReply, cls).parser(datapath, version, msg_type,
msg_len, xid, buf)
msg.flags, msg.miss_send_len = struct.unpack_from(
ofproto.OFP_SWITCH_CONFIG_PACK_STR, msg.buf,
ofproto.OFP_HEADER_SIZE)
return msg
@_set_msg_type(ofproto.OFPT_SET_CONFIG)
class OFPSetConfig(MsgBase):
"""
Set config request message
The controller sends a set config request message to set configuraion
parameters.
============= =========================================================
Attribute Description
============= =========================================================
flags Bitmap of the following flags.
| OFPC_FRAG_NORMAL
| OFPC_FRAG_DROP
| OFPC_FRAG_REASM
miss_send_len Max bytes of new flow that datapath should send to the
controller
============= =========================================================
Example::
def send_set_config(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPSetConfig(datapath, ofp.OFPC_FRAG_NORMAL, 256)
datapath.send_msg(req)
"""
def __init__(self, datapath, flags=0, miss_send_len=0):
super(OFPSetConfig, self).__init__(datapath)
self.flags = flags
self.miss_send_len = miss_send_len
def _serialize_body(self):
assert self.flags is not None
assert self.miss_send_len is not None
msg_pack_into(ofproto.OFP_SWITCH_CONFIG_PACK_STR,
self.buf, ofproto.OFP_HEADER_SIZE,
self.flags, self.miss_send_len)
class OFPMatch(StringifyMixin):
"""
Flow Match Structure
This class is implementation of the flow match structure having
compose/query API.
You can define the flow match by the keyword arguments.
The following arguments are available.
================ =============== ==================================
Argument Value Description
================ =============== ==================================
in_port Integer 32bit Switch input port
in_phy_port Integer 32bit Switch physical input port
metadata Integer 64bit Metadata passed between tables
eth_dst MAC address Ethernet destination address
eth_src MAC address Ethernet source address
eth_type Integer 16bit Ethernet frame type
vlan_vid Integer 16bit VLAN id
vlan_pcp Integer 8bit VLAN priority
ip_dscp Integer 8bit IP DSCP (6 bits in ToS field)
ip_ecn Integer 8bit IP ECN (2 bits in ToS field)
ip_proto Integer 8bit IP protocol
ipv4_src IPv4 address IPv4 source address
ipv4_dst IPv4 address IPv4 destination address
tcp_src Integer 16bit TCP source port
tcp_dst Integer 16bit TCP destination port
udp_src Integer 16bit UDP source port
udp_dst Integer 16bit UDP destination port
sctp_src Integer 16bit SCTP source port
sctp_dst Integer 16bit SCTP destination port
icmpv4_type Integer 8bit ICMP type
icmpv4_code Integer 8bit ICMP code
arp_op Integer 16bit ARP opcode
arp_spa IPv4 address ARP source IPv4 address
arp_tpa IPv4 address ARP target IPv4 address
arp_sha MAC address ARP source hardware address
arp_tha MAC address ARP target hardware address
ipv6_src IPv6 address IPv6 source address
ipv6_dst IPv6 address IPv6 destination address
ipv6_flabel Integer 32bit IPv6 Flow Label
icmpv6_type Integer 8bit ICMPv6 type
icmpv6_code Integer 8bit ICMPv6 code
ipv6_nd_target IPv6 address Target address for ND
ipv6_nd_sll MAC address Source link-layer for ND
ipv6_nd_tll MAC address Target link-layer for ND
mpls_label Integer 32bit MPLS label
mpls_tc Integer 8bit MPLS TC
mpls_bos Integer 8bit MPLS BoS bit
pbb_isid Integer 24bit PBB I-SID
tunnel_id Integer 64bit Logical Port Metadata
ipv6_exthdr Integer 16bit IPv6 Extension Header pseudo-field
pbb_uca Integer 8bit PBB UCA header field
tcp_flags Integer 16bit TCP flags
actset_output Integer 32bit Output port from action set metadata
packet_type Integer 32bit Packet type value
================ =============== ==================================
Example::
>>> # compose
>>> match = parser.OFPMatch(
... in_port=1,
... eth_type=0x86dd,
... ipv6_src=('2001:db8:bd05:1d2:288a:1fc0:1:10ee',
... 'ffff:ffff:ffff:ffff::'),
... ipv6_dst='2001:db8:bd05:1d2:288a:1fc0:1:10ee')
>>> # query
>>> if 'ipv6_src' in match:
... print match['ipv6_src']
...
('2001:db8:bd05:1d2:288a:1fc0:1:10ee', 'ffff:ffff:ffff:ffff::')
.. Note::
For the list of the supported Nicira experimenter matches,
please refer to :ref:`os_ken.ofproto.nx_match <nx_match_structures>`.
.. Note::
For VLAN id match field, special values are defined in OpenFlow Spec.
1) Packets with and without a VLAN tag
- Example::
match = parser.OFPMatch()
- Packet Matching
====================== =====
non-VLAN-tagged MATCH
VLAN-tagged(vlan_id=3) MATCH
VLAN-tagged(vlan_id=5) MATCH
====================== =====
2) Only packets without a VLAN tag
- Example::
match = parser.OFPMatch(vlan_vid=0x0000)
- Packet Matching
====================== =====
non-VLAN-tagged MATCH
VLAN-tagged(vlan_id=3) x
VLAN-tagged(vlan_id=5) x
====================== =====
3) Only packets with a VLAN tag regardless of its value
- Example::
match = parser.OFPMatch(vlan_vid=(0x1000, 0x1000))
- Packet Matching
====================== =====
non-VLAN-tagged x
VLAN-tagged(vlan_id=3) MATCH
VLAN-tagged(vlan_id=5) MATCH
====================== =====
4) Only packets with VLAN tag and VID equal
- Example::
match = parser.OFPMatch(vlan_vid=(0x1000 | 3))
- Packet Matching
====================== =====
non-VLAN-tagged x
VLAN-tagged(vlan_id=3) MATCH
VLAN-tagged(vlan_id=5) x
====================== =====
"""
def __init__(self, type_=None, length=None, _ordered_fields=None,
**kwargs):
super(OFPMatch, self).__init__()
self.type = ofproto.OFPMT_OXM
self.length = length
if _ordered_fields is not None:
assert not kwargs
self._fields2 = _ordered_fields
else:
kwargs = dict(ofproto.oxm_normalize_user(k, v) for
(k, v) in kwargs.items())
fields = [ofproto.oxm_from_user(k, v) for (k, v)
in kwargs.items()]
# assumption: sorting by OXM type values makes fields
# meet ordering requirements (eg. eth_type before ipv4_src)
fields.sort(
key=lambda x: x[0][0] if isinstance(x[0], tuple) else x[0])
self._fields2 = [ofproto.oxm_to_user(n, v, m) for (n, v, m)
in fields]
@classmethod
def parser(cls, buf, offset):
"""
Returns an object which is generated from a buffer including the
expression of the wire protocol of the flow match.
"""
match = OFPMatch()
type_, length = struct.unpack_from('!HH', buf, offset)
match.type = type_
match.length = length
# ofp_match adjustment
offset += 4
length -= 4
fields = []
while length > 0:
n, value, mask, field_len = ofproto.oxm_parse(buf, offset)
k, uv = ofproto.oxm_to_user(n, value, mask)
fields.append((k, uv))
offset += field_len
length -= field_len
match._fields2 = fields
return match
def serialize(self, buf, offset):
"""
Outputs the expression of the wire protocol of the flow match into
the buf.
Returns the output length.
"""
fields = [ofproto.oxm_from_user(k, uv) for (k, uv)
in self._fields2]
hdr_pack_str = '!HH'
field_offset = offset + struct.calcsize(hdr_pack_str)
for (n, value, mask) in fields:
field_offset += ofproto.oxm_serialize(n, value, mask, buf,
field_offset)
length = field_offset - offset
msg_pack_into(hdr_pack_str, buf, offset, ofproto.OFPMT_OXM, length)
self.length = length
pad_len = utils.round_up(length, 8) - length
msg_pack_into("%dx" % pad_len, buf, field_offset)
return length + pad_len
def __getitem__(self, key):
return dict(self._fields2)[key]
def __contains__(self, key):
return key in dict(self._fields2)
def iteritems(self):
return iter(dict(self._fields2).items())
def items(self):
return self._fields2
def get(self, key, default=None):
return dict(self._fields2).get(key, default)
def stringify_attrs(self):
yield "oxm_fields", dict(self._fields2)
def to_jsondict(self):
"""
Returns a dict expressing the flow match.
"""
body = {"oxm_fields": [ofproto.oxm_to_jsondict(k, uv) for k, uv
in self._fields2],
"length": self.length,
"type": self.type}
return {self.__class__.__name__: body}
@classmethod
def from_jsondict(cls, dict_):
"""
Returns an object which is generated from a dict.
Exception raises:
KeyError -- Unknown match field is defined in dict
"""
fields = [ofproto.oxm_from_jsondict(f) for f
in dict_['oxm_fields']]
return OFPMatch(_ordered_fields=fields)
class OFPStats(StringifyMixin):
"""
Flow Stats Structure
This class is implementation of the flow stats structure having
compose/query API.
You can define the flow stats by the keyword arguments.
The following arguments are available.
============= ================ ============================================
Argument Value Description
============= ================ ============================================
duration Integer 32bit*2 Time flow entry has been alive. This field
is a tuple of two Integer 32bit. The first
value is duration_sec and the second is
duration_nsec.
idle_time Integer 32bit*2 Time flow entry has been idle.
flow_count Integer 32bit Number of aggregated flow entries.
packet_count Integer 64bit Number of packets matched by a flow entry.
byte_count Integer 64bit Number of bytes matched by a flow entry.
============= ================ ============================================
Example::
>>> # compose
>>> stats = parser.OFPStats(
... packet_count=100,
... duration=(100, 200)
>>> # query
>>> if 'duration' in stats:
... print stats['duration']
...
(100, 200)
"""
def __init__(self, length=None, _ordered_fields=None, **kwargs):
super(OFPStats, self).__init__()
self.length = length
if _ordered_fields is not None:
assert not kwargs
self.fields = _ordered_fields
else:
fields = [ofproto.oxs_from_user(k, v) for (k, v)
in kwargs.items()]
# sort by OXS type values
fields.sort(
key=lambda x: x[0][0] if isinstance(x[0], tuple) else x[0])
# No mask
self.fields = [ofproto.oxs_to_user(n, v, None) for (n, v, _)
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 stats.
"""
stats = OFPStats()
reserved, length = struct.unpack_from('!HH', buf, offset)
stats.length = length
# ofp_stats adjustment
offset += 4
length -= 4
fields = []
while length > 0:
n, value, _, field_len = ofproto.oxs_parse(buf, offset)
k, uv = ofproto.oxs_to_user(n, value, None) # No mask
fields.append((k, uv))
offset += field_len
length -= field_len
stats.fields = fields
return stats
def serialize(self, buf, offset):
"""
Outputs the expression of the wire protocol of the flow stats into
the buf.
Returns the output length.
"""
fields = [ofproto.oxs_from_user(k, uv) for (k, uv)
in self.fields]
hdr_pack_str = '!HH'
field_offset = offset + struct.calcsize(hdr_pack_str)
for (n, value, _) in fields:
# No mask
field_offset += ofproto.oxs_serialize(n, value, None, buf,
field_offset)
reserved = 0
length = field_offset - offset
msg_pack_into(hdr_pack_str, buf, offset, reserved, length)
self.length = length
pad_len = utils.round_up(length, 8) - length
msg_pack_into("%dx" % pad_len, buf, field_offset)
return length + pad_len
def __getitem__(self, key):
return dict(self.fields)[key]
def __contains__(self, key):
return key in dict(self.fields)
def iteritems(self):
return dict(self.fields).items()
def items(self):
return self.fields
def get(self, key, default=None):
return dict(self.fields).get(key, default)
def stringify_attrs(self):
yield "oxs_fields", dict(self.fields)
def to_jsondict(self):
"""
Returns a dict expressing the flow stats.
"""
body = {"oxs_fields": [ofproto.oxs_to_jsondict(k, uv) for k, uv
in self.fields],
"length": self.length}
return {self.__class__.__name__: body}
@classmethod
def from_jsondict(cls, dict_):
"""
Returns an object which is generated from a dict.
Exception raises:
KeyError -- Unknown stats field is defined in dict
"""
fields = [ofproto.oxs_from_jsondict(f) for f
in dict_['oxs_fields']]
return OFPStats(_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)
if not length:
raise ValueError
rest = buf[utils.round_up(length, 8):]
try:
subcls = cls._TYPES[type_]
except KeyError:
subcls = OFPPropUnknown
prop = subcls.parser(buf)
prop.type = type_
prop.length = length
return prop, rest
@classmethod
def get_rest(cls, buf):
(type_, length) = struct.unpack_from(cls._PACK_STR, buf, 0)
offset = struct.calcsize(cls._PACK_STR)
return buf[offset:length]
def serialize(self):
# Body
# serialize_body should be implemented by subclass
body = bytearray()
body += self.serialize_body()
# fixup
self.length = len(body) + struct.calcsize(self._PACK_STR)
# Header
buf = bytearray()
msg_pack_into(self._PACK_STR, buf, 0, self.type, self.length)
buf += body
# Pad
pad_len = utils.round_up(self.length, 8) - self.length
msg_pack_into("%dx" % pad_len, buf, len(buf))
return buf
class OFPPropCommonExperimenter4ByteData(StringifyMixin):
_PACK_STR = '!HHII'
_EXPERIMENTER_DATA_PACK_STR = '!I'
_EXPERIMENTER_DATA_SIZE = 4
def __init__(self, type_=None, length=None, experimenter=None,
exp_type=None, data=bytearray()):
self.type = type_
self.length = length
self.experimenter = experimenter
self.exp_type = exp_type
self.data = data
@classmethod
def parser(cls, buf):
(type_, length, experimenter, exp_type) = struct.unpack_from(
ofproto.OFP_PROP_EXPERIMENTER_PACK_STR, buf, 0)
rest = buf[ofproto.OFP_PROP_EXPERIMENTER_SIZE:length]
data = []
while rest:
(d,) = struct.unpack_from(
cls._EXPERIMENTER_DATA_PACK_STR, rest, 0)
data.append(d)
rest = rest[cls._EXPERIMENTER_DATA_SIZE:]
return cls(type_, length, experimenter, exp_type, data)
def serialize(self):
offset = 0
bin_data = bytearray()
for d in self.data:
msg_pack_into(self._EXPERIMENTER_DATA_PACK_STR,
bin_data, offset, d)
offset += self._EXPERIMENTER_DATA_SIZE
# fixup
self.length = struct.calcsize(self._PACK_STR)
self.length += len(bin_data)
buf = bytearray()
msg_pack_into(self._PACK_STR, buf,
0, self.type, self.length, self.experimenter,
self.exp_type)
buf += bin_data
# Pad
pad_len = utils.round_up(self.length, 8) - self.length
msg_pack_into("%dx" % pad_len, buf, len(buf))
return buf
class OFPPortDescProp(OFPPropBase):
_TYPES = {}
@OFPPortDescProp.register_type(ofproto.OFPPDPT_ETHERNET)
class OFPPortDescPropEthernet(OFPPortDescProp):
def __init__(self, type_=None, length=None, curr=None, advertised=None,
supported=None, peer=None, curr_speed=None, max_speed=None):
self.type = type_
self.length = length
self.curr = curr
self.advertised = advertised
self.supported = supported
self.peer = peer
self.curr_speed = curr_speed
self.max_speed = max_speed
@classmethod
def parser(cls, buf):
ether = cls()
(ether.type, ether.length, ether.curr,
ether.advertised, ether.supported,
ether.peer, ether.curr_speed, ether.max_speed) = struct.unpack_from(
ofproto.OFP_PORT_DESC_PROP_ETHERNET_PACK_STR, buf, 0)
return ether
@OFPPortDescProp.register_type(ofproto.OFPPDPT_OPTICAL)
class OFPPortDescPropOptical(OFPPortDescProp):
def __init__(self, type_=None, length=None, supported=None,
tx_min_freq_lmda=None, tx_max_freq_lmda=None,
tx_grid_freq_lmda=None, rx_min_freq_lmda=None,
rx_max_freq_lmda=None, rx_grid_freq_lmda=None,
tx_pwr_min=None, tx_pwr_max=None):
self.type = type_
self.length = length
self.supported = supported
self.tx_min_freq_lmda = tx_min_freq_lmda
self.tx_max_freq_lmda = tx_max_freq_lmda
self.tx_grid_freq_lmda = tx_grid_freq_lmda
self.rx_min_freq_lmda = rx_min_freq_lmda
self.rx_max_freq_lmda = rx_max_freq_lmda
self.rx_grid_freq_lmda = rx_grid_freq_lmda
self.tx_pwr_min = tx_pwr_min
self.tx_pwr_max = tx_pwr_max
@classmethod
def parser(cls, buf):
optical = cls()
(optical.type, optical.length, optical.supported,
optical.tx_min_freq_lmda, optical.tx_max_freq_lmda,
optical.tx_grid_freq_lmda, optical.rx_min_freq_lmda,
optical.rx_max_freq_lmda, optical.rx_grid_freq_lmda,
optical.tx_pwr_min, optical.tx_pwr_max) = struct.unpack_from(
ofproto.OFP_PORT_DESC_PROP_OPTICAL_PACK_STR, buf, 0)
return optical
@OFPPortDescProp.register_type(ofproto.OFPPDPT_PIPELINE_INPUT)
@OFPPortDescProp.register_type(ofproto.OFPPDPT_PIPELINE_OUTPUT)
class OFPPortDescPropOxm(OFPPortDescProp):
def __init__(self, type_=None, length=None, oxm_ids=None):
oxm_ids = oxm_ids if oxm_ids else []
super(OFPPortDescPropOxm, 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
@OFPPortDescProp.register_type(ofproto.OFPPDPT_RECIRCULATE)
class OFPPortDescPropRecirculate(OFPPortDescProp):
_PORT_NO_PACK_STR = '!I'
def __init__(self, type_=None, length=None, port_nos=None):
port_nos = port_nos if port_nos else []
super(OFPPortDescPropRecirculate, self).__init__(type_, length)
self.port_nos = port_nos
@classmethod
def parser(cls, buf):
rest = cls.get_rest(buf)
nos = []
while rest:
(n,) = struct.unpack_from(cls._PORT_NO_PACK_STR,
six.binary_type(rest), 0)
rest = rest[struct.calcsize(cls._PORT_NO_PACK_STR):]
nos.append(n)
return cls(port_nos=nos)
def serialize_body(self):
bin_nos = bytearray()
for n in self.port_nos:
bin_no = bytearray()
msg_pack_into(self._PORT_NO_PACK_STR, bin_no, 0, n)
bin_nos += bin_no
return bin_nos
@OFPPortDescProp.register_type(ofproto.OFPPDPT_EXPERIMENTER)
class OFPPortDescPropExperimenter(OFPPropCommonExperimenter4ByteData):
pass
class OFPTableModProp(OFPPropBase):
_TYPES = {}
@OFPTableModProp.register_type(ofproto.OFPTMPT_EVICTION)
class OFPTableModPropEviction(OFPTableModProp):
def __init__(self, type_=None, length=None, flags=None):
self.type = type_
self.length = length
self.flags = flags
@classmethod
def parser(cls, buf):
eviction = cls()
(eviction.type, eviction.length, eviction.flags) = struct.unpack_from(
ofproto.OFP_TABLE_MOD_PROP_EVICTION_PACK_STR, buf, 0)
return eviction
def serialize(self):
# fixup
self.length = ofproto.OFP_TABLE_MOD_PROP_EVICTION_SIZE
buf = bytearray()
msg_pack_into(ofproto.OFP_TABLE_MOD_PROP_EVICTION_PACK_STR, buf, 0,
self.type, self.length, self.flags)
return buf
@OFPTableModProp.register_type(ofproto.OFPTMPT_VACANCY)
class OFPTableModPropVacancy(OFPTableModProp):
def __init__(self, type_=None, length=None, vacancy_down=None,
vacancy_up=None, vacancy=None):
self.type = type_
self.length = length
self.vacancy_down = vacancy_down
self.vacancy_up = vacancy_up
self.vacancy = vacancy
@classmethod
def parser(cls, buf):
vacancy = cls()
(vacancy.type, vacancy.length, vacancy.vacancy_down,
vacancy.vacancy_up, vacancy.vacancy) = struct.unpack_from(
ofproto.OFP_TABLE_MOD_PROP_VACANCY_PACK_STR, buf, 0)
return vacancy
def serialize(self):
# fixup
self.length = ofproto.OFP_TABLE_MOD_PROP_VACANCY_SIZE
buf = bytearray()
msg_pack_into(ofproto.OFP_TABLE_MOD_PROP_VACANCY_PACK_STR, buf, 0,
self.type, self.length, self.vacancy_down,
self.vacancy_up, self.vacancy)
return buf
@OFPTableModProp.register_type(ofproto.OFPTMPT_EXPERIMENTER)
class OFPTableModPropExperimenter(OFPPropCommonExperimenter4ByteData):
pass
class OFPQueueDescProp(OFPPropBase):
_TYPES = {}
@OFPQueueDescProp.register_type(ofproto.OFPQDPT_MIN_RATE)
class OFPQueueDescPropMinRate(OFPQueueDescProp):
def __init__(self, type_=None, length=None, rate=None):
self.type = type_
self.length = length
self.rate = rate
@classmethod
def parser(cls, buf):
minrate = cls()
(minrate.type, minrate.length, minrate.rate) = struct.unpack_from(
ofproto.OFP_QUEUE_DESC_PROP_MIN_RATE_PACK_STR, buf, 0)
return minrate
@OFPQueueDescProp.register_type(ofproto.OFPQDPT_MAX_RATE)
class OFPQueueDescPropMaxRate(OFPQueueDescProp):
def __init__(self, type_=None, length=None, rate=None):
self.type = type_
self.length = length
self.rate = rate
@classmethod
def parser(cls, buf):
maxrate = cls()
(maxrate.type, maxrate.length, maxrate.rate) = struct.unpack_from(
ofproto.OFP_QUEUE_DESC_PROP_MAX_RATE_PACK_STR, buf, 0)
return maxrate
@OFPQueueDescProp.register_type(ofproto.OFPQDPT_EXPERIMENTER)
class OFPQueueDescPropExperimenter(OFPPropCommonExperimenter4ByteData):
pass
class OFPRoleProp(OFPPropBase):
_TYPES = {}
@OFPRoleProp.register_type(ofproto.OFPRPT_EXPERIMENTER)
class OFPRolePropExperimenter(OFPPropCommonExperimenter4ByteData):
pass
class OFPTime(StringifyMixin):
def __init__(self, seconds=None, nanoseconds=None):
self.seconds = seconds
self.nanoseconds = nanoseconds
@classmethod
def parser(cls, buf, offset):
cls_ = cls()
(cls_.seconds, cls_.nanoseconds) = struct.unpack_from(
ofproto.OFP_TIME_PACK_STR, buf, offset)
return cls_
def serialize(self, buf, offset):
msg_pack_into(ofproto.OFP_TIME_PACK_STR, buf, offset,
self.seconds, self.nanoseconds)
return ofproto.OFP_TIME_SIZE
class OFPBundleProp(OFPPropBase):
_TYPES = {}
@OFPBundleProp.register_type(ofproto.OFPBPT_TIME)
class OFPBundlePropTime(OFPBundleProp):
def __init__(self, type_=None, length=None, scheduled_time=None):
super(OFPBundlePropTime, self).__init__(type_, length)
self.scheduled_time = scheduled_time
@classmethod
def parser(cls, buf):
prop = cls()
offset = ofproto.OFP_BUNDLE_PROP_TIME_PACK_STR0_SIZE
prop.scheduled_time = OFPTime.parser(buf, offset)
return prop
def serialize(self):
# fixup
self.length = ofproto.OFP_BUNDLE_PROP_TIME_PACK_STR_SIZE
buf = bytearray()
msg_pack_into(ofproto.OFP_BUNDLE_PROP_TIME_PACK_STR0, buf, 0,
self.type, self.length)
offset = ofproto.OFP_BUNDLE_PROP_TIME_PACK_STR0_SIZE
self.scheduled_time.serialize(buf, offset)
return buf
@OFPBundleProp.register_type(ofproto.OFPRPT_EXPERIMENTER)
class OFPBundlePropExperimenter(OFPPropCommonExperimenter4ByteData):
pass
@_register_parser
@_set_msg_type(ofproto.OFPT_PACKET_IN)
class OFPPacketIn(MsgBase):
"""
Packet-In message
The switch sends the packet that received to the controller by this
message.
============= =========================================================
Attribute Description
============= =========================================================
buffer_id ID assigned by datapath
total_len Full length of frame
reason Reason packet is being sent.
| OFPR_TABLE_MISS
| OFPR_APPLY_ACTION
| OFPR_INVALID_TTL
| OFPR_ACTION_SET
| OFPR_GROUP
| OFPR_PACKET_OUT
table_id ID of the table that was looked up
cookie Cookie of the flow entry that was looked up
match Instance of ``OFPMatch``
data Ethernet frame
============= =========================================================
Example::
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def packet_in_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
if msg.reason == ofp.TABLE_MISS:
reason = 'TABLE MISS'
elif msg.reason == ofp.OFPR_APPLY_ACTION:
reason = 'APPLY ACTION'
elif msg.reason == ofp.OFPR_INVALID_TTL:
reason = 'INVALID TTL'
elif msg.reason == ofp.OFPR_ACTION_SET:
reason = 'ACTION SET'
elif msg.reason == ofp.OFPR_GROUP:
reason = 'GROUP'
elif msg.reason == ofp.OFPR_PACKET_OUT:
reason = 'PACKET OUT'
else:
reason = 'unknown'
self.logger.debug('OFPPacketIn received: '
'buffer_id=%x total_len=%d reason=%s '
'table_id=%d cookie=%d match=%s data=%s',
msg.buffer_id, msg.total_len, reason,
msg.table_id, msg.cookie, msg.match,
utils.hex_array(msg.data))
"""
def __init__(self, datapath, buffer_id=None, total_len=None, reason=None,
table_id=None, cookie=None, match=None, data=None):
super(OFPPacketIn, self).__init__(datapath)
self.buffer_id = buffer_id
self.total_len = total_len
self.reason = reason
self.table_id = table_id
self.cookie = cookie
self.match = match
self.data = data
@classmethod
def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
msg = super(OFPPacketIn, cls).parser(datapath, version, msg_type,
msg_len, xid, buf)
(msg.buffer_id, msg.total_len, msg.reason,
msg.table_id, msg.cookie) = struct.unpack_from(
ofproto.OFP_PACKET_IN_PACK_STR,
msg.buf, ofproto.OFP_HEADER_SIZE)
msg.match = OFPMatch.parser(msg.buf, ofproto.OFP_PACKET_IN_SIZE -
ofproto.OFP_MATCH_SIZE)
match_len = utils.round_up(msg.match.length, 8)
msg.data = msg.buf[(ofproto.OFP_PACKET_IN_SIZE -
ofproto.OFP_MATCH_SIZE + match_len + 2):]
if msg.total_len < len(msg.data):
# discard padding for 8-byte alignment of OFP packet
msg.data = msg.data[:msg.total_len]
return msg
@_register_parser
@_set_msg_type(ofproto.OFPT_FLOW_REMOVED)
class OFPFlowRemoved(MsgBase):
"""
Flow removed message
When flow entries time out or are deleted, the switch notifies controller
with this message.
================ ======================================================
Attribute Description
================ ======================================================
table_id ID of the table
reason One of the following values.
| OFPRR_IDLE_TIMEOUT
| OFPRR_HARD_TIMEOUT
| OFPRR_DELETE
| OFPRR_GROUP_DELETE
| OFPRR_METER_DELETE
| OFPRR_EVICTION
priority Priority level of flow entry
idle_timeout Idle timeout from original flow mod
hard_timeout Hard timeout from original flow mod
cookie Opaque controller-issued identifier
match Instance of ``OFPMatch``
stats Instance of ``OFPStats``
================ ======================================================
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'
elif msg.reason == ofp.OFPRR_METER_DELETE:
reason = 'METER DELETE'
elif msg.reason == ofp.OFPRR_EVICTION:
reason = 'EVICTION'
else:
reason = 'unknown'
self.logger.debug('OFPFlowRemoved received: '
'table_id=%d reason=%s priority=%d '
'idle_timeout=%d hard_timeout=%d cookie=%d '
'match=%s stats=%s',
msg.table_id, reason, msg.priority,
msg.idle_timeout, msg.hard_timeout, msg.cookie,
msg.match, msg.stats)
"""
def __init__(self, datapath, table_id=None, reason=None, priority=None,
idle_timeout=None, hard_timeout=None, cookie=None,
match=None, stats=None):
super(OFPFlowRemoved, self).__init__(datapath)
self.table_id = table_id
self.reason = reason
self.priority = priority
self.idle_timeout = idle_timeout
self.hard_timeout = hard_timeout
self.cookie = cookie
self.match = match
self.stats = stats
@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.table_id, msg.reason, msg.priority, msg.idle_timeout,
msg.hard_timeout, msg.cookie) = 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)
offset += utils.round_up(msg.match.length, 8)
stats_length = msg.msg_len - offset
if stats_length > 0:
msg.stats = OFPStats.parser(buf, offset)
return msg
class OFPPort(StringifyMixin):
"""
Description of a port
========== =========================================================
Attribute Description
========== =========================================================
port_no Port number and it uniquely identifies a port within
a switch.
length Length of ofp_port (excluding padding).
hw_addr MAC address for the port.
name Null-terminated string containing a human-readable name
for the interface.
config Bitmap of port configration flags.
| OFPPC_PORT_DOWN
| OFPPC_NO_RECV
| OFPPC_NO_FWD
| OFPPC_NO_PACKET_IN
state Bitmap of port state flags.
| OFPPS_LINK_DOWN
| OFPPS_BLOCKED
| OFPPS_LIVE
properties List of ``OFPPortDescProp`` subclass instance
========== =========================================================
"""
_TYPE = {
'ascii': [
'hw_addr',
],
'utf-8': [
# OF spec is unclear about the encoding of name.
# we assumes UTF-8, which is used by OVS.
'name',
]
}
def __init__(self, port_no=None, length=None, hw_addr=None, name=None,
config=None, state=None, properties=None):
super(OFPPort, self).__init__()
self.port_no = port_no
self.length = length
self.hw_addr = hw_addr
self.name = name
self.config = config
self.state = state
self.properties = properties
@classmethod
def parser(cls, buf, offset):
(port_no, length, hw_addr, name, config, state) = struct.unpack_from(
ofproto.OFP_PORT_PACK_STR, buf, offset)
hw_addr = addrconv.mac.bin_to_text(hw_addr)
name = name.rstrip(b'\0')
props = []
rest = buf[offset + ofproto.OFP_PORT_SIZE:offset + length]
while rest:
p, rest = OFPPortDescProp.parse(rest)
props.append(p)
ofpport = cls(port_no, length, hw_addr, name, config, state, props)
return ofpport
class OFPTableDesc(StringifyMixin):
def __init__(self, length=None, table_id=None, config=None,
properties=None):
super(OFPTableDesc, self).__init__()
self.table_id = table_id
self.length = length
self.config = config
self.properties = properties
@classmethod
def parser(cls, buf, offset):
(length, table_id, config) = struct.unpack_from(
ofproto.OFP_TABLE_DESC_PACK_STR, buf, offset)
props = []
rest = buf[offset + ofproto.OFP_TABLE_DESC_SIZE:offset + length]
while rest:
p, rest = OFPTableModProp.parse(rest)
props.append(p)
ofptabledesc = cls(length, table_id, config, props)
return ofptabledesc
class OFPQueueDesc(StringifyMixin):
def __init__(self, port_no=None, queue_id=None, len_=None,
properties=None):
super(OFPQueueDesc, self).__init__()
self.port_no = port_no
self.queue_id = queue_id
self.len = len_
self.properties = properties
@classmethod
def parser(cls, buf, offset):
(port_no, queue_id, len_) = struct.unpack_from(
ofproto.OFP_QUEUE_DESC_PACK_STR, buf, offset)
props = []
rest = buf[offset + ofproto.OFP_QUEUE_DESC_SIZE:offset + len_]
while rest:
p, rest = OFPQueueDescProp.parse(rest)
props.append(p)
ofpqueuedesc = cls(port_no, queue_id, len_, props)
return ofpqueuedesc
def _set_stats_type(stats_type, stats_body_cls):
def _set_cls_stats_type(cls):
cls.cls_stats_type = stats_type
cls.cls_stats_body_cls = stats_body_cls
return cls
return _set_cls_stats_type
@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
class OFPMultipartRequest(MsgBase):
def __init__(self, datapath, flags):
super(OFPMultipartRequest, self).__init__(datapath)
self.type = self.__class__.cls_stats_type
self.flags = flags
def _serialize_stats_body(self):
pass
def _serialize_body(self):
msg_pack_into(ofproto.OFP_MULTIPART_REQUEST_PACK_STR,
self.buf, ofproto.OFP_HEADER_SIZE,
self.type, self.flags)
self._serialize_stats_body()
@_register_parser
@_set_msg_type(ofproto.OFPT_METER_MOD)
class OFPMeterMod(MsgBase):
"""
Meter modification message
The controller sends this message to modify the meter.
================ ======================================================
Attribute Description
================ ======================================================
command One of the following values.
| OFPMC_ADD
| OFPMC_MODIFY
| OFPMC_DELETE
flags Bitmap of the following flags.
| OFPMF_KBPS
| OFPMF_PKTPS
| OFPMF_BURST
| OFPMF_STATS
meter_id Meter instance
bands list of the following class instance.
| OFPMeterBandDrop
| OFPMeterBandDscpRemark
| OFPMeterBandExperimenter
================ ======================================================
"""
def __init__(self, datapath, command=ofproto.OFPMC_ADD,
flags=ofproto.OFPMF_KBPS, meter_id=1, bands=None):
bands = bands if bands else []
super(OFPMeterMod, self).__init__(datapath)
self.command = command
self.flags = flags
self.meter_id = meter_id
self.bands = bands
@classmethod
def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
msg = super(OFPMeterMod, cls).parser(
datapath, version, msg_type, msg_len, xid, buf)
(msg.command, msg.flags, msg.meter_id) = struct.unpack_from(
ofproto.OFP_METER_MOD_PACK_STR, buf, ofproto.OFP_HEADER_SIZE)
offset = ofproto.OFP_METER_MOD_SIZE
msg.bands = []
while offset < msg.msg_len:
band = OFPMeterBandHeader.parser(buf, offset)
msg.bands.append(band)
offset += band.len
return msg
def _serialize_body(self):
msg_pack_into(ofproto.OFP_METER_MOD_PACK_STR, self.buf,
ofproto.OFP_HEADER_SIZE,
self.command, self.flags, self.meter_id)
offset = ofproto.OFP_METER_MOD_SIZE
for b in self.bands:
b.serialize(self.buf, offset)
offset += b.len
@_set_msg_type(ofproto.OFPT_TABLE_MOD)
class OFPTableMod(MsgBase):
"""
Flow table configuration message
The controller sends this message to configure table state.
================ ======================================================
Attribute Description
================ ======================================================
table_id ID of the table (OFPTT_ALL indicates all tables)
config Bitmap of configuration flags.
| OFPTC_EVICTION
| OFPTC_VACANCY_EVENTS
properties List of ``OFPTableModProp`` subclass instance
================ ======================================================
Example::
def send_table_mod(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPTableMod(datapath, 1, 3)
flags = ofp.OFPTC_VACANCY_EVENTS
properties = [ofp_parser.OFPTableModPropEviction(flags)]
req = ofp_parser.OFPTableMod(datapath, 1, 3, properties)
datapath.send_msg(req)
"""
def __init__(self, datapath, table_id, config, properties):
super(OFPTableMod, self).__init__(datapath)
self.table_id = table_id
self.config = config
self.properties = properties
def _serialize_body(self):
props_buf = bytearray()
for p in self.properties:
props_buf += p.serialize()
msg_pack_into(ofproto.OFP_TABLE_MOD_PACK_STR, self.buf,
ofproto.OFP_HEADER_SIZE,
self.table_id, self.config)
self.buf += props_buf
@_register_parser
@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
class OFPMultipartReply(MsgBase):
_STATS_MSG_TYPES = {}
@staticmethod
def register_stats_type(body_single_struct=False):
def _register_stats_type(cls):
assert cls.cls_stats_type is not None
assert cls.cls_stats_type not in OFPMultipartReply._STATS_MSG_TYPES
assert cls.cls_stats_body_cls is not None
cls.cls_body_single_struct = body_single_struct
OFPMultipartReply._STATS_MSG_TYPES[cls.cls_stats_type] = cls
return cls
return _register_stats_type
def __init__(self, datapath, body=None, flags=None):
super(OFPMultipartReply, self).__init__(datapath)
self.body = body
self.flags = flags
@classmethod
def parser_stats_body(cls, buf, msg_len, offset):
body_cls = cls.cls_stats_body_cls
body = []
while offset < msg_len:
entry = body_cls.parser(buf, offset)
body.append(entry)
offset += entry.length
if cls.cls_body_single_struct:
return body[0]
return body
@classmethod
def parser_stats(cls, datapath, version, msg_type, msg_len, xid, buf):
msg = MsgBase.parser.__func__(
cls, datapath, version, msg_type, msg_len, xid, buf)
msg.body = msg.parser_stats_body(msg.buf, msg.msg_len,
ofproto.OFP_MULTIPART_REPLY_SIZE)
return msg
@classmethod
def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
type_, flags = struct.unpack_from(
ofproto.OFP_MULTIPART_REPLY_PACK_STR, six.binary_type(buf),
ofproto.OFP_HEADER_SIZE)
stats_type_cls = cls._STATS_MSG_TYPES.get(type_)
msg = super(OFPMultipartReply, stats_type_cls).parser(
datapath, version, msg_type, msg_len, xid, buf)
msg.type = type_
msg.flags = flags
offset = ofproto.OFP_MULTIPART_REPLY_SIZE
body = []
while offset < msg_len:
b = stats_type_cls.cls_stats_body_cls.parser(msg.buf, offset)
offset_step = b.length if hasattr(b, 'length') else b.len
if offset_step < 1:
raise exception.OFPMalformedMessage()
body.append(b)
offset += offset_step
if stats_type_cls.cls_body_single_struct:
msg.body = body[0]
else:
msg.body = body
return msg
class OFPDescStats(ofproto_parser.namedtuple('OFPDescStats', (
'mfr_desc', 'hw_desc', 'sw_desc', 'serial_num', 'dp_desc'))):
_TYPE = {
'ascii': [
'mfr_desc',
'hw_desc',
'sw_desc',
'serial_num',
'dp_desc',
]
}
@classmethod
def parser(cls, buf, offset):
desc = struct.unpack_from(ofproto.OFP_DESC_PACK_STR,
buf, offset)
desc = list(desc)
desc = [x.rstrip(b'\0') for x in desc]
stats = cls(*desc)
stats.length = ofproto.OFP_DESC_SIZE
return stats
@_set_stats_type(ofproto.OFPMP_DESC, OFPDescStats)
@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
class OFPDescStatsRequest(OFPMultipartRequest):
"""
Description statistics request message
The controller uses this message to query description of the switch.
================ ======================================================
Attribute Description
================ ======================================================
flags Zero or ``OFPMPF_REQ_MORE``
================ ======================================================
Example::
def send_desc_stats_request(self, datapath):
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPDescStatsRequest(datapath, 0)
datapath.send_msg(req)
"""
def __init__(self, datapath, flags=0, type_=None):
super(OFPDescStatsRequest, self).__init__(datapath, flags)
@OFPMultipartReply.register_stats_type(body_single_struct=True)
@_set_stats_type(ofproto.OFPMP_DESC, OFPDescStats)
@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
class OFPDescStatsReply(OFPMultipartReply):
"""
Description statistics reply message
The switch responds with this message to a description statistics
request.
================ ======================================================
Attribute Description
================ ======================================================
body Instance of ``OFPDescStats``
================ ======================================================
Example::
@set_ev_cls(ofp_event.EventOFPDescStatsReply, MAIN_DISPATCHER)
def desc_stats_reply_handler(self, ev):
body = ev.msg.body
self.logger.debug('DescStats: mfr_desc=%s hw_desc=%s sw_desc=%s '
'serial_num=%s dp_desc=%s',
body.mfr_desc, body.hw_desc, body.sw_desc,
body.serial_num, body.dp_desc)
"""
def __init__(self, datapath, type_=None, **kwargs):
super(OFPDescStatsReply, self).__init__(datapath, **kwargs)
class OFPTableFeaturesStats(StringifyMixin):
_TYPE = {
'utf-8': [
# OF spec is unclear about the encoding of name.
# we assumes UTF-8.
'name',
]
}
def __init__(self, table_id=None, command=None, features=None, name=None,
metadata_match=None, metadata_write=None, capabilities=None,
max_entries=None, properties=None, length=None):
super(OFPTableFeaturesStats, self).__init__()
self.length = length
self.table_id = table_id
self.command = command
self.features = features
self.name = name
self.metadata_match = metadata_match
self.metadata_write = metadata_write
self.capabilities = capabilities
self.max_entries = max_entries
self.properties = properties
@classmethod
def parser(cls, buf, offset):
tbl = cls()
(tbl.length, tbl.table_id, tbl.command, tbl.features,
name, tbl.metadata_match, tbl.metadata_write,
tbl.capabilities, tbl.max_entries
) = struct.unpack_from(ofproto.OFP_TABLE_FEATURES_PACK_STR,
buf, offset)
tbl.name = name.rstrip(b'\0')
props = []
rest = buf[offset + ofproto.OFP_TABLE_FEATURES_SIZE:
offset + tbl.length]
while rest:
p, rest = OFPTableFeatureProp.parse(rest)
props.append(p)
tbl.properties = props
return tbl
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.command, self.features,
self.name, self.metadata_match, self.metadata_write,
self.capabilities, self.max_entries)
return buf + bin_props
class OFPTableFeatureProp(OFPPropBase):
_TYPES = {}
class OFPInstructionId(StringifyMixin):
_PACK_STR = '!HH' # type, len
def __init__(self, type_, len_=None):
self.type = type_
self.len = len_
# XXX experimenter
@classmethod
def parse(cls, buf):
(type_, len_,) = struct.unpack_from(cls._PACK_STR, six.binary_type(buf), 0)
rest = buf[len_:]
return cls(type_=type_, len_=len_), rest
def serialize(self):
# fixup
self.len = struct.calcsize(self._PACK_STR)
buf = bytearray()
msg_pack_into(self._PACK_STR, buf, 0, self.type, self.len)
return buf
@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_INSTRUCTIONS)
@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_INSTRUCTIONS_MISS)
class OFPTableFeaturePropInstructions(OFPTableFeatureProp):
def __init__(self, type_=None, length=None, instruction_ids=None):
instruction_ids = instruction_ids if instruction_ids else []
super(OFPTableFeaturePropInstructions, self).__init__(type_, length)
self.instruction_ids = instruction_ids
@classmethod
def parser(cls, buf):
rest = cls.get_rest(buf)
ids = []
while rest:
i, rest = OFPInstructionId.parse(rest)
ids.append(i)
return cls(instruction_ids=ids)
def serialize_body(self):
bin_ids = bytearray()
for i in self.instruction_ids:
bin_ids += i.serialize()
return bin_ids
# Implementation note: While OpenFlow 1.3.2 shares the same ofp_action_header
# for flow_mod and table_features, we have separate classes. We named this
# class to match with OpenFlow 1.4's name. (ofp_action_id)
class OFPActionId(StringifyMixin):
_PACK_STR = '!HH' # type, len
def __init__(self, type_, len_=None):
self.type = type_
self.len = len_
# XXX experimenter
@classmethod
def parse(cls, buf):
(type_, len_,) = struct.unpack_from(cls._PACK_STR, six.binary_type(buf), 0)
rest = buf[len_:]
return cls(type_=type_, len_=len_), rest
def serialize(self):
# fixup
self.len = struct.calcsize(self._PACK_STR)
buf = bytearray()
msg_pack_into(self._PACK_STR, buf, 0, self.type, self.len)
return buf
@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_ACTIONS)
@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_ACTIONS_MISS)
@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_ACTIONS)
@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_ACTIONS_MISS)
class OFPTableFeaturePropActions(OFPTableFeatureProp):
def __init__(self, type_=None, length=None, action_ids=None):
action_ids = action_ids if action_ids else []
super(OFPTableFeaturePropActions, self).__init__(type_, length)
self.action_ids = action_ids
@classmethod
def parser(cls, buf):
rest = cls.get_rest(buf)
ids = []
while rest:
i, rest = OFPActionId.parse(rest)
ids.append(i)
return cls(action_ids=ids)
def serialize_body(self):
bin_ids = bytearray()
for i in self.action_ids:
bin_ids += i.serialize()
return bin_ids
@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_NEXT_TABLES)
@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_NEXT_TABLES_MISS)
@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_TABLE_SYNC_FROM)
class OFPTableFeaturePropNextTables(OFPTableFeatureProp):
_TABLE_ID_PACK_STR = '!B'
def __init__(self, type_=None, length=None, table_ids=None):
table_ids = table_ids if table_ids else []
super(OFPTableFeaturePropNextTables, self).__init__(type_, length)
self.table_ids = table_ids
@classmethod
def parser(cls, buf):
rest = cls.get_rest(buf)
ids = []
while rest:
(i,) = struct.unpack_from(cls._TABLE_ID_PACK_STR, six.binary_type(rest), 0)
rest = rest[struct.calcsize(cls._TABLE_ID_PACK_STR):]
ids.append(i)
return cls(table_ids=ids)
def serialize_body(self):
bin_ids = bytearray()
for i in self.table_ids:
bin_id = bytearray()
msg_pack_into(self._TABLE_ID_PACK_STR, bin_id, 0, i)
bin_ids += bin_id
return bin_ids
# Implementation note: OFPOxmId is specific to this implementation.
# It does not have a corresponding structure in the specification.
# (the specification uses plain uint32_t for non-experimenter OXMs
# and uint64_t for experimenter OXMs.)
#
# i have taken a look at some of software switch implementations
# but they all look broken or incomplete. according to the spec,
# oxm_hasmask should be 1 if a switch supports masking for the type.
# the right value for oxm_length is not clear from the spec.
# update: OpenFlow 1.3.3 "clarified" that oxm_length here is the payload
# length. it's still unclear if it should be doubled for hasmask or not,
# though.
# ofsoftswitch13
# oxm_hasmask always 0
# oxm_length same as ofp_match etc (as without mask)
# linc/of_protocol
# oxm_hasmask always 0
# oxm_length always 0
# ovs:
# seems in flux as of writing this [20141003]
# updtate: OVS checks the oxm_length strictly which contained in
# the OFPAT_COPY_FIELD action when using OpenFlow 1.5, so here composes the
# payload length as the oxm_length (if has mask, it will be doubled, still
# unclear though).
class OFPOxmId(StringifyMixin):
_PACK_STR = '!I' # oxm header
_EXPERIMENTER_ID_PACK_STR = '!I'
_TYPE = {
'ascii': [
'type',
],
}
def __init__(self, type_, hasmask=False, length=None):
self.type = type_
self.hasmask = hasmask
self.length = length
@classmethod
def parse(cls, buf):
(oxm,) = struct.unpack_from(cls._PACK_STR, six.binary_type(buf), 0)
# oxm (32 bit) == class (16) | field (7) | hasmask (1) | length (8)
# in case of experimenter OXMs, another 32 bit value
# (experimenter id) follows.
(type_, _v) = ofproto.oxm_to_user(oxm >> (1 + 8), None, None)
rest = buf[struct.calcsize(cls._PACK_STR):]
hasmask = ofproto.oxm_tlv_header_extract_hasmask(oxm)
length = oxm & 0xff # XXX see the comment on OFPOxmId
class_ = oxm >> (7 + 1 + 8)
if class_ == ofproto.OFPXMC_EXPERIMENTER:
(exp_id,) = struct.unpack_from(cls._EXPERIMENTER_ID_PACK_STR,
six.binary_type(rest), 0)
rest = rest[struct.calcsize(cls._EXPERIMENTER_ID_PACK_STR):]
subcls = OFPExperimenterOxmId
return subcls(type_=type_, exp_id=exp_id, hasmask=hasmask,
length=length), rest
else:
return cls(type_=type_, hasmask=hasmask, length=length), rest
def serialize(self):
n, t = ofproto.oxm_get_field_info_by_name(self.type)
if not self.length:
# XXX see the comment on OFPOxmId
self.length = t.size * 2 if self.hasmask else t.size
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)
@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_COPYFIELD)
@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_COPYFIELD_MISS)
@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_COPYFIELD)
@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_COPYFIELD_MISS)
class OFPTableFeaturePropOxm(OFPTableFeatureProp):
def __init__(self, type_=None, length=None, oxm_ids=None):
oxm_ids = oxm_ids if oxm_ids else []
super(OFPTableFeaturePropOxm, self).__init__(type_, length)
self.oxm_ids = oxm_ids
@classmethod
def parser(cls, buf):
rest = cls.get_rest(buf)
ids = []
while rest:
i, rest = OFPOxmId.parse(rest)
ids.append(i)
return cls(oxm_ids=ids)
def serialize_body(self):
bin_ids = bytearray()
for i in self.oxm_ids:
bin_ids += i.serialize()
return bin_ids
@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_PACKET_TYPES)
class OFPTableFeaturePropOxmValues(OFPTableFeatureProp):
def __init__(self, type_=None, length=None, _ordered_values=None,
**kwargs):
super(OFPTableFeaturePropOxmValues, self).__init__(type_, length)
if _ordered_values is not None:
assert not kwargs
self.oxm_values = _ordered_values
else:
kwargs = dict(ofproto.oxm_normalize_user(k, v) for
(k, v) in kwargs.items())
values = [ofproto.oxm_from_user(k, v) for (k, v)
in kwargs.items()]
# assumption: sorting by OXM type values makes fields
# meet ordering requirements (eg. eth_type before ipv4_src)
values.sort(
key=lambda x: x[0][0] if isinstance(x[0], tuple) else x[0])
self.oxm_values = [ofproto.oxm_to_user(n, v, m) for (n, v, m)
in values]
@classmethod
def parser(cls, buf):
rest = cls.get_rest(buf)
values = []
while rest:
n, value, mask, field_len = ofproto.oxm_parse(rest, 0)
k, uv = ofproto.oxm_to_user(n, value, mask)
values.append((k, uv))
rest = rest[field_len:]
return cls(_ordered_values=values)
def serialize_body(self):
values = [ofproto.oxm_from_user(k, uv) for (k, uv)
in self.oxm_values]
offset = 0
buf = bytearray()
for (n, value, mask) in values:
offset += ofproto.oxm_serialize(n, value, mask, buf, offset)
return buf
def __getitem__(self, key):
return dict(self.oxm_values)[key]
def __contains__(self, key):
return key in dict(self.oxm_values)
def iteritems(self):
return iter(dict(self.oxm_values).items())
def items(self):
return self.oxm_values
def get(self, key, default=None):
return dict(self.oxm_values).get(key, default)
def stringify_attrs(self):
yield "oxm_values", dict(self.oxm_values)
def to_jsondict(self):
"""
Returns a dict expressing the OXM values.
"""
body = {"oxm_values": [ofproto.oxm_to_jsondict(k, uv) for k, uv
in self.oxm_values],
"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 OXM value is defined in dict
"""
type_ = dict_['type']
values = [ofproto.oxm_from_jsondict(f) for f
in dict_['oxm_values']]
return cls(type_=type_, _ordered_values=values)
@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_EXPERIMENTER)
@OFPTableFeatureProp.register_type(ofproto.OFPTFPT_EXPERIMENTER_MISS)
class OFPTableFeaturePropExperimenter(OFPPropCommonExperimenter4ByteData):
pass
@_set_stats_type(ofproto.OFPMP_TABLE_FEATURES, OFPTableFeaturesStats)
@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
class OFPTableFeaturesStatsRequest(OFPMultipartRequest):
"""
Table features statistics request message
The controller uses this message to query table features.
================ ======================================================
Attribute Description
================ ======================================================
body List of ``OFPTableFeaturesStats`` instances.
The default is [].
================ ======================================================
"""
def __init__(self, datapath, flags=0, body=None, type_=None):
body = body if body else []
super(OFPTableFeaturesStatsRequest, self).__init__(datapath, flags)
self.body = body
def _serialize_stats_body(self):
bin_body = bytearray()
for p in self.body:
bin_body += p.serialize()
self.buf += bin_body
@OFPMultipartReply.register_stats_type()
@_set_stats_type(ofproto.OFPMP_TABLE_FEATURES, OFPTableFeaturesStats)
@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
class OFPTableFeaturesStatsReply(OFPMultipartReply):
"""
Table features statistics reply message
The switch responds with this message to a table features statistics
request.
================ ======================================================
Attribute Description
================ ======================================================
body List of ``OFPTableFeaturesStats`` instance
================ ======================================================
"""
def __init__(self, datapath, type_=None, **kwargs):
super(OFPTableFeaturesStatsReply, self).__init__(datapath, **kwargs)
@_set_stats_type(ofproto.OFPMP_PORT_DESC, OFPPort)
@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
class OFPPortDescStatsRequest(OFPMultipartRequest):
"""
Port description request message
The controller uses this message to query description of one or all the ports.
================ ======================================================
Attribute Description
================ ======================================================
flags Zero or ``OFPMPF_REQ_MORE``
port_no Port number to read (OFPP_ANY to all ports)
================ ======================================================
Example::
def send_port_desc_stats_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPPortDescStatsRequest(datapath, 0, ofp.OFPP_ANY)
datapath.send_msg(req)
"""
def __init__(self, datapath, flags=0, port_no=ofproto.OFPP_ANY, type_=None):
super(OFPPortDescStatsRequest, self).__init__(datapath, flags)
self.port_no = port_no
def _serialize_stats_body(self):
msg_pack_into(ofproto.OFP_PORT_MULTIPART_REQUEST_PACK_STR,
self.buf,
ofproto.OFP_MULTIPART_REQUEST_SIZE,
self.port_no)
@OFPMultipartReply.register_stats_type()
@_set_stats_type(ofproto.OFPMP_PORT_DESC, OFPPort)
@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
class OFPPortDescStatsReply(OFPMultipartReply):
"""
Port description reply message
The switch responds with this message to a port description request.
================ ======================================================
Attribute Description
================ ======================================================
body List of ``OFPPort`` instance
================ ======================================================
Example::
@set_ev_cls(ofp_event.EventOFPPortDescStatsReply, MAIN_DISPATCHER)
def port_desc_stats_reply_handler(self, ev):
ports = []
for p in ev.msg.body:
ports.append('port_no=%d hw_addr=%s name=%s config=0x%08x '
'state=0x%08x properties=%s' %
(p.port_no, p.hw_addr,
p.name, p.config, p.state, repr(p.properties)))
self.logger.debug('OFPPortDescStatsReply received: %s', ports)
"""
def __init__(self, datapath, type_=None, **kwargs):
super(OFPPortDescStatsReply, self).__init__(datapath, **kwargs)
@_set_stats_type(ofproto.OFPMP_TABLE_DESC, OFPTableDesc)
@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
class OFPTableDescStatsRequest(OFPMultipartRequest):
"""
Table description request message
The controller uses this message to query description of all the tables.
================ ======================================================
Attribute Description
================ ======================================================
flags Zero or ``OFPMPF_REQ_MORE``
================ ======================================================
Example::
def send_table_desc_stats_request(self, datapath):
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPTableDescStatsRequest(datapath, 0)
datapath.send_msg(req)
"""
def __init__(self, datapath, flags=0, type_=None):
super(OFPTableDescStatsRequest, self).__init__(datapath, flags)
@OFPMultipartReply.register_stats_type()
@_set_stats_type(ofproto.OFPMP_TABLE_DESC, OFPTableDesc)
@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
class OFPTableDescStatsReply(OFPMultipartReply):
"""
Table description reply message
The switch responds with this message to a table description request.
================ ======================================================
Attribute Description
================ ======================================================
body List of ``OFPTableDesc`` instance
================ ======================================================
Example::
@set_ev_cls(ofp_event.EventOFPTableDescStatsReply, MAIN_DISPATCHER)
def table_desc_stats_reply_handler(self, ev):
tables = []
for p in ev.msg.body:
tables.append('table_id=%d config=0x%08x properties=%s' %
(p.table_id, p.config, repr(p.properties)))
self.logger.debug('OFPTableDescStatsReply received: %s', tables)
"""
def __init__(self, datapath, type_=None, **kwargs):
super(OFPTableDescStatsReply, self).__init__(datapath, **kwargs)
@_set_stats_type(ofproto.OFPMP_QUEUE_DESC, OFPQueueDesc)
@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
class OFPQueueDescStatsRequest(OFPMultipartRequest):
"""
Queue description request message
The controller uses this message to query description of all the queues.
================ ======================================================
Attribute Description
================ ======================================================
flags Zero or ``OFPMPF_REQ_MORE``
port_no Port number to read (OFPP_ANY for all ports)
queue_id ID of queue to read (OFPQ_ALL for all queues)
================ ======================================================
Example::
def send_queue_desc_stats_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPQueueDescStatsRequest(datapath, 0,
ofp.OFPP_ANY,
ofp.OFPQ_ALL)
datapath.send_msg(req)
"""
def __init__(self, datapath, flags=0, port_no=ofproto.OFPP_ANY,
queue_id=ofproto.OFPQ_ALL, type_=None):
super(OFPQueueDescStatsRequest, self).__init__(datapath, flags)
self.port_no = port_no
self.queue_id = queue_id
def _serialize_stats_body(self):
msg_pack_into(ofproto.OFP_QUEUE_MULTIPART_REQUEST_PACK_STR,
self.buf,
ofproto.OFP_MULTIPART_REQUEST_SIZE,
self.port_no, self.queue_id)
@OFPMultipartReply.register_stats_type()
@_set_stats_type(ofproto.OFPMP_QUEUE_DESC, OFPQueueDesc)
@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
class OFPQueueDescStatsReply(OFPMultipartReply):
"""
Queue description reply message
The switch responds with this message to a queue description request.
================ ======================================================
Attribute Description
================ ======================================================
body List of ``OFPQueueDesc`` instance
================ ======================================================
Example::
@set_ev_cls(ofp_event.EventOFPQueueDescStatsReply, MAIN_DISPATCHER)
def queue_desc_stats_reply_handler(self, ev):
queues = []
for q in ev.msg.body:
queues.append('port_no=%d queue_id=0x%08x properties=%s' %
(q.port_no, q.queue_id, repr(q.properties)))
self.logger.debug('OFPQueueDescStatsReply received: %s', queues)
"""
def __init__(self, datapath, type_=None, **kwargs):
super(OFPQueueDescStatsReply, self).__init__(datapath, **kwargs)
class OFPQueueStatsProp(OFPPropBase):
_TYPES = {}
@OFPQueueStatsProp.register_type(ofproto.OFPQSPT_EXPERIMENTER)
class OFPQueueStatsPropExperimenter(OFPPropCommonExperimenter4ByteData):
pass
class OFPQueueStats(StringifyMixin):
def __init__(self, length=None, port_no=None, queue_id=None,
tx_bytes=None, tx_packets=None, tx_errors=None,
duration_sec=None, duration_nsec=None, properties=None):
super(OFPQueueStats, self).__init__()
self.length = length
self.port_no = port_no
self.queue_id = queue_id
self.tx_bytes = tx_bytes
self.tx_packets = tx_packets
self.tx_errors = tx_errors
self.duration_sec = duration_sec
self.duration_nsec = duration_nsec
self.properties = properties
@classmethod
def parser(cls, buf, offset):
(length, port_no, queue_id, tx_bytes, tx_packets, tx_errors,
duration_sec, duration_nsec) = struct.unpack_from(
ofproto.OFP_QUEUE_STATS_PACK_STR, buf, offset)
props = []
rest = buf[offset + ofproto.OFP_QUEUE_STATS_SIZE:offset + length]
while rest:
p, rest = OFPQueueStatsProp.parse(rest)
props.append(p)
stats = cls(length, port_no, queue_id, tx_bytes, tx_packets, tx_errors,
duration_sec, duration_nsec, props)
return stats
@_set_stats_type(ofproto.OFPMP_QUEUE_STATS, OFPQueueStats)
@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
class OFPQueueStatsRequest(OFPMultipartRequest):
"""
Queue statistics request message
The controller uses this message to query queue statictics.
================ ======================================================
Attribute Description
================ ======================================================
flags Zero or ``OFPMPF_REQ_MORE``
port_no Port number to read
queue_id ID of queue to read
================ ======================================================
Example::
def send_queue_stats_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPQueueStatsRequest(datapath, 0, ofp.OFPP_ANY,
ofp.OFPQ_ALL)
datapath.send_msg(req)
"""
def __init__(self, datapath, flags=0, port_no=ofproto.OFPP_ANY,
queue_id=ofproto.OFPQ_ALL, type_=None):
super(OFPQueueStatsRequest, self).__init__(datapath, flags)
self.port_no = port_no
self.queue_id = queue_id
def _serialize_stats_body(self):
msg_pack_into(ofproto.OFP_QUEUE_MULTIPART_REQUEST_PACK_STR,
self.buf,
ofproto.OFP_MULTIPART_REQUEST_SIZE,
self.port_no, self.queue_id)
@OFPMultipartReply.register_stats_type()
@_set_stats_type(ofproto.OFPMP_QUEUE_STATS, OFPQueueStats)
@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
class OFPQueueStatsReply(OFPMultipartReply):
"""
Queue statistics reply message
The switch responds with this message to an aggregate flow statistics
request.
================ ======================================================
Attribute Description
================ ======================================================
body List of ``OFPQueueStats`` instance
================ ======================================================
Example::
@set_ev_cls(ofp_event.EventOFPQueueStatsReply, MAIN_DISPATCHER)
def queue_stats_reply_handler(self, ev):
queues = []
for stat in ev.msg.body:
queues.append('port_no=%d queue_id=%d '
'tx_bytes=%d tx_packets=%d tx_errors=%d '
'duration_sec=%d duration_nsec=%d'
'properties=%s' %
(stat.port_no, stat.queue_id,
stat.tx_bytes, stat.tx_packets, stat.tx_errors,
stat.duration_sec, stat.duration_nsec,
repr(stat.properties)))
self.logger.debug('QueueStats: %s', queues)
"""
def __init__(self, datapath, type_=None, **kwargs):
super(OFPQueueStatsReply, self).__init__(datapath, **kwargs)
class OFPBucketCounter(StringifyMixin):
def __init__(self, packet_count, byte_count):
super(OFPBucketCounter, self).__init__()
self.packet_count = packet_count
self.byte_count = byte_count
@classmethod
def parser(cls, buf, offset):
packet_count, byte_count = struct.unpack_from(
ofproto.OFP_BUCKET_COUNTER_PACK_STR, buf, offset)
return cls(packet_count, byte_count)
class OFPGroupStats(StringifyMixin):
def __init__(self, length=None, group_id=None, ref_count=None,
packet_count=None, byte_count=None, duration_sec=None,
duration_nsec=None, bucket_stats=None):
super(OFPGroupStats, self).__init__()
self.length = length
self.group_id = group_id
self.ref_count = ref_count
self.packet_count = packet_count
self.byte_count = byte_count
self.duration_sec = duration_sec
self.duration_nsec = duration_nsec
self.bucket_stats = bucket_stats
@classmethod
def parser(cls, buf, offset):
group = struct.unpack_from(ofproto.OFP_GROUP_STATS_PACK_STR,
buf, offset)
group_stats = cls(*group)
group_stats.bucket_stats = []
total_len = group_stats.length + offset
offset += ofproto.OFP_GROUP_STATS_SIZE
while total_len > offset:
b = OFPBucketCounter.parser(buf, offset)
group_stats.bucket_stats.append(b)
offset += ofproto.OFP_BUCKET_COUNTER_SIZE
return group_stats
@_set_stats_type(ofproto.OFPMP_GROUP_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_MULTIPART_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, properties=None,
length=None, bucket_array_len=None):
buckets = buckets if buckets else []
properties = properties if properties else []
super(OFPGroupDescStats, self).__init__()
self.length = length
self.type = type_
self.group_id = group_id
self.buckets = buckets
self.properties = properties
@classmethod
def parser(cls, buf, offset):
stats = cls()
(stats.length, stats.type, stats.group_id,
stats.bucket_array_len) = struct.unpack_from(
ofproto.OFP_GROUP_DESC_STATS_PACK_STR, buf, offset)
offset += ofproto.OFP_GROUP_DESC_STATS_SIZE
bucket_buf = buf[offset:offset + stats.bucket_array_len]
stats.buckets = []
while bucket_buf:
bucket = OFPBucket.parser(bucket_buf, 0)
stats.buckets.append(bucket)
bucket_buf = bucket_buf[bucket.len:]
offset += stats.bucket_array_len
rest = buf[offset:offset + stats.length]
while rest:
p, rest = OFPGroupProp.parse(rest)
stats.properties.append(p)
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``
group_id ID of group to read (OFPG_ALL to all groups)
================ ======================================================
Example::
def send_group_desc_stats_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPGroupDescStatsRequest(datapath, 0, ofp.OFPG_ALL)
datapath.send_msg(req)
"""
def __init__(self, datapath, flags=0, group_id=ofproto.OFPG_ALL,
type_=None):
super(OFPGroupDescStatsRequest, self).__init__(datapath, flags)
self.group_id = group_id
def _serialize_stats_body(self):
msg_pack_into(ofproto.OFP_GROUP_MULTIPART_REQUEST_PACK_STR,
self.buf,
ofproto.OFP_MULTIPART_REQUEST_SIZE,
self.group_id)
@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 properties=%s' %
(stat.length, stat.type, stat.group_id,
stat.bucket, repr(stat.properties)))
self.logger.debug('GroupDescStats: %s', descs)
"""
def __init__(self, datapath, type_=None, **kwargs):
super(OFPGroupDescStatsReply, self).__init__(datapath, **kwargs)
class OFPGroupFeaturesStats(ofproto_parser.namedtuple('OFPGroupFeaturesStats',
('types', 'capabilities', 'max_groups',
'actions'))):
@classmethod
def parser(cls, buf, offset):
group_features = struct.unpack_from(
ofproto.OFP_GROUP_FEATURES_PACK_STR, buf, offset)
types = group_features[0]
capabilities = group_features[1]
max_groups = list(group_features[2:6])
actions = list(group_features[6:10])
stats = cls(types, capabilities, max_groups, actions)
stats.length = ofproto.OFP_GROUP_FEATURES_SIZE
return stats
@_set_stats_type(ofproto.OFPMP_GROUP_FEATURES, OFPGroupFeaturesStats)
@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
class OFPGroupFeaturesStatsRequest(OFPMultipartRequest):
"""
Group features request message
The controller uses this message to list the capabilities of groups on
a switch.
================ ======================================================
Attribute Description
================ ======================================================
flags Zero or ``OFPMPF_REQ_MORE``
================ ======================================================
Example::
def send_group_features_stats_request(self, datapath):
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPGroupFeaturesStatsRequest(datapath, 0)
datapath.send_msg(req)
"""
def __init__(self, datapath, flags=0, type_=None):
super(OFPGroupFeaturesStatsRequest, self).__init__(datapath, flags)
@OFPMultipartReply.register_stats_type(body_single_struct=True)
@_set_stats_type(ofproto.OFPMP_GROUP_FEATURES, OFPGroupFeaturesStats)
@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
class OFPGroupFeaturesStatsReply(OFPMultipartReply):
"""
Group features reply message
The switch responds with this message to a group features request.
================ ======================================================
Attribute Description
================ ======================================================
body Instance of ``OFPGroupFeaturesStats``
================ ======================================================
Example::
@set_ev_cls(ofp_event.EventOFPGroupFeaturesStatsReply, MAIN_DISPATCHER)
def group_features_stats_reply_handler(self, ev):
body = ev.msg.body
self.logger.debug('GroupFeaturesStats: types=%d '
'capabilities=0x%08x max_groups=%s '
'actions=%s',
body.types, body.capabilities,
body.max_groups, body.actions)
"""
def __init__(self, datapath, type_=None, **kwargs):
super(OFPGroupFeaturesStatsReply, self).__init__(datapath, **kwargs)
class OFPMeterBandStats(StringifyMixin):
def __init__(self, packet_band_count, byte_band_count):
super(OFPMeterBandStats, self).__init__()
self.packet_band_count = packet_band_count
self.byte_band_count = byte_band_count
@classmethod
def parser(cls, buf, offset):
band_stats = struct.unpack_from(
ofproto.OFP_METER_BAND_STATS_PACK_STR, buf, offset)
return cls(*band_stats)
class OFPMeterStats(StringifyMixin):
def __init__(self, meter_id=None, ref_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.ref_count = ref_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.ref_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 ref_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.ref_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 OFPMeterDescStats(StringifyMixin):
def __init__(self, flags=None, meter_id=None, bands=None, length=None):
super(OFPMeterDescStats, 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_DESC_PACK_STR, buf, offset)
offset += ofproto.OFP_METER_DESC_SIZE
meter_config.bands = []
length = ofproto.OFP_METER_DESC_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, OFPMeterDescStats)
@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
class OFPMeterDescStatsRequest(OFPMultipartRequest):
"""
Meter description 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_desc_stats_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPMeterDescStatsRequest(datapath, 0,
ofp.OFPM_ALL)
datapath.send_msg(req)
"""
def __init__(self, datapath, flags=0, meter_id=ofproto.OFPM_ALL,
type_=None):
super(OFPMeterDescStatsRequest, 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, OFPMeterDescStats)
@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
class OFPMeterDescStatsReply(OFPMultipartReply):
"""
Meter description statistics reply message
The switch responds with this message to a meter description
statistics request.
================ ======================================================
Attribute Description
================ ======================================================
body List of ``OFPMeterDescStats`` instance
================ ======================================================
Example::
@set_ev_cls(ofp_event.EventOFPMeterDescStatsReply, MAIN_DISPATCHER)
def meter_desc_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('MeterDescStats: %s', configs)
"""
def __init__(self, datapath, type_=None, **kwargs):
super(OFPMeterDescStatsReply, self).__init__(datapath, **kwargs)
class OFPMeterFeaturesStats(ofproto_parser.namedtuple('OFPMeterFeaturesStats',
('max_meter', 'band_types', 'capabilities',
'max_bands', 'max_color', 'features'))):
@classmethod
def parser(cls, buf, offset):
meter_features = struct.unpack_from(
ofproto.OFP_METER_FEATURES_PACK_STR, buf, offset)
stats = cls(*meter_features)
stats.length = ofproto.OFP_METER_FEATURES_SIZE
return stats
@_set_stats_type(ofproto.OFPMP_METER_FEATURES, OFPMeterFeaturesStats)
@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
class OFPMeterFeaturesStatsRequest(OFPMultipartRequest):
"""
Meter features statistics request message
The controller uses this message to query the set of features of the
metering subsystem.
================ ======================================================
Attribute Description
================ ======================================================
flags Zero or ``OFPMPF_REQ_MORE``
================ ======================================================
Example::
def send_meter_features_stats_request(self, datapath):
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPMeterFeaturesStatsRequest(datapath, 0)
datapath.send_msg(req)
"""
def __init__(self, datapath, flags=0, type_=None):
super(OFPMeterFeaturesStatsRequest, self).__init__(datapath, flags)
@OFPMultipartReply.register_stats_type()
@_set_stats_type(ofproto.OFPMP_METER_FEATURES, OFPMeterFeaturesStats)
@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
class OFPMeterFeaturesStatsReply(OFPMultipartReply):
"""
Meter features statistics reply message
The switch responds with this message to a meter features statistics
request.
================ ======================================================
Attribute Description
================ ======================================================
body List of ``OFPMeterFeaturesStats`` instance
================ ======================================================
Example::
@set_ev_cls(ofp_event.EventOFPMeterFeaturesStatsReply, MAIN_DISPATCHER)
def meter_features_stats_reply_handler(self, ev):
features = []
for stat in ev.msg.body:
features.append('max_meter=%d band_types=0x%08x '
'capabilities=0x%08x max_bands=%d '
'max_color=%d' %
(stat.max_meter, stat.band_types,
stat.capabilities, stat.max_bands,
stat.max_color))
self.logger.debug('MeterFeaturesStats: %s', features)
"""
def __init__(self, datapath, type_=None, **kwargs):
super(OFPMeterFeaturesStatsReply, self).__init__(datapath, **kwargs)
class OFPFlowUpdate(StringifyMixin):
def __init__(self, length, event):
super(OFPFlowUpdate, self).__init__()
self.length = length
self.event = event
class OFPFlowUpdateHeader(OFPFlowUpdate):
_EVENT = {}
@staticmethod
def register_flow_update_event(event, length):
def _register_flow_update_event(cls):
OFPFlowUpdateHeader._EVENT[event] = cls
cls.cls_flow_update_event = event
cls.cls_flow_update_length = length
return cls
return _register_flow_update_event
def __init__(self, length=None, event=None):
cls = self.__class__
super(OFPFlowUpdateHeader, self).__init__(length,
cls.cls_flow_update_event)
self.length = length
@classmethod
def parser(cls, buf, offset):
length, event = struct.unpack_from(
ofproto.OFP_FLOW_UPDATE_HEADER_PACK_STR, buf, offset)
cls_ = cls._EVENT[event]
return cls_.parser(buf, offset)
@OFPFlowUpdateHeader.register_flow_update_event(
ofproto.OFPFME_INITIAL, ofproto.OFP_FLOW_UPDATE_FULL_SIZE)
@OFPFlowUpdateHeader.register_flow_update_event(
ofproto.OFPFME_ADDED, ofproto.OFP_FLOW_UPDATE_FULL_SIZE)
@OFPFlowUpdateHeader.register_flow_update_event(
ofproto.OFPFME_REMOVED, ofproto.OFP_FLOW_UPDATE_FULL_SIZE)
@OFPFlowUpdateHeader.register_flow_update_event(
ofproto.OFPFME_MODIFIED, ofproto.OFP_FLOW_UPDATE_FULL_SIZE)
class OFPFlowUpdateFull(OFPFlowUpdateHeader):
def __init__(self, length=None, event=None, table_id=None, reason=None,
idle_timeout=None, hard_timeout=None, priority=None,
cookie=None, match=None, instructions=None):
instructions = instructions if instructions else []
super(OFPFlowUpdateFull, self).__init__(length, event)
self.table_id = table_id
self.reason = reason
self.idle_timeout = idle_timeout
self.hard_timeout = hard_timeout
self.priority = priority
self.cookie = cookie
self.match = match
assert (event != ofproto.OFPFME_REMOVED or len(instructions) == 0)
for i in instructions:
assert isinstance(i, OFPInstruction)
self.instructions = instructions
@classmethod
def parser(cls, buf, offset):
(length, event, table_id, reason, idle_timeout, hard_timeout, priority,
cookie) = struct.unpack_from(ofproto.OFP_FLOW_UPDATE_FULL_0_PACK_STR,
buf, offset)
offset += ofproto.OFP_FLOW_UPDATE_FULL_0_SIZE
assert cls.cls_flow_update_length <= length
assert cls.cls_flow_update_event == event
match = OFPMatch.parser(buf, offset)
match_length = utils.round_up(match.length, 8)
offset += match_length
inst_length = (length - ofproto.OFP_FLOW_UPDATE_FULL_0_SIZE -
match_length)
instructions = []
while inst_length > 0:
inst = OFPInstruction.parser(buf, offset)
instructions.append(inst)
offset += inst.len
inst_length -= inst.len
return cls(length, event, table_id, reason, idle_timeout,
hard_timeout, priority, cookie, match, instructions)
@OFPFlowUpdateHeader.register_flow_update_event(
ofproto.OFPFME_ABBREV, ofproto.OFP_FLOW_UPDATE_ABBREV_SIZE)
class OFPFlowUpdateAbbrev(OFPFlowUpdateHeader):
def __init__(self, length=None, event=None, xid=None):
super(OFPFlowUpdateAbbrev, self).__init__(length, event)
self.xid = xid
@classmethod
def parser(cls, buf, offset):
length, event, xid = struct.unpack_from(
ofproto.OFP_FLOW_UPDATE_ABBREV_PACK_STR, buf, offset)
assert cls.cls_flow_update_length == length
assert cls.cls_flow_update_event == event
return cls(length, event, xid)
@OFPFlowUpdateHeader.register_flow_update_event(
ofproto.OFPFME_PAUSED, ofproto.OFP_FLOW_UPDATE_PAUSED_SIZE)
@OFPFlowUpdateHeader.register_flow_update_event(
ofproto.OFPFME_RESUMED, ofproto.OFP_FLOW_UPDATE_PAUSED_SIZE)
class OFPFlowUpdatePaused(OFPFlowUpdateHeader):
@classmethod
def parser(cls, buf, offset):
length, event = struct.unpack_from(
ofproto.OFP_FLOW_UPDATE_PAUSED_PACK_STR, buf, offset)
assert cls.cls_flow_update_length == length
assert cls.cls_flow_update_event == event
return cls(length, event)
class OFPFlowMonitorRequestBase(OFPMultipartRequest):
def __init__(self, datapath, flags, monitor_id, out_port, out_group,
monitor_flags, table_id, command, match):
super(OFPFlowMonitorRequestBase, self).__init__(datapath, flags)
self.monitor_id = monitor_id
self.out_port = out_port
self.out_group = out_group
self.monitor_flags = monitor_flags
self.table_id = table_id
self.command = command
self.match = match
def _serialize_stats_body(self):
offset = ofproto.OFP_MULTIPART_REQUEST_SIZE
msg_pack_into(ofproto.OFP_FLOW_MONITOR_REQUEST_0_PACK_STR, self.buf,
offset, self.monitor_id, self.out_port, self.out_group,
self.monitor_flags, self.table_id, self.command)
offset += ofproto.OFP_FLOW_MONITOR_REQUEST_0_SIZE
self.match.serialize(self.buf, offset)
@_set_stats_type(ofproto.OFPMP_FLOW_MONITOR, OFPFlowUpdateHeader)
@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
class OFPFlowMonitorRequest(OFPFlowMonitorRequestBase):
"""
Flow monitor request message
The controller uses this message to query flow monitors.
================ ======================================================
Attribute Description
================ ======================================================
flags Zero or ``OFPMPF_REQ_MORE``
monitor_id Controller-assigned ID for this monitor
out_port Require matching entries to include this as an output
port
out_group Require matching entries to include this as an output
group
monitor_flags Bitmap of the following flags.
| OFPFMF_INITIAL
| OFPFMF_ADD
| OFPFMF_REMOVED
| OFPFMF_MODIFY
| OFPFMF_INSTRUCTIONS
| OFPFMF_NO_ABBREV
| OFPFMF_ONLY_OWN
table_id ID of table to monitor
command One of the following values.
| OFPFMC_ADD
| OFPFMC_MODIFY
| OFPFMC_DELETE
match Instance of ``OFPMatch``
================ ======================================================
Example::
def send_flow_monitor_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
monitor_flags = [ofp.OFPFMF_INITIAL, ofp.OFPFMF_ONLY_OWN]
match = ofp_parser.OFPMatch(in_port=1)
req = ofp_parser.OFPFlowMonitorRequest(datapath, 0, 10000,
ofp.OFPP_ANY, ofp.OFPG_ANY,
monitor_flags,
ofp.OFPTT_ALL,
ofp.OFPFMC_ADD, match)
datapath.send_msg(req)
"""
def __init__(self, datapath, flags=0, monitor_id=0,
out_port=ofproto.OFPP_ANY, out_group=ofproto.OFPG_ANY,
monitor_flags=0, table_id=ofproto.OFPTT_ALL,
command=ofproto.OFPFMC_ADD, match=None, type_=None):
if match is None:
match = OFPMatch()
super(OFPFlowMonitorRequest, self).__init__(datapath, flags,
monitor_id, out_port,
out_group, monitor_flags,
table_id, command, match)
@OFPMultipartReply.register_stats_type()
@_set_stats_type(ofproto.OFPMP_FLOW_MONITOR, OFPFlowUpdateHeader)
@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
class OFPFlowMonitorReply(OFPMultipartReply):
"""
Flow monitor reply message
The switch responds with this message to a flow monitor request.
================ ======================================================
Attribute Description
================ ======================================================
body List of list of the following class instance.
| OFPFlowMonitorFull
| OFPFlowMonitorAbbrev
| OFPFlowMonitorPaused
================ ======================================================
Example::
@set_ev_cls(ofp_event.EventOFPFlowMonitorReply, MAIN_DISPATCHER)
def flow_monitor_reply_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
flow_updates = []
for update in msg.body:
update_str = 'length=%d event=%d' %
(update.length, update.event)
if (update.event == ofp.OFPFME_INITIAL or
update.event == ofp.OFPFME_ADDED or
update.event == ofp.OFPFME_REMOVED or
update.event == ofp.OFPFME_MODIFIED):
update_str += 'table_id=%d reason=%d idle_timeout=%d '
'hard_timeout=%d priority=%d cookie=%d '
'match=%d instructions=%s' %
(update.table_id, update.reason,
update.idle_timeout, update.hard_timeout,
update.priority, update.cookie,
update.match, update.instructions)
elif update.event == ofp.OFPFME_ABBREV:
update_str += 'xid=%d' % (update.xid)
flow_updates.append(update_str)
self.logger.debug('FlowUpdates: %s', flow_updates)
"""
def __init__(self, datapath, type_=None, **kwargs):
super(OFPFlowMonitorReply, self).__init__(datapath, **kwargs)
class OFPBundleFeaturesProp(OFPPropBase):
_TYPES = {}
@OFPBundleFeaturesProp.register_type(ofproto.OFPTMPBF_TIME_CAPABILITY)
class OFPBundleFeaturesPropTime(OFPBundleFeaturesProp):
def __init__(self, type_=None, length=None, sched_accuracy=None,
sched_max_future=None, sched_max_past=None, timestamp=None):
super(OFPBundleFeaturesPropTime, self).__init__(type_, length)
self.sched_accuracy = sched_accuracy
self.sched_max_future = sched_max_future
self.sched_max_past = sched_max_past
self.timestamp = timestamp
@classmethod
def parser(cls, buf):
prop = cls()
(prop.type, prop.length) = struct.unpack_from(
ofproto.OFP_BUNDLE_FEATURES_PROP_TIME_0_PACK_STR, buf)
offset = ofproto.OFP_BUNDLE_FEATURES_PROP_TIME_0_SIZE
for f in ['sched_accuracy', 'sched_max_future', 'sched_max_past',
'timestamp']:
t = OFPTime.parser(buf, offset)
setattr(prop, f, t)
offset += ofproto.OFP_TIME_SIZE
return prop
def serialize(self):
# fixup
self.length = ofproto.OFP_BUNDLE_FEATURES_PROP_TIME_SIZE
buf = bytearray()
msg_pack_into(ofproto.OFP_BUNDLE_FEATURES_PROP_TIME_0_PACK_STR, buf, 0,
self.type, self.length)
offset = ofproto.OFP_BUNDLE_FEATURES_PROP_TIME_0_SIZE
for f in [self.sched_accuracy, self.sched_max_future,
self.sched_max_past, self.timestamp]:
f.serialize(buf, offset)
offset += ofproto.OFP_TIME_SIZE
return buf
@OFPBundleFeaturesProp.register_type(ofproto.OFPTMPBF_EXPERIMENTER)
class OFPBundleFeaturesPropExperimenter(OFPPropCommonExperimenter4ByteData):
pass
class OFPBundleFeaturesStats(ofproto_parser.namedtuple(
'OFPBundleFeaturesStats', ('capabilities', 'properties'))):
@classmethod
def parser(cls, buf, offset):
(capabilities, ) = struct.unpack_from(
ofproto.OFP_BUNDLE_FEATURES_PACK_STR, buf, offset)
properties = []
length = ofproto.OFP_BUNDLE_FEATURES_SIZE
rest = buf[offset + length:]
while rest:
p, rest = OFPBundleFeaturesProp.parse(rest)
properties.append(p)
length += p.length
bndl = cls(capabilities, properties)
# Note: length field is not defined in the specification and
# is specific to this implementation.
bndl.length = length
return bndl
@_set_stats_type(ofproto.OFPMP_BUNDLE_FEATURES, OFPBundleFeaturesStats)
@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
class OFPBundleFeaturesStatsRequest(OFPMultipartRequest):
"""
Bundle features request message
The controller uses this message to query a switch about its bundle
capabilities, including whether it supports atomic bundles, ordered
bundles, and scheduled bundles.
====================== ====================================================
Attribute Description
====================== ====================================================
flags Zero or ``OFPMPF_REQ_MORE``
feature_request_flags Bitmap of the following flags.
| OFPBF_TIMESTAMP
| OFPBF_TIME_SET_SCHED
properties List of ``OFPBundleFeaturesProp`` subclass instance
====================== ====================================================
Example::
def send_bundle_features_stats_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPBundleFeaturesStatsRequest(datapath, 0)
datapath.send_msg(req)
"""
def __init__(self, datapath, flags=0, feature_request_flags=0,
properties=None, type_=None):
properties = properties if properties else []
super(OFPBundleFeaturesStatsRequest, self).__init__(datapath, flags)
self.feature_request_flags = feature_request_flags
self.properties = properties
def _serialize_stats_body(self):
bin_props = bytearray()
for p in self.properties:
bin_props += p.serialize()
msg_pack_into(ofproto.OFP_BUNDLE_FEATURES_REQUEST_PACK_STR,
self.buf, ofproto.OFP_MULTIPART_REQUEST_SIZE,
self.feature_request_flags)
self.buf += bin_props
@OFPMultipartReply.register_stats_type(body_single_struct=True)
@_set_stats_type(ofproto.OFPMP_BUNDLE_FEATURES, OFPBundleFeaturesStats)
@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
class OFPBundleFeaturesStatsReply(OFPMultipartReply):
"""
Bundle features reply message
The switch responds with this message to a bundle features request.
================ ======================================================
Attribute Description
================ ======================================================
body Instance of ``OFPBundleFeaturesStats``
================ ======================================================
Example::
@set_ev_cls(ofp_event.EventOFPBundleFeaturesStatsReply, MAIN_DISPATCHER)
def bundle_features_stats_reply_handler(self, ev):
body = ev.msg.body
self.logger.debug('OFPBundleFeaturesStats: capabilities=%0x%08x '
'properties=%s',
body.capabilities, repr(body.properties))
"""
def __init__(self, datapath, type_=None, **kwargs):
super(OFPBundleFeaturesStatsReply, 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 OFPFlowDesc(StringifyMixin):
def __init__(self, table_id=None, priority=None,
idle_timeout=None, hard_timeout=None, flags=None,
importance=None, cookie=None, match=None, stats=None,
instructions=None, length=None):
super(OFPFlowDesc, self).__init__()
self.length = length
self.table_id = table_id
self.priority = priority
self.idle_timeout = idle_timeout
self.hard_timeout = hard_timeout
self.flags = flags
self.importance = importance
self.cookie = cookie
self.match = match
self.stats = stats
self.instructions = instructions
@classmethod
def parser(cls, buf, offset):
flow_desc = cls()
(flow_desc.length, flow_desc.table_id,
flow_desc.priority, flow_desc.idle_timeout,
flow_desc.hard_timeout, flow_desc.flags,
flow_desc.importance,
flow_desc.cookie) = struct.unpack_from(
ofproto.OFP_FLOW_DESC_0_PACK_STR, buf, offset)
offset += ofproto.OFP_FLOW_DESC_0_SIZE
flow_desc.match = OFPMatch.parser(buf, offset)
match_length = utils.round_up(flow_desc.match.length, 8)
offset += match_length
flow_desc.stats = OFPStats.parser(buf, offset)
stats_length = utils.round_up(flow_desc.stats.length, 8)
offset += stats_length
instructions = []
inst_length = (flow_desc.length - (ofproto.OFP_FLOW_DESC_0_SIZE +
match_length + stats_length))
while inst_length > 0:
inst = OFPInstruction.parser(buf, offset)
instructions.append(inst)
offset += inst.len
inst_length -= inst.len
flow_desc.instructions = instructions
return flow_desc
class OFPFlowStats(StringifyMixin):
def __init__(self, table_id=None, reason=None, priority=None,
match=None, stats=None, length=None):
super(OFPFlowStats, self).__init__()
self.table_id = table_id
self.reason = reason
self.priority = priority
self.match = match
self.stats = stats
self.length = length
@classmethod
def parser(cls, buf, offset):
flow_stats = cls()
(flow_stats.length, flow_stats.table_id, flow_stats.reason,
flow_stats.priority) = 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)
offset += match_length
stats_length = (flow_stats.length - (ofproto.OFP_FLOW_STATS_0_SIZE +
match_length))
if stats_length > 0:
flow_stats.stats = OFPStats.parser(buf, offset)
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_DESC, OFPFlowDesc)
@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
class OFPFlowDescStatsRequest(OFPFlowStatsRequestBase):
"""
Individual flow descriptions request message
The controller uses this message to query individual flow descriptions.
================ ======================================================
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_desc_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.OFPFlowDescStatsRequest(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(OFPFlowDescStatsRequest, self).__init__(
datapath, flags, table_id, out_port, out_group, cookie,
cookie_mask, match)
@OFPMultipartReply.register_stats_type()
@_set_stats_type(ofproto.OFPMP_FLOW_DESC, OFPFlowDesc)
@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
class OFPFlowDescStatsReply(OFPMultipartReply):
"""
Individual flow descriptions reply message
The switch responds with this message to an individual flow descriptions
request.
================ ======================================================
Attribute Description
================ ======================================================
body List of ``OFPFlowDesc`` instance
================ ======================================================
Example::
@set_ev_cls(ofp_event.EventOFPFlowDescStatsReply, MAIN_DISPATCHER)
def flow_desc_reply_handler(self, ev):
flows = []
for stat in ev.msg.body:
flows.append('table_id=%s priority=%d '
'idle_timeout=%d hard_timeout=%d flags=0x%04x '
'importance=%d cookie=%d match=%s '
'stats=%s instructions=%s' %
(stat.table_id, stat.priority,
stat.idle_timeout, stat.hard_timeout,
stat.flags, stat.importance,
stat.cookie, stat.match,
stat.stats, stat.instructions))
self.logger.debug('FlowDesc: %s', flows)
"""
def __init__(self, datapath, type_=None, **kwargs):
super(OFPFlowDescStatsReply, self).__init__(datapath, **kwargs)
@_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 reason=%d priority=%d '
'match=%s stats=%s' %
(stat.table_id, stat.reason, stat.priority,
stat.match, stat.stats))
self.logger.debug('FlowStats: %s', flows)
"""
def __init__(self, datapath, type_=None, **kwargs):
super(OFPFlowStatsReply, self).__init__(datapath, **kwargs)
class OFPAggregateStats(StringifyMixin):
def __init__(self, stats=None, length=None):
super(OFPAggregateStats, self).__init__()
self.stats = stats
# Note: length field is specific to this implementation.
# It does not have a corresponding field in the specification.
self.length = length
@classmethod
def parser(cls, buf, offset):
stats = OFPStats.parser(buf, offset)
agg = cls(stats)
agg.length = utils.round_up(stats.length, 8)
return agg
@_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: stats=%s', body.stats)
"""
def __init__(self, datapath, type_=None, **kwargs):
super(OFPAggregateStatsReply, self).__init__(datapath, **kwargs)
class OFPTableStats(ofproto_parser.namedtuple('OFPTableStats', (
'table_id', 'active_count', 'lookup_count',
'matched_count'))):
@classmethod
def parser(cls, buf, offset):
tbl = struct.unpack_from(ofproto.OFP_TABLE_STATS_PACK_STR,
buf, offset)
stats = cls(*tbl)
stats.length = ofproto.OFP_TABLE_STATS_SIZE
return stats
@_set_stats_type(ofproto.OFPMP_TABLE_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_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(OFPPortStatsProp):
def __init__(self, type_=None, length=None, rx_frame_err=None,
rx_over_err=None, rx_crc_err=None, collisions=None):
self.type = type_
self.length = length
self.rx_frame_err = rx_frame_err
self.rx_over_err = rx_over_err
self.rx_crc_err = rx_crc_err
self.collisions = collisions
@classmethod
def parser(cls, buf):
ether = cls()
(ether.type, ether.length, ether.rx_frame_err, ether.rx_over_err,
ether.rx_crc_err, ether.collisions) = struct.unpack_from(
ofproto.OFP_PORT_STATS_PROP_ETHERNET_PACK_STR, buf, 0)
return ether
@OFPPortStatsProp.register_type(ofproto.OFPPSPT_OPTICAL)
class OFPPortStatsPropOptical(OFPPortStatsProp):
def __init__(self, type_=None, length=None, flags=None,
tx_freq_lmda=None, tx_offset=None, tx_grid_span=None,
rx_freq_lmda=None, rx_offset=None, rx_grid_span=None,
tx_pwr=None, rx_pwr=None, bias_current=None,
temperature=None):
self.type = type_
self.length = length
self.flags = flags
self.tx_freq_lmda = tx_freq_lmda
self.tx_offset = tx_offset
self.tx_grid_span = tx_grid_span
self.rx_freq_lmda = rx_freq_lmda
self.rx_offset = rx_offset
self.rx_grid_span = rx_grid_span
self.tx_pwr = tx_pwr
self.rx_pwr = rx_pwr
self.bias_current = bias_current
self.temperature = temperature
@classmethod
def parser(cls, buf):
optical = cls()
(optical.type, optical.length, optical.flags,
optical.tx_freq_lmda, optical.tx_offset, optical.tx_grid_span,
optical.rx_freq_lmda, optical.rx_offset, optical.rx_grid_span,
optical.tx_pwr, optical.rx_pwr, optical.bias_current,
optical.temperature) = struct.unpack_from(
ofproto.OFP_PORT_STATS_PROP_OPTICAL_PACK_STR, buf, 0)
return optical
@OFPPortStatsProp.register_type(ofproto.OFPPSPT_EXPERIMENTER)
class OFPPortStatsPropExperimenter(OFPPropCommonExperimenter4ByteData):
pass
class OFPPortStats(StringifyMixin):
def __init__(self, length=None, port_no=None, duration_sec=None,
duration_nsec=None, rx_packets=None, tx_packets=None,
rx_bytes=None, tx_bytes=None, rx_dropped=None,
tx_dropped=None, rx_errors=None, tx_errors=None,
properties=None):
super(OFPPortStats, self).__init__()
self.length = length
self.port_no = port_no
self.duration_sec = duration_sec
self.duration_nsec = duration_nsec
self.rx_packets = rx_packets
self.tx_packets = tx_packets
self.rx_bytes = rx_bytes
self.tx_bytes = tx_bytes
self.rx_dropped = rx_dropped
self.tx_dropped = tx_dropped
self.rx_errors = rx_errors
self.tx_errors = tx_errors
self.properties = properties
@classmethod
def parser(cls, buf, offset):
(length, port_no, duration_sec, duration_nsec, rx_packets,
tx_packets, rx_bytes, tx_bytes, rx_dropped, tx_dropped,
rx_errors, tx_errors) = struct.unpack_from(
ofproto.OFP_PORT_STATS_PACK_STR, buf, offset)
props = []
rest = buf[offset + ofproto.OFP_PORT_STATS_SIZE:offset + length]
while rest:
p, rest = OFPPortStatsProp.parse(rest)
props.append(p)
stats = cls(length, port_no, duration_sec, duration_nsec, rx_packets,
tx_packets, rx_bytes, tx_bytes, rx_dropped, tx_dropped,
rx_errors, tx_errors, props)
return stats
@_set_stats_type(ofproto.OFPMP_PORT_STATS, OFPPortStats)
@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
class OFPPortStatsRequest(OFPMultipartRequest):
"""
Port statistics request message
The controller uses this message to query information about ports
statistics.
================ ======================================================
Attribute Description
================ ======================================================
flags Zero or ``OFPMPF_REQ_MORE``
port_no Port number to read (OFPP_ANY to all ports)
================ ======================================================
Example::
def send_port_stats_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPPortStatsRequest(datapath, 0, ofp.OFPP_ANY)
datapath.send_msg(req)
"""
def __init__(self, datapath, flags, port_no, type_=None):
super(OFPPortStatsRequest, self).__init__(datapath, flags)
self.port_no = port_no
def _serialize_stats_body(self):
msg_pack_into(ofproto.OFP_PORT_MULTIPART_REQUEST_PACK_STR,
self.buf,
ofproto.OFP_MULTIPART_REQUEST_SIZE,
self.port_no)
@OFPMultipartReply.register_stats_type()
@_set_stats_type(ofproto.OFPMP_PORT_STATS, OFPPortStats)
@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
class OFPPortStatsReply(OFPMultipartReply):
"""
Port statistics reply message
The switch responds with this message to a port statistics request.
================ ======================================================
Attribute Description
================ ======================================================
body List of ``OFPPortStats`` instance
================ ======================================================
Example::
@set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER)
def port_stats_reply_handler(self, ev):
ports = []
for stat in ev.msg.body:
ports.append(stat.length, stat.port_no,
stat.duration_sec, stat.duration_nsec,
stat.rx_packets, stat.tx_packets,
stat.rx_bytes, stat.tx_bytes,
stat.rx_dropped, stat.tx_dropped,
stat.rx_errors, stat.tx_errors,
repr(stat.properties))
self.logger.debug('PortStats: %s', ports)
"""
def __init__(self, datapath, type_=None, **kwargs):
super(OFPPortStatsReply, self).__init__(datapath, **kwargs)
@_set_msg_type(ofproto.OFPT_BARRIER_REQUEST)
class OFPBarrierRequest(MsgBase):
"""
Barrier request message
The controller sends this message to ensure message dependencies have
been met or receive notifications for completed operations.
Example::
def send_barrier_request(self, datapath):
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPBarrierRequest(datapath)
datapath.send_msg(req)
"""
def __init__(self, datapath):
super(OFPBarrierRequest, self).__init__(datapath)
@_register_parser
@_set_msg_type(ofproto.OFPT_BARRIER_REPLY)
class OFPBarrierReply(MsgBase):
"""
Barrier reply message
The switch responds with this message to a barrier request.
Example::
@set_ev_cls(ofp_event.EventOFPBarrierReply, MAIN_DISPATCHER)
def barrier_reply_handler(self, ev):
self.logger.debug('OFPBarrierReply received')
"""
def __init__(self, datapath):
super(OFPBarrierReply, self).__init__(datapath)
@_register_parser
@_set_msg_type(ofproto.OFPT_PORT_STATUS)
class OFPPortStatus(MsgBase):
"""
Port status message
The switch notifies controller of change of ports.
================ ======================================================
Attribute Description
================ ======================================================
reason One of the following values.
| OFPPR_ADD
| OFPPR_DELETE
| OFPPR_MODIFY
desc instance of ``OFPPort``
================ ======================================================
Example::
@set_ev_cls(ofp_event.EventOFPPortStatus, MAIN_DISPATCHER)
def port_status_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
if msg.reason == ofp.OFPPR_ADD:
reason = 'ADD'
elif msg.reason == ofp.OFPPR_DELETE:
reason = 'DELETE'
elif msg.reason == ofp.OFPPR_MODIFY:
reason = 'MODIFY'
else:
reason = 'unknown'
self.logger.debug('OFPPortStatus received: reason=%s desc=%s',
reason, msg.desc)
"""
def __init__(self, datapath, reason=None, desc=None):
super(OFPPortStatus, self).__init__(datapath)
self.reason = reason
self.desc = desc
@classmethod
def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
msg = super(OFPPortStatus, cls).parser(datapath, version, msg_type,
msg_len, xid, buf)
msg.reason = struct.unpack_from(
ofproto.OFP_PORT_STATUS_PACK_STR, msg.buf,
ofproto.OFP_HEADER_SIZE)[0]
msg.desc = OFPPort.parser(msg.buf, ofproto.OFP_PORT_STATUS_DESC_OFFSET)
return msg
@_register_parser
@_set_msg_type(ofproto.OFPT_ROLE_STATUS)
class OFPRoleStatus(MsgBase):
"""
Role status message
The switch notifies controller of change of role.
================ ======================================================
Attribute Description
================ ======================================================
role One of the following values.
| OFPCR_ROLE_NOCHANGE
| OFPCR_ROLE_EQUAL
| OFPCR_ROLE_MASTER
reason One of the following values.
| OFPCRR_MASTER_REQUEST
| OFPCRR_CONFIG
| OFPCRR_EXPERIMENTER
generation_id Master Election Generation ID
properties List of ``OFPRoleProp`` subclass instance
================ ======================================================
Example::
@set_ev_cls(ofp_event.EventOFPRoleStatus, MAIN_DISPATCHER)
def role_status_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
if msg.role == ofp.OFPCR_ROLE_NOCHANGE:
role = 'ROLE NOCHANGE'
elif msg.role == ofp.OFPCR_ROLE_EQUAL:
role = 'ROLE EQUAL'
elif msg.role == ofp.OFPCR_ROLE_MASTER:
role = 'ROLE MASTER'
else:
role = 'unknown'
if msg.reason == ofp.OFPCRR_MASTER_REQUEST:
reason = 'MASTER REQUEST'
elif msg.reason == ofp.OFPCRR_CONFIG:
reason = 'CONFIG'
elif msg.reason == ofp.OFPCRR_EXPERIMENTER:
reason = 'EXPERIMENTER'
else:
reason = 'unknown'
self.logger.debug('OFPRoleStatus received: role=%s reason=%s '
'generation_id=%d properties=%s', role, reason,
msg.generation_id, repr(msg.properties))
"""
def __init__(self, datapath, role=None, reason=None,
generation_id=None, properties=None):
super(OFPRoleStatus, self).__init__(datapath)
self.role = role
self.reason = reason
self.generation_id = generation_id
self.properties = properties
@classmethod
def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
msg = super(OFPRoleStatus, cls).parser(datapath, version, msg_type,
msg_len, xid, buf)
(msg.role, msg.reason, msg.generation_id) = struct.unpack_from(
ofproto.OFP_ROLE_STATUS_PACK_STR, msg.buf,
ofproto.OFP_HEADER_SIZE)
msg.properties = []
rest = msg.buf[ofproto.OFP_ROLE_STATUS_SIZE:]
while rest:
p, rest = OFPRoleProp.parse(rest)
msg.properties.append(p)
return msg
@_register_parser
@_set_msg_type(ofproto.OFPT_TABLE_STATUS)
class OFPTableStatus(MsgBase):
"""
Table status message
The switch notifies controller of change of table status.
================ ======================================================
Attribute Description
================ ======================================================
reason One of the following values.
| OFPTR_VACANCY_DOWN
| OFPTR_VACANCY_UP
table ``OFPTableDesc`` instance
================ ======================================================
Example::
@set_ev_cls(ofp_event.EventOFPTableStatus, MAIN_DISPATCHER)
def table(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
if msg.reason == ofp.OFPTR_VACANCY_DOWN:
reason = 'VACANCY_DOWN'
elif msg.reason == ofp.OFPTR_VACANCY_UP:
reason = 'VACANCY_UP'
else:
reason = 'unknown'
self.logger.debug('OFPTableStatus received: reason=%s '
'table_id=%d config=0x%08x properties=%s',
reason, msg.table.table_id, msg.table.config,
repr(msg.table.properties))
"""
def __init__(self, datapath, reason=None, table=None):
super(OFPTableStatus, self).__init__(datapath)
self.reason = reason
self.table = table
@classmethod
def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
msg = super(OFPTableStatus, cls).parser(datapath, version, msg_type,
msg_len, xid, buf)
(msg.reason,) = struct.unpack_from(ofproto.OFP_TABLE_STATUS_0_PACK_STR,
msg.buf, ofproto.OFP_HEADER_SIZE)
msg.table = OFPTableDesc.parser(msg.buf,
ofproto.OFP_TABLE_STATUS_0_SIZE)
return msg
@_register_parser
@_set_msg_type(ofproto.OFPT_REQUESTFORWARD)
class OFPRequestForward(MsgInMsgBase):
"""
Forwarded request message
The swtich forwards request messages from one controller to other
controllers.
================ ======================================================
Attribute Description
================ ======================================================
request ``OFPGroupMod`` or ``OFPMeterMod`` instance
================ ======================================================
Example::
@set_ev_cls(ofp_event.EventOFPRequestForward, MAIN_DISPATCHER)
def request_forward_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
if msg.request.msg_type == ofp.OFPT_GROUP_MOD:
self.logger.debug(
'OFPRequestForward received: request=OFPGroupMod('
'command=%d, type=%d, group_id=%d, command_bucket_id=%d, '
'buckets=%s, properties=%s)',
msg.request.command, msg.request.type,
msg.request.group_id, msg.request.command_bucket_id,
msg.request.buckets, repr(msg.request.properties))
elif msg.request.msg_type == ofp.OFPT_METER_MOD:
self.logger.debug(
'OFPRequestForward received: request=OFPMeterMod('
'command=%d, flags=%d, meter_id=%d, bands=%s)',
msg.request.command, msg.request.flags,
msg.request.meter_id, msg.request.bands)
else:
self.logger.debug(
'OFPRequestForward received: request=Unknown')
"""
def __init__(self, datapath, request=None):
super(OFPRequestForward, self).__init__(datapath)
self.request = request
@classmethod
def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
msg = super(OFPRequestForward, cls).parser(
datapath, version, msg_type, msg_len, xid, buf)
req_buf = buf[ofproto.OFP_HEADER_SIZE:]
(_ver, _type, _len, _xid) = ofproto_parser.header(req_buf)
msg.request = ofproto_parser.msg(
datapath, _ver, _type, _len, _xid, req_buf)
return msg
def _serialize_body(self):
assert isinstance(self.request, (OFPGroupMod, OFPMeterMod))
self.request.serialize()
self.buf += self.request.buf
class OFPControllerStatusProp(OFPPropBase):
_TYPES = {}
@OFPControllerStatusProp.register_type(ofproto.OFPCSPT_URI)
class OFPControllerStatusPropUri(OFPControllerStatusProp):
_TYPE = {
'ascii': [
'uri',
]
}
def __init__(self, type_=None, length=None, uri=None):
super(OFPControllerStatusPropUri, self).__init__(type_, length)
self.uri = uri
@classmethod
def parser(cls, buf):
rest = cls.get_rest(buf)
pack_str = '!%ds' % len(rest)
(uri, ) = struct.unpack_from(pack_str, rest, 0)
return cls(uri=uri)
@OFPControllerStatusProp.register_type(ofproto.OFPCSPT_EXPERIMENTER)
class OFPControllerStatusPropExperimenter(OFPPropCommonExperimenter4ByteData):
pass
class OFPControllerStatusStats(StringifyMixin):
"""
Controller status structure
============== =========================================================
Attribute Description
============== =========================================================
length Length of this entry.
short_id ID number which identifies the controller.
role Bitmap of controller's role flags.
| OFPCR_ROLE_NOCHANGE
| OFPCR_ROLE_EQUAL
| OFPCR_ROLE_MASTER
| OFPCR_ROLE_SLAVE
reason Bitmap of controller status reason flags.
| OFPCSR_REQUEST
| OFPCSR_CHANNEL_STATUS
| OFPCSR_ROLE
| OFPCSR_CONTROLLER_ADDED
| OFPCSR_CONTROLLER_REMOVED
| OFPCSR_SHORT_ID
| OFPCSR_EXPERIMENTER
channel_status Bitmap of control channel status flags.
| OFPCT_STATUS_UP
| OFPCT_STATUS_DOWN
properties List of ``OFPControllerStatusProp`` subclass instance
============== =========================================================
"""
def __init__(self, short_id=None, role=None, reason=None,
channel_status=None, properties=None, length=None):
super(OFPControllerStatusStats, self).__init__()
self.length = length
self.short_id = short_id
self.role = role
self.reason = reason
self.channel_status = channel_status
self.properties = properties
@classmethod
def parser(cls, buf, offset):
status = cls()
(status.length, status.short_id,
status.role, status.reason,
status.channel_status) = struct.unpack_from(
ofproto.OFP_CONTROLLER_STATUS_PACK_STR, buf, offset)
offset += ofproto.OFP_CONTROLLER_STATUS_SIZE
status.properties = []
rest = buf[offset:offset + status.length]
while rest:
p, rest = OFPControllerStatusProp.parse(rest)
status.properties.append(p)
return status
@_set_stats_type(ofproto.OFPMP_CONTROLLER_STATUS, OFPControllerStatusStats)
@_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
class OFPControllerStatusStatsRequest(OFPMultipartRequest):
"""
Controller status multipart request message
The controller uses this message to request the status, the roles
and the control channels of other controllers configured on the switch.
================ ======================================================
Attribute Description
================ ======================================================
flags Zero or ``OFPMPF_REQ_MORE``
================ ======================================================
Example::
def send_controller_status_multipart_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(OFPControllerStatusStatsRequest,
self).__init__(datapath, flags)
@OFPMultipartReply.register_stats_type()
@_set_stats_type(ofproto.OFPMP_CONTROLLER_STATUS, OFPControllerStatusStats)
@_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
class OFPControllerStatusStatsReply(OFPMultipartReply):
"""
Controller status multipart reply message
The switch responds with this message to a controller status
multipart request.
================ ======================================================
Attribute Description
================ ======================================================
body List of ``OFPControllerStatus`` instance
================ ======================================================
Example::
@set_ev_cls(ofp_event.EventOFPControllerStatusStatsReply,
MAIN_DISPATCHER)
def controller_status_multipart_reply_handler(self, ev):
status = []
for s in ev.msg.body:
status.append('short_id=%d role=%d reason=%d '
'channel_status=%d properties=%s' %
(s.short_id, s.role, s.reason,
s.channel_status, repr(s.properties)))
self.logger.debug('OFPControllerStatusStatsReply received: %s',
status)
"""
def __init__(self, datapath, type_=None, **kwargs):
super(OFPControllerStatusStatsReply, self).__init__(datapath,
**kwargs)
@_register_parser
@_set_msg_type(ofproto.OFPT_CONTROLLER_STATUS)
class OFPControllerStatus(MsgBase):
"""
Controller status message
The switch informs the controller about the status of the control
channel it maintains with each controller.
================ ======================================================
Attribute Description
================ ======================================================
status ``OFPControllerStatusStats`` instance
================ ======================================================
Example::
@set_ev_cls(ofp_event.EventOFPControllerStatus, MAIN_DISPATCHER)
def table(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
status = msg.status
if status.role == ofp.OFPCR_ROLE_NOCHANGE:
role = 'NOCHANGE'
elif status.role == ofp.OFPCR_ROLE_EQUAL:
role = 'EQUAL'
elif status.role == ofp.OFPCR_ROLE_MASTER:
role = 'MASTER'
elif status.role == ofp.OFPCR_ROLE_SLAVE:
role = 'SLAVE'
else:
role = 'unknown'
if status.reason == ofp.OFPCSR_REQUEST:
reason = 'REQUEST'
elif status.reason == ofp.OFPCSR_CHANNEL_STATUS:
reason = 'CHANNEL_STATUS'
elif status.reason == ofp.OFPCSR_ROLE:
reason = 'ROLE'
elif status.reason == ofp.OFPCSR_CONTROLLER_ADDED:
reason = 'CONTROLLER_ADDED'
elif status.reason == ofp.OFPCSR_CONTROLLER_REMOVED:
reason = 'CONTROLLER_REMOVED'
elif status.reason == ofp.OFPCSR_SHORT_ID:
reason = 'SHORT_ID'
elif status.reason == ofp.OFPCSR_EXPERIMENTER:
reason = 'EXPERIMENTER'
else:
reason = 'unknown'
if status.channel_status == OFPCT_STATUS_UP:
channel_status = 'UP'
if status.channel_status == OFPCT_STATUS_DOWN:
channel_status = 'DOWN'
else:
channel_status = 'unknown'
self.logger.debug('OFPControllerStatus received: short_id=%d'
'role=%s reason=%s channel_status=%s '
'properties=%s',
status.short_id, role, reason, channel_status,
repr(status.properties))
"""
def __init__(self, datapath, status=None):
super(OFPControllerStatus, self).__init__(datapath)
self.status = status
@classmethod
def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
msg = super(OFPControllerStatus, cls).parser(datapath, version,
msg_type, msg_len,
xid, buf)
msg.status = OFPControllerStatusStats.parser(msg.buf,
ofproto.OFP_HEADER_SIZE)
return msg
@_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)
match Instance of ``OFPMatch``
(``in_port`` is mandatory in the match field)
actions list of OpenFlow action class
data Packet data of a binary type value or
an instances of packet.Packet.
================ ======================================================
Example::
def send_packet_out(self, datapath, buffer_id, in_port):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
match = OFPMatch(in_port=in_port)
actions = [ofp_parser.OFPActionOutput(ofp.OFPP_FLOOD, 0)]
req = ofp_parser.OFPPacketOut(datapath, buffer_id,
match, actions)
datapath.send_msg(req)
"""
def __init__(self, datapath, buffer_id=None, match=None, actions=None,
data=None, actions_len=None):
super(OFPPacketOut, self).__init__(datapath)
if buffer_id is None:
self.buffer_id = ofproto.OFP_NO_BUFFER
else:
self.buffer_id = buffer_id
self.actions_len = 0
assert 'in_port' in match
self.match = match
self.actions = actions
self.data = data
def _serialize_body(self):
# adjustment
offset = ofproto.OFP_PACKET_OUT_0_SIZE
match_len = self.match.serialize(self.buf, offset)
offset += match_len
self.actions_len = 0
for a in self.actions:
a.serialize(self.buf, offset)
offset += a.len
self.actions_len += a.len
if self.buffer_id == ofproto.OFP_NO_BUFFER:
assert self.data is not None
if isinstance(self.data, packet.Packet):
self.data.serialize()
self.buf += self.data.data
else:
self.buf += self.data
else:
assert self.data is None
msg_pack_into(ofproto.OFP_PACKET_OUT_0_PACK_STR,
self.buf, ofproto.OFP_HEADER_SIZE,
self.buffer_id, self.actions_len)
@classmethod
def from_jsondict(cls, dict_, decode_string=base64.b64decode,
**additional_args):
if isinstance(dict_['data'], dict):
data = dict_.pop('data')
ins = super(OFPPacketOut, cls).from_jsondict(dict_,
decode_string,
**additional_args)
ins.data = packet.Packet.from_jsondict(data['Packet'])
dict_['data'] = data
else:
ins = super(OFPPacketOut, cls).from_jsondict(dict_,
decode_string,
**additional_args)
return ins
@_register_parser
@_set_msg_type(ofproto.OFPT_FLOW_MOD)
class OFPFlowMod(MsgBase):
"""
Modify Flow entry message
The controller sends this message to modify the flow table.
================ ======================================================
Attribute Description
================ ======================================================
cookie Opaque controller-issued identifier
cookie_mask Mask used to restrict the cookie bits that must match
when the command is ``OPFFC_MODIFY*`` or
``OFPFC_DELETE*``
table_id ID of the table to put the flow in
command One of the following values.
| OFPFC_ADD
| OFPFC_MODIFY
| OFPFC_MODIFY_STRICT
| OFPFC_DELETE
| OFPFC_DELETE_STRICT
idle_timeout Idle time before discarding (seconds)
hard_timeout Max time before discarding (seconds)
priority Priority level of flow entry
buffer_id Buffered packet to apply to (or OFP_NO_BUFFER)
out_port For ``OFPFC_DELETE*`` commands, require matching
entries to include this as an output port
out_group For ``OFPFC_DELETE*`` commands, require matching
entries to include this as an output group
flags Bitmap of the following flags.
| OFPFF_SEND_FLOW_REM
| OFPFF_CHECK_OVERLAP
| OFPFF_RESET_COUNTS
| OFPFF_NO_PKT_COUNTS
| OFPFF_NO_BYT_COUNTS
importance Eviction precedence
match Instance of ``OFPMatch``
instructions list of ``OFPInstruction*`` instance
================ ======================================================
Example::
def send_flow_mod(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
cookie = cookie_mask = 0
table_id = 0
idle_timeout = hard_timeout = 0
priority = 32768
buffer_id = ofp.OFP_NO_BUFFER
importance = 0
match = ofp_parser.OFPMatch(in_port=1, eth_dst='ff:ff:ff:ff:ff:ff')
actions = [ofp_parser.OFPActionOutput(ofp.OFPP_NORMAL, 0)]
inst = [ofp_parser.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS,
actions)]
req = ofp_parser.OFPFlowMod(datapath, cookie, cookie_mask,
table_id, ofp.OFPFC_ADD,
idle_timeout, hard_timeout,
priority, buffer_id,
ofp.OFPP_ANY, ofp.OFPG_ANY,
ofp.OFPFF_SEND_FLOW_REM,
importance,
match, inst)
datapath.send_msg(req)
"""
def __init__(self, datapath, cookie=0, cookie_mask=0, table_id=0,
command=ofproto.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=ofproto.OFP_DEFAULT_PRIORITY,
buffer_id=ofproto.OFP_NO_BUFFER,
out_port=0, out_group=0, flags=0, importance=0,
match=None,
instructions=None):
instructions = instructions if instructions else []
super(OFPFlowMod, self).__init__(datapath)
self.cookie = cookie
self.cookie_mask = cookie_mask
self.table_id = table_id
self.command = command
self.idle_timeout = idle_timeout
self.hard_timeout = hard_timeout
self.priority = priority
self.buffer_id = buffer_id
self.out_port = out_port
self.out_group = out_group
self.flags = flags
self.importance = importance
if match is None:
match = OFPMatch()
assert isinstance(match, OFPMatch)
self.match = match
for i in instructions:
assert isinstance(i, OFPInstruction)
self.instructions = instructions
def _serialize_body(self):
msg_pack_into(ofproto.OFP_FLOW_MOD_PACK_STR0, self.buf,
ofproto.OFP_HEADER_SIZE,
self.cookie, self.cookie_mask, self.table_id,
self.command, self.idle_timeout, self.hard_timeout,
self.priority, self.buffer_id, self.out_port,
self.out_group, self.flags, self.importance)
offset = (ofproto.OFP_FLOW_MOD_SIZE -
ofproto.OFP_MATCH_SIZE)
match_len = self.match.serialize(self.buf, offset)
offset += match_len
for inst in self.instructions:
inst.serialize(self.buf, offset)
offset += inst.len
@classmethod
def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
msg = super(OFPFlowMod, cls).parser(
datapath, version, msg_type, msg_len, xid, buf)
(msg.cookie, msg.cookie_mask, msg.table_id,
msg.command, msg.idle_timeout, msg.hard_timeout,
msg.priority, msg.buffer_id, msg.out_port,
msg.out_group, msg.flags, msg.importance) = struct.unpack_from(
ofproto.OFP_FLOW_MOD_PACK_STR0, msg.buf,
ofproto.OFP_HEADER_SIZE)
offset = ofproto.OFP_FLOW_MOD_SIZE - ofproto.OFP_HEADER_SIZE
msg.match = OFPMatch.parser(buf, offset)
offset += utils.round_up(msg.match.length, 8)
instructions = []
while offset < msg_len:
i = OFPInstruction.parser(buf, offset)
instructions.append(i)
offset += i.len
msg.instructions = instructions
return msg
class OFPInstruction(StringifyMixin):
_INSTRUCTION_TYPES = {}
@staticmethod
def register_instruction_type(types):
def _register_instruction_type(cls):
for type_ in types:
OFPInstruction._INSTRUCTION_TYPES[type_] = cls
return cls
return _register_instruction_type
@classmethod
def parser(cls, buf, offset):
(type_, len_) = struct.unpack_from('!HH', buf, offset)
cls_ = cls._INSTRUCTION_TYPES.get(type_)
return cls_.parser(buf, offset)
@OFPInstruction.register_instruction_type([ofproto.OFPIT_GOTO_TABLE])
class OFPInstructionGotoTable(OFPInstruction):
"""
Goto table instruction
This instruction indicates the next table in the processing pipeline.
================ ======================================================
Attribute Description
================ ======================================================
table_id Next table
================ ======================================================
"""
def __init__(self, table_id, type_=None, len_=None):
super(OFPInstructionGotoTable, self).__init__()
self.type = ofproto.OFPIT_GOTO_TABLE
self.len = ofproto.OFP_INSTRUCTION_GOTO_TABLE_SIZE
self.table_id = table_id
@classmethod
def parser(cls, buf, offset):
(type_, len_, table_id) = struct.unpack_from(
ofproto.OFP_INSTRUCTION_GOTO_TABLE_PACK_STR,
buf, offset)
return cls(table_id)
def serialize(self, buf, offset):
msg_pack_into(ofproto.OFP_INSTRUCTION_GOTO_TABLE_PACK_STR,
buf, offset, self.type, self.len, self.table_id)
@OFPInstruction.register_instruction_type([ofproto.OFPIT_WRITE_METADATA])
class OFPInstructionWriteMetadata(OFPInstruction):
"""
Write metadata instruction
This instruction writes the masked metadata value into the metadata field.
================ ======================================================
Attribute Description
================ ======================================================
metadata Metadata value to write
metadata_mask Metadata write bitmask
================ ======================================================
"""
def __init__(self, metadata, metadata_mask, type_=None, len_=None):
super(OFPInstructionWriteMetadata, self).__init__()
self.type = ofproto.OFPIT_WRITE_METADATA
self.len = ofproto.OFP_INSTRUCTION_WRITE_METADATA_SIZE
self.metadata = metadata
self.metadata_mask = metadata_mask
@classmethod
def parser(cls, buf, offset):
(type_, len_, metadata, metadata_mask) = struct.unpack_from(
ofproto.OFP_INSTRUCTION_WRITE_METADATA_PACK_STR,
buf, offset)
return cls(metadata, metadata_mask)
def serialize(self, buf, offset):
msg_pack_into(ofproto.OFP_INSTRUCTION_WRITE_METADATA_PACK_STR,
buf, offset, self.type, self.len, self.metadata,
self.metadata_mask)
@OFPInstruction.register_instruction_type([ofproto.OFPIT_WRITE_ACTIONS,
ofproto.OFPIT_APPLY_ACTIONS,
ofproto.OFPIT_CLEAR_ACTIONS])
class OFPInstructionActions(OFPInstruction):
"""
Actions instruction
This instruction writes/applies/clears the actions.
================ ======================================================
Attribute Description
================ ======================================================
type One of following values.
| OFPIT_WRITE_ACTIONS
| OFPIT_APPLY_ACTIONS
| OFPIT_CLEAR_ACTIONS
actions list of OpenFlow action class
================ ======================================================
``type`` attribute corresponds to ``type_`` parameter of __init__.
"""
def __init__(self, type_, actions=None, len_=None):
super(OFPInstructionActions, self).__init__()
self.type = type_
for a in actions:
assert isinstance(a, OFPAction)
self.actions = actions
@classmethod
def parser(cls, buf, offset):
(type_, len_) = struct.unpack_from(
ofproto.OFP_INSTRUCTION_ACTIONS_PACK_STR,
buf, offset)
offset += ofproto.OFP_INSTRUCTION_ACTIONS_SIZE
actions = []
actions_len = len_ - ofproto.OFP_INSTRUCTION_ACTIONS_SIZE
while actions_len > 0:
a = OFPAction.parser(buf, offset)
actions.append(a)
actions_len -= a.len
offset += a.len
inst = cls(type_, actions)
inst.len = len_
return inst
def serialize(self, buf, offset):
action_offset = offset + ofproto.OFP_INSTRUCTION_ACTIONS_SIZE
if self.actions:
for a in self.actions:
a.serialize(buf, action_offset)
action_offset += a.len
self.len = action_offset - offset
pad_len = utils.round_up(self.len, 8) - self.len
msg_pack_into("%dx" % pad_len, buf, action_offset)
self.len += pad_len
msg_pack_into(ofproto.OFP_INSTRUCTION_ACTIONS_PACK_STR,
buf, offset, self.type, self.len)
@OFPInstruction.register_instruction_type([ofproto.OFPIT_STAT_TRIGGER])
class OFPInstructionStatTrigger(OFPInstruction):
"""
Statistics triggers instruction
This instruction defines a set of statistics thresholds using OXS.
================ ======================================================
Attribute Description
================ ======================================================
flags Bitmap of the following flags.
| OFPSTF_PERIODIC
| OFPSTF_ONLY_FIRST
thresholds Instance of ``OFPStats``
================ ======================================================
"""
def __init__(self, flags, thresholds, type_=None, len_=None):
super(OFPInstructionStatTrigger, self).__init__()
self.type = ofproto.OFPIT_STAT_TRIGGER
self.len = len_
self.flags = flags
self.thresholds = thresholds
@classmethod
def parser(cls, buf, offset):
(type_, len_, flags) = struct.unpack_from(
ofproto.OFP_INSTRUCTION_STAT_TRIGGER_PACK_STR0, buf, offset)
# adjustment
offset += 8
thresholds = OFPStats.parser(buf, offset)
inst = cls(flags, thresholds)
inst.len = len_
return inst
def serialize(self, buf, offset):
stats_len = self.thresholds.serialize(buf, offset + 8)
self.len = 8 + stats_len
msg_pack_into(ofproto.OFP_INSTRUCTION_STAT_TRIGGER_PACK_STR0,
buf, offset, self.type, self.len, self.flags)
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
which including with/without mask.
Example::
set_field = OFPActionSetField(eth_src="00:00:00:00:00:00")
set_field = OFPActionSetField(ipv4_src=("192.168.100.0",
"255.255.255.0"))
"""
def __init__(self, field=None, **kwargs):
super(OFPActionSetField, self).__init__()
assert len(kwargs) == 1
key = list(kwargs.keys())[0]
value = kwargs[key]
assert isinstance(key, (str, six.text_type))
self.key = key
self.value = value
@classmethod
def parser(cls, buf, offset):
(type_, len_) = struct.unpack_from(
ofproto.OFP_ACTION_SET_FIELD_PACK_STR, buf, offset)
(n, value, mask, _len) = ofproto.oxm_parse(buf, offset + 4)
k, uv = ofproto.oxm_to_user(n, value, mask)
action = cls(**{k: uv})
action.len = len_
return action
def serialize(self, buf, offset):
n, value, mask = ofproto.oxm_from_user(self.key, self.value)
len_ = ofproto.oxm_serialize(n, value, mask, buf, offset + 4)
self.len = utils.round_up(4 + len_, 8)
msg_pack_into('!HH', buf, offset, self.type, self.len)
pad_len = self.len - (4 + len_)
msg_pack_into("%dx" % pad_len, buf, offset + 4 + len_)
def to_jsondict(self):
return {
self.__class__.__name__: {
'field': ofproto.oxm_to_jsondict(self.key, self.value),
"len": self.len,
"type": self.type
}
}
@classmethod
def from_jsondict(cls, dict_):
k, v = ofproto.oxm_from_jsondict(dict_['field'])
return OFPActionSetField(**{k: v})
def stringify_attrs(self):
yield (self.key, self.value)
@OFPAction.register_action_type(ofproto.OFPAT_PUSH_PBB,
ofproto.OFP_ACTION_PUSH_SIZE)
class OFPActionPushPbb(OFPAction):
"""
Push PBB action
This action pushes a new PBB header to the packet.
================ ======================================================
Attribute Description
================ ======================================================
ethertype Ether type
================ ======================================================
"""
def __init__(self, ethertype, type_=None, len_=None):
super(OFPActionPushPbb, self).__init__()
self.ethertype = ethertype
@classmethod
def parser(cls, buf, offset):
(type_, len_, ethertype) = struct.unpack_from(
ofproto.OFP_ACTION_PUSH_PACK_STR, buf, offset)
return cls(ethertype)
def serialize(self, buf, offset):
msg_pack_into(ofproto.OFP_ACTION_PUSH_PACK_STR, buf, offset,
self.type, self.len, self.ethertype)
@OFPAction.register_action_type(ofproto.OFPAT_POP_PBB,
ofproto.OFP_ACTION_HEADER_SIZE)
class OFPActionPopPbb(OFPAction):
"""
Pop PBB action
This action pops the outermost PBB service instance header from
the packet.
"""
def __init__(self, type_=None, len_=None):
super(OFPActionPopPbb, self).__init__()
@classmethod
def parser(cls, buf, offset):
(type_, len_) = struct.unpack_from(
ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
return cls()
@OFPAction.register_action_type(ofproto.OFPAT_COPY_FIELD,
ofproto.OFP_ACTION_COPY_FIELD_SIZE)
class OFPActionCopyField(OFPAction):
"""
Copy Field action
This action copy value between header and register.
================ ======================================================
Attribute Description
================ ======================================================
n_bits Number of bits to copy.
src_offset Starting bit offset in source.
dst_offset Starting bit offset in destination.
oxm_ids List of ``OFPOxmId`` instances.
The first element of this list, src_oxm_id,
identifies the field where the value is copied from.
The second element of this list, dst_oxm_id,
identifies the field where the value is copied to.
The default is [].
================ ======================================================
"""
def __init__(self, n_bits=0, src_offset=0, dst_offset=0, oxm_ids=None,
type_=None, len_=None):
oxm_ids = oxm_ids if oxm_ids else []
super(OFPActionCopyField, self).__init__()
self.n_bits = n_bits
self.src_offset = src_offset
self.dst_offset = dst_offset
assert len(oxm_ids) == 2
self.oxm_ids = []
for i in oxm_ids:
if isinstance(i, OFPOxmId):
i.hasmask = False # fixup
self.oxm_ids.append(i)
elif isinstance(i, six.text_type):
self.oxm_ids.append(OFPOxmId(i, hasmask=False))
else:
raise ValueError('invalid value for oxm_ids: %s' % oxm_ids)
@classmethod
def parser(cls, buf, offset):
(type_, len_, n_bits, src_offset, dst_offset) = struct.unpack_from(
ofproto.OFP_ACTION_COPY_FIELD_PACK_STR, buf, offset)
offset += ofproto.OFP_ACTION_COPY_FIELD_SIZE
rest = buf[offset:offset + len_]
oxm_ids = []
while rest:
i, rest = OFPOxmId.parse(rest)
oxm_ids.append(i)
return cls(n_bits, src_offset, dst_offset, oxm_ids, type_, len_)
def serialize(self, buf, offset):
oxm_ids_buf = b''
for i in self.oxm_ids:
oxm_ids_buf += i.serialize()
action_len = ofproto.OFP_ACTION_COPY_FIELD_SIZE + len(oxm_ids_buf)
self.len = utils.round_up(action_len, 8)
pad_len = self.len - action_len
msg_pack_into(ofproto.OFP_ACTION_COPY_FIELD_PACK_STR, buf,
offset, self.type, self.len,
self.n_bits, self.src_offset, self.dst_offset)
buf += oxm_ids_buf + b'\x00' * pad_len
@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
================ ======================================================
.. Note::
For the list of the supported Nicira experimenter actions,
please refer to :ref:`os_ken.ofproto.nx_actions <nx_actions_structures>`.
"""
def __init__(self, experimenter):
super(OFPActionExperimenter, self).__init__()
self.type = ofproto.OFPAT_EXPERIMENTER
self.experimenter = experimenter
self.len = None
@classmethod
def parser(cls, buf, offset):
(type_, len_, experimenter) = struct.unpack_from(
ofproto.OFP_ACTION_EXPERIMENTER_HEADER_PACK_STR, buf, offset)
data = buf[(offset + ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE
): offset + len_]
if experimenter == ofproto_common.NX_EXPERIMENTER_ID:
obj = NXAction.parse(data)
else:
obj = OFPActionExperimenterUnknown(experimenter, data)
obj.len = len_
return obj
def serialize(self, buf, offset):
msg_pack_into(ofproto.OFP_ACTION_EXPERIMENTER_HEADER_PACK_STR,
buf, offset, self.type, self.len, self.experimenter)
class OFPActionExperimenterUnknown(OFPActionExperimenter):
def __init__(self, experimenter, data=None, type_=None, len_=None):
super(OFPActionExperimenterUnknown,
self).__init__(experimenter=experimenter)
self.data = data
def serialize(self, buf, offset):
# fixup
data = self.data
if data is None:
data = bytearray()
self.len = (utils.round_up(len(data), 8) +
ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE)
super(OFPActionExperimenterUnknown, self).serialize(buf, offset)
msg_pack_into('!%ds' % len(self.data),
buf,
offset + ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE,
self.data)
class OFPGroupProp(OFPPropBase):
_TYPES = {}
@OFPGroupProp.register_type(ofproto.OFPGPT_EXPERIMENTER)
class OFPGroupPropExperimenter(OFPPropCommonExperimenter4ByteData):
pass
@_register_parser
@_set_msg_type(ofproto.OFPT_GROUP_MOD)
class OFPGroupMod(MsgBase):
"""
Modify group entry message
The controller sends this message to modify the group table.
================== ======================================================
Attribute Description
================== ======================================================
command One of the following values.
| OFPGC_ADD
| OFPGC_MODIFY
| OFPGC_DELETE
| OFPGC_INSERT_BUCKET
| OFPGC_REMOVE_BUCKET
type One of the following values.
| OFPGT_ALL
| OFPGT_SELECT
| OFPGT_INDIRECT
| OFPGT_FF
group_id Group identifier.
command_bucket_id Bucket Id used as part of OFPGC_INSERT_BUCKET and
OFPGC_REMOVE_BUCKET commands execution.
buckets List of ``OFPBucket`` instance
properties List of ``OFPGroupProp`` instance
================== ======================================================
``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
command_bucket_id=1
req = ofp_parser.OFPGroupMod(datapath, ofp.OFPGC_ADD,
ofp.OFPGT_SELECT, group_id,
command_bucket_id, buckets)
datapath.send_msg(req)
"""
def __init__(self, datapath, command=ofproto.OFPGC_ADD,
type_=ofproto.OFPGT_ALL, group_id=0,
command_bucket_id=ofproto.OFPG_BUCKET_ALL,
buckets=None, properties=None, bucket_array_len=None):
buckets = buckets if buckets else []
properties = properties if properties else []
super(OFPGroupMod, self).__init__(datapath)
self.command = command
self.type = type_
self.group_id = group_id
self.command_bucket_id = command_bucket_id
self.buckets = buckets
self.properties = properties
@classmethod
def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
msg = super(OFPGroupMod, cls).parser(
datapath, version, msg_type, msg_len, xid, buf)
(msg.command, msg.type, msg.group_id, msg.bucket_array_len,
msg.command_bucket_id) = struct.unpack_from(
ofproto.OFP_GROUP_MOD_PACK_STR, buf, ofproto.OFP_HEADER_SIZE)
offset = ofproto.OFP_GROUP_MOD_SIZE
bucket_buf = buf[offset:offset + msg.bucket_array_len]
msg.buckets = []
while bucket_buf:
bucket = OFPBucket.parser(bucket_buf, 0)
msg.buckets.append(bucket)
bucket_buf = bucket_buf[bucket.len:]
offset += msg.bucket_array_len
rest = buf[offset:offset + msg.msg_len]
while rest:
p, rest = OFPGroupProp.parse(rest)
msg.properties.append(p)
return msg
def _serialize_body(self):
offset = ofproto.OFP_GROUP_MOD_SIZE
self.bucket_array_len = 0
for b in self.buckets:
b.serialize(self.buf, offset)
offset += b.len
self.bucket_array_len += b.len
msg_pack_into(ofproto.OFP_GROUP_MOD_PACK_STR, self.buf,
ofproto.OFP_HEADER_SIZE,
self.command, self.type, self.group_id,
self.bucket_array_len, self.command_bucket_id)
bin_props = bytearray()
for p in self.properties:
bin_props += p.serialize()
self.buf += bin_props
class OFPPortModProp(OFPPropBase):
_TYPES = {}
class OFPPortModPropEthernet(OFPPortModProp):
def __init__(self, type_=None, length=None, advertise=None):
self.type = type_
self.advertise = advertise
def serialize(self):
# fixup
self.length = struct.calcsize(
ofproto.OFP_PORT_MOD_PROP_ETHERNET_PACK_STR)
buf = bytearray()
msg_pack_into(ofproto.OFP_PORT_MOD_PROP_ETHERNET_PACK_STR,
buf, 0, self.type, self.length, self.advertise)
return buf
class OFPPortModPropOptical(OFPPortModProp):
def __init__(self, type_=None, length=None, configure=None,
freq_lmda=None, fl_offset=None, grid_span=None,
tx_pwr=None):
self.type = type_
self.length = length
self.configure = configure
self.freq_lmda = freq_lmda
self.fl_offset = fl_offset
self.grid_span = grid_span
self.tx_pwr = tx_pwr
def serialize(self):
# fixup
self.length = struct.calcsize(
ofproto.OFP_PORT_MOD_PROP_OPTICAL_PACK_STR)
buf = bytearray()
msg_pack_into(ofproto.OFP_PORT_MOD_PROP_OPTICAL_PACK_STR, buf, 0,
self.type, self.length, self.configure, self.freq_lmda,
self.fl_offset, self.grid_span, self.tx_pwr)
return buf
class OFPPortModPropExperimenter(OFPPropCommonExperimenter4ByteData):
pass
@_set_msg_type(ofproto.OFPT_PORT_MOD)
class OFPPortMod(MsgBase):
"""
Port modification message
The controller sneds this message to modify the behavior of the port.
================ ======================================================
Attribute Description
================ ======================================================
port_no Port number to modify
hw_addr The hardware address that must be the same as hw_addr
of ``OFPPort`` of ``OFPSwitchFeatures``
config Bitmap of configuration flags.
| OFPPC_PORT_DOWN
| OFPPC_NO_RECV
| OFPPC_NO_FWD
| OFPPC_NO_PACKET_IN
mask Bitmap of configuration flags above to be changed
properties List of ``OFPPortModProp`` subclass instance
================ ======================================================
Example::
def send_port_mod(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
port_no = 3
hw_addr = 'fa:c8:e8:76:1d:7e'
config = 0
mask = (ofp.OFPPC_PORT_DOWN | ofp.OFPPC_NO_RECV |
ofp.OFPPC_NO_FWD | ofp.OFPPC_NO_PACKET_IN)
advertise = (ofp.OFPPF_10MB_HD | ofp.OFPPF_100MB_FD |
ofp.OFPPF_1GB_FD | ofp.OFPPF_COPPER |
ofp.OFPPF_AUTONEG | ofp.OFPPF_PAUSE |
ofp.OFPPF_PAUSE_ASYM)
properties = [ofp_parser.OFPPortModPropEthernet(advertise)]
req = ofp_parser.OFPPortMod(datapath, port_no, hw_addr, config,
mask, properties)
datapath.send_msg(req)
"""
_TYPE = {
'ascii': [
'hw_addr',
]
}
def __init__(self, datapath, port_no=0, hw_addr='00:00:00:00:00:00',
config=0, mask=0, properties=None):
super(OFPPortMod, self).__init__(datapath)
self.port_no = port_no
self.hw_addr = hw_addr
self.config = config
self.mask = mask
self.properties = properties or []
def _serialize_body(self):
bin_props = bytearray()
for p in self.properties:
bin_props += p.serialize()
msg_pack_into(ofproto.OFP_PORT_MOD_PACK_STR, self.buf,
ofproto.OFP_HEADER_SIZE,
self.port_no, addrconv.mac.text_to_bin(self.hw_addr),
self.config,
self.mask)
self.buf += bin_props
class OFPGroupBucketProp(OFPPropBase):
_TYPES = {}
@OFPGroupBucketProp.register_type(ofproto.OFPGBPT_WEIGHT)
class OFPGroupBucketPropWeight(OFPGroupBucketProp):
def __init__(self, type_=None, length=None, weight=None):
super(OFPGroupBucketPropWeight, self).__init__(type_, length)
self.weight = weight
@classmethod
def parser(cls, buf):
prop = cls()
(prop.type, prop.length, prop.weight) = struct.unpack_from(
ofproto.OFP_GROUP_BUCKET_PROP_WEIGHT_PACK_STR, buf, 0)
return prop
def serialize(self):
# fixup
self.length = ofproto.OFP_GROUP_BUCKET_PROP_WEIGHT_SIZE
buf = bytearray()
msg_pack_into(ofproto.OFP_GROUP_BUCKET_PROP_WEIGHT_PACK_STR, buf, 0,
self.type, self.length, self.weight)
return buf
@OFPGroupBucketProp.register_type(ofproto.OFPGBPT_WATCH_PORT)
@OFPGroupBucketProp.register_type(ofproto.OFPGBPT_WATCH_GROUP)
class OFPGroupBucketPropWatch(OFPGroupBucketProp):
def __init__(self, type_=None, length=None, watch=None):
super(OFPGroupBucketPropWatch, self).__init__(type_, length)
self.watch = watch
@classmethod
def parser(cls, buf):
prop = cls()
(prop.type, prop.length, prop.watch) = struct.unpack_from(
ofproto.OFP_GROUP_BUCKET_PROP_WATCH_PACK_STR, buf, 0)
return prop
def serialize(self):
# fixup
self.length = ofproto.OFP_GROUP_BUCKET_PROP_WATCH_SIZE
buf = bytearray()
msg_pack_into(ofproto.OFP_GROUP_BUCKET_PROP_WATCH_PACK_STR, buf, 0,
self.type, self.length, self.watch)
return buf
@OFPGroupBucketProp.register_type(ofproto.OFPGBPT_EXPERIMENTER)
class OFPGroupBucketPropExperimenter(OFPPropCommonExperimenter4ByteData):
pass
class OFPBucket(StringifyMixin):
def __init__(self, bucket_id=0, actions=None, properties=None,
len_=None, action_array_len=None):
actions = actions if actions else []
properties = properties if properties else []
super(OFPBucket, self).__init__()
self.bucket_id = bucket_id
self.actions = actions
self.properties = properties
@classmethod
def parser(cls, buf, offset):
msg = cls()
(msg.len, msg.action_array_len,
msg.bucket_id) = struct.unpack_from(
ofproto.OFP_BUCKET_PACK_STR, buf, offset)
offset += ofproto.OFP_BUCKET_SIZE
action_buf = buf[offset:offset + msg.action_array_len]
msg.actions = []
while action_buf:
action = OFPAction.parser(action_buf, 0)
msg.actions.append(action)
action_buf = action_buf[action.len:]
offset += msg.action_array_len
rest = buf[offset:offset + msg.len]
msg.properties = []
while rest:
p, rest = OFPGroupBucketProp.parse(rest)
msg.properties.append(p)
return msg
def serialize(self, buf, offset):
action_offset = offset + ofproto.OFP_BUCKET_SIZE
self.action_array_len = 0
for a in self.actions:
a.serialize(buf, action_offset)
action_offset += a.len
self.action_array_len += a.len
bin_props = bytearray()
for p in self.properties:
bin_props += p.serialize()
props_len = len(bin_props)
self.len = utils.round_up(ofproto.OFP_BUCKET_SIZE +
self.action_array_len + props_len, 8)
msg_pack_into(ofproto.OFP_BUCKET_PACK_STR, buf, offset,
self.len, self.action_array_len, self.bucket_id)
buf += bin_props
@_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
short_id ID number for the controller.
The default is OFPCID_UNDEFINED.
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,
ofp.OFPCID_UNDEFINED, 0)
datapath.send_msg(req)
"""
def __init__(self, datapath, role=None, short_id=None,
generation_id=None):
super(OFPRoleRequest, self).__init__(datapath)
self.role = role
self.short_id = short_id
self.generation_id = generation_id
def _serialize_body(self):
assert self.role is not None
assert self.generation_id is not None
if self.short_id is None:
self.short_id = ofproto.OFPCID_UNDEFINED
msg_pack_into(ofproto.OFP_ROLE_REQUEST_PACK_STR,
self.buf, ofproto.OFP_HEADER_SIZE,
self.role, self.short_id, 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
short_id ID number for the controller.
The default is OFPCID_UNDEFINED.
generation_id Master Election Generation ID
================ ======================================================
Example::
@set_ev_cls(ofp_event.EventOFPRoleReply, MAIN_DISPATCHER)
def role_reply_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
if msg.role == ofp.OFPCR_ROLE_NOCHANGE:
role = 'NOCHANGE'
elif msg.role == ofp.OFPCR_ROLE_EQUAL:
role = 'EQUAL'
elif msg.role == ofp.OFPCR_ROLE_MASTER:
role = 'MASTER'
elif msg.role == ofp.OFPCR_ROLE_SLAVE:
role = 'SLAVE'
else:
role = 'unknown'
self.logger.debug('OFPRoleReply received: '
'role=%s short_id=%d, generation_id=%d',
role, msg.short_id, msg.generation_id)
"""
def __init__(self, datapath, role=None, short_id=None,
generation_id=None):
super(OFPRoleReply, self).__init__(datapath)
self.role = role
self.short_id = short_id
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.short_id, msg.generation_id) = struct.unpack_from(
ofproto.OFP_ROLE_REQUEST_PACK_STR, msg.buf,
ofproto.OFP_HEADER_SIZE)
return msg
class OFPAsyncConfigProp(OFPPropBase):
_TYPES = {}
@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_PACKET_IN_SLAVE)
@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_PACKET_IN_MASTER)
@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_PORT_STATUS_SLAVE)
@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_PORT_STATUS_MASTER)
@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_FLOW_REMOVED_SLAVE)
@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_FLOW_REMOVED_MASTER)
@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_ROLE_STATUS_SLAVE)
@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_ROLE_STATUS_MASTER)
@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_TABLE_STATUS_SLAVE)
@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_TABLE_STATUS_MASTER)
@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_REQUESTFORWARD_SLAVE)
@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_REQUESTFORWARD_MASTER)
class OFPAsyncConfigPropReasons(OFPAsyncConfigProp):
def __init__(self, type_=None, length=None, mask=None):
self.type = type_
self.length = length
self.mask = mask
@classmethod
def parser(cls, buf):
reasons = cls()
(reasons.type, reasons.length, reasons.mask) = struct.unpack_from(
ofproto.OFP_ASYNC_CONFIG_PROP_REASONS_PACK_STR, buf, 0)
return reasons
def serialize(self):
# fixup
self.length = ofproto.OFP_ASYNC_CONFIG_PROP_REASONS_SIZE
buf = bytearray()
msg_pack_into(ofproto.OFP_ASYNC_CONFIG_PROP_REASONS_PACK_STR, buf, 0,
self.type, self.length, self.mask)
return buf
@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_EXPERIMENTER_SLAVE)
@OFPAsyncConfigProp.register_type(ofproto.OFPACPT_EXPERIMENTER_MASTER)
class OFPAsyncConfigPropExperimenter(OFPPropCommonExperimenter4ByteData):
pass
@_set_msg_type(ofproto.OFPT_GET_ASYNC_REQUEST)
class OFPGetAsyncRequest(MsgBase):
"""
Get asynchronous configuration request message
The controller uses this message to query the asynchronous message.
Example::
def send_get_async_request(self, datapath):
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPGetAsyncRequest(datapath)
datapath.send_msg(req)
"""
def __init__(self, datapath):
super(OFPGetAsyncRequest, self).__init__(datapath)
@_register_parser
@_set_msg_type(ofproto.OFPT_GET_ASYNC_REPLY)
class OFPGetAsyncReply(MsgBase):
"""
Get asynchronous configuration reply message
The switch responds with this message to a get asynchronous configuration
request.
================== ====================================================
Attribute Description
================== ====================================================
properties List of ``OFPAsyncConfigProp`` subclass instances
================== ====================================================
Example::
@set_ev_cls(ofp_event.EventOFPGetAsyncReply, MAIN_DISPATCHER)
def get_async_reply_handler(self, ev):
msg = ev.msg
self.logger.debug('OFPGetAsyncReply received: '
'properties=%s', repr(msg.properties))
"""
def __init__(self, datapath, properties=None):
super(OFPGetAsyncReply, self).__init__(datapath)
self.properties = properties
@classmethod
def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
msg = super(OFPGetAsyncReply, cls).parser(datapath, version,
msg_type, msg_len,
xid, buf)
msg.properties = []
rest = msg.buf[ofproto.OFP_HEADER_SIZE:]
while rest:
p, rest = OFPAsyncConfigProp.parse(rest)
msg.properties.append(p)
return msg
@_set_msg_type(ofproto.OFPT_SET_ASYNC)
class OFPSetAsync(MsgBase):
"""
Set asynchronous configuration message
The controller sends this message to set the asynchronous messages that
it wants to receive on a given OpneFlow channel.
================== ====================================================
Attribute Description
================== ====================================================
properties List of ``OFPAsyncConfigProp`` subclass instances
================== ====================================================
Example::
def send_set_async(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
properties = [
ofp_parser.OFPAsyncConfigPropReasons(
ofp.OFPACPT_PACKET_IN_SLAVE, 8,
(1 << ofp.OFPR_APPLY_ACTION
| 1 << ofp.OFPR_INVALID_TTL))]
req = ofp_parser.OFPSetAsync(datapath, properties)
datapath.send_msg(req)
"""
def __init__(self, datapath, properties=None):
super(OFPSetAsync, self).__init__(datapath)
self.properties = properties
def _serialize_body(self):
bin_props = bytearray()
for p in self.properties:
bin_props += p.serialize()
self.buf += bin_props
@_register_parser
@_set_msg_type(ofproto.OFPT_BUNDLE_CONTROL)
class OFPBundleCtrlMsg(MsgBase):
"""
Bundle control message
The controller uses this message to create, destroy and commit bundles
================ ======================================================
Attribute Description
================ ======================================================
bundle_id Id of the bundle
type One of the following values.
| OFPBCT_OPEN_REQUEST
| OFPBCT_OPEN_REPLY
| OFPBCT_CLOSE_REQUEST
| OFPBCT_CLOSE_REPLY
| OFPBCT_COMMIT_REQUEST
| OFPBCT_COMMIT_REPLY
| OFPBCT_DISCARD_REQUEST
| OFPBCT_DISCARD_REPLY
flags Bitmap of the following flags.
| OFPBF_ATOMIC
| OFPBF_ORDERED
properties List of ``OFPBundleProp`` subclass instance
================ ======================================================
Example::
def send_bundle_control(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPBundleCtrlMsg(datapath, 7,
ofp.OFPBCT_OPEN_REQUEST,
ofp.OFPBF_ATOMIC, [])
datapath.send_msg(req)
"""
def __init__(self, datapath, bundle_id=None, type_=None, flags=None,
properties=None):
super(OFPBundleCtrlMsg, self).__init__(datapath)
self.bundle_id = bundle_id
self.type = type_
self.flags = flags
self.properties = properties
def _serialize_body(self):
bin_props = bytearray()
for p in self.properties:
bin_props += p.serialize()
msg_pack_into(ofproto.OFP_BUNDLE_CTRL_MSG_PACK_STR,
self.buf, ofproto.OFP_HEADER_SIZE, self.bundle_id,
self.type, self.flags)
self.buf += bin_props
@classmethod
def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
msg = super(OFPBundleCtrlMsg, cls).parser(datapath, version,
msg_type, msg_len,
xid, buf)
(bundle_id, type_, flags) = struct.unpack_from(
ofproto.OFP_BUNDLE_CTRL_MSG_PACK_STR, buf,
ofproto.OFP_HEADER_SIZE)
msg.bundle_id = bundle_id
msg.type = type_
msg.flags = flags
msg.properties = []
rest = msg.buf[ofproto.OFP_BUNDLE_CTRL_MSG_SIZE:]
while rest:
p, rest = OFPBundleProp.parse(rest)
msg.properties.append(p)
return msg
@_set_msg_type(ofproto.OFPT_BUNDLE_ADD_MESSAGE)
class OFPBundleAddMsg(MsgInMsgBase):
"""
Bundle add message
The controller uses this message to add a message to a bundle
================ ======================================================
Attribute Description
================ ======================================================
bundle_id Id of the bundle
flags Bitmap of the following flags.
| OFPBF_ATOMIC
| OFPBF_ORDERED
message ``MsgBase`` subclass instance
properties List of ``OFPBundleProp`` subclass instance
================ ======================================================
Example::
def send_bundle_add_message(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
msg = ofp_parser.OFPRoleRequest(datapath, ofp.OFPCR_ROLE_EQUAL, 0)
req = ofp_parser.OFPBundleAddMsg(datapath, 7, ofp.OFPBF_ATOMIC,
msg, [])
datapath.send_msg(req)
"""
def __init__(self, datapath, bundle_id, flags, message, properties):
super(OFPBundleAddMsg, self).__init__(datapath)
self.bundle_id = bundle_id
self.flags = flags
self.message = message
self.properties = properties
def _serialize_body(self):
# The xid of the inner message must be the same as
# that of the outer message (OF1.4.0 7.3.9.2)
if self.message.xid != self.xid:
self.message.set_xid(self.xid)
# Message
self.message.serialize()
tail_buf = self.message.buf
# Pad
if len(self.properties) > 0:
message_len = len(tail_buf)
pad_len = utils.round_up(message_len, 8) - message_len
msg_pack_into("%dx" % pad_len, tail_buf, message_len)
# Properties
for p in self.properties:
tail_buf += p.serialize()
# Head
msg_pack_into(ofproto.OFP_BUNDLE_ADD_MSG_0_PACK_STR,
self.buf, ofproto.OFP_HEADER_SIZE, self.bundle_id,
self.flags)
# Finish
self.buf += tail_buf
nx_actions.generate(
'os_ken.ofproto.ofproto_v1_5',
'os_ken.ofproto.ofproto_v1_5_parser'
)