# Copyright (C) 2012, 2013, 2014 Nippon Telegraph and Telephone Corporation. # Copyright (C) 2012, 2013 Isaku Yamahata # # 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 nicira_ext 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 def _register_exp_type(experimenter, exp_type): assert exp_type not in OFPExperimenter._subtypes def _wrapper(cls): OFPExperimenter._subtypes[(experimenter, exp_type)] = cls return cls return _wrapper @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 ============= ========================================================= """ _subtypes = {} 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:] if (msg.experimenter, msg.exp_type) in cls._subtypes: new_msg = cls._subtypes[ (msg.experimenter, msg.exp_type)].parser_subtype(msg) new_msg.set_headers(msg.version, msg.msg_type, msg.msg_len, msg.xid) new_msg.set_buf(msg.buf) return new_msg 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 `. .. 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) 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 `. """ 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 @_register_exp_type(ofproto_common.NX_EXPERIMENTER_ID, nicira_ext.NXT_SET_PACKET_IN_FORMAT) class NXTSetPacketInFormatMsg(OFPExperimenter): def __init__(self, datapath, packet_in_format): super(NXTSetPacketInFormatMsg, self).__init__( datapath, ofproto_common.NX_EXPERIMENTER_ID, nicira_ext.NXT_SET_PACKET_IN_FORMAT) self.packet_in_format = packet_in_format def _serialize_body(self): msg_pack_into(ofproto.OFP_EXPERIMENTER_HEADER_PACK_STR, self.buf, ofproto.OFP_HEADER_SIZE, self.experimenter, self.exp_type) msg_pack_into(nicira_ext.NX_SET_PACKET_IN_FORMAT_PACK_STR, self.buf, ofproto.OFP_EXPERIMENTER_HEADER_SIZE, self.packet_in_format) @classmethod def parser_subtype(cls, super_msg): packet_in_format = struct.unpack_from( nicira_ext.NX_SET_PACKET_IN_FORMAT_PACK_STR, super_msg.data)[0] msg = cls(super_msg.datapath, packet_in_format) msg.properties = [] return msg @_register_exp_type(ofproto_common.NX_EXPERIMENTER_ID, nicira_ext.NXT_PACKET_IN2) class NXTPacketIn2(OFPExperimenter): def __init__(self, datapath, properties=None): super(NXTPacketIn2, self).__init__( datapath, ofproto_common.NX_EXPERIMENTER_ID, nicira_ext.NXT_PACKET_IN2) self.properties = properties or [] self.data = None self.total_len = None self.buffer_id = None self.table_id = None self.cookie = None self.reason = None self.metadata = None self.userdata = None self.continuation = None def _serialize_body(self): bin_props = bytearray() for p in self.properties: bin_props += p.serialize() msg_pack_into(ofproto.OFP_EXPERIMENTER_HEADER_PACK_STR, self.buf, ofproto.OFP_HEADER_SIZE, self.experimenter, self.exp_type) self.buf += bin_props @classmethod def parser_subtype(cls, super_msg): msg = cls(super_msg.datapath) rest = super_msg.data while rest: p, rest = NXTPacketIn2Prop.parse(rest) msg.properties.append(p) msg._parse_property(p) return msg def _parse_property(self, p): if p.type == nicira_ext.NXPINT_PACKET: self.data = p.data # Note: here total_len is length of packet but not msg self.total_len = p.length elif p.type == nicira_ext.NXPINT_FULL_LEN: self.total_len = struct.unpack_from('!I', p.data)[0] elif p.type == nicira_ext.NXPINT_BUFFER_ID: self.buffer_id = struct.unpack_from('!I', p.data)[0] elif p.type == nicira_ext.NXPINT_TABLE_ID: self.table_id = struct.unpack_from('B', p.data)[0] elif p.type == nicira_ext.NXPINT_COOKIE: self.cookie = struct.unpack_from('!Q', p.data)[0] elif p.type == nicira_ext.NXPINT_REASON: self.reason = struct.unpack_from('!B', p.data)[0] elif p.type == nicira_ext.NXPINT_METADATA: self.metadata = p.data elif p.type == nicira_ext.NXPINT_USERDATA: self.userdata = p.data elif p.type == nicira_ext.NXPINT_CONTINUATION: self.continuation = p.data class NXTPacketIn2Prop(OFPPropBase): _TYPES = {} _PROP_TYPE = None def __init__(self, type_=None, length=None, data=None): super(NXTPacketIn2Prop, self).__init__(type_, length) self.data = data @classmethod def parse(cls, buf): (type_, length) = struct.unpack_from(cls._PACK_STR, buf, 0) rest = buf[utils.round_up(length, 8):] try: subcls = cls._TYPES[type_] except KeyError: subcls = OFPPropUnknown prop = subcls.sub_parser(buf, type, length) prop.type = type_ prop.length = length return prop, rest def serialize_body(self): return self.data @classmethod def sub_parser(cls, buf, type, length): p = cls(type, length - 4, buf[4:length]) return p @NXTPacketIn2Prop.register_type(nicira_ext.NXPINT_PACKET) class NXTPacketIn2PropPacket(NXTPacketIn2Prop): _PROP_TYPE = nicira_ext.NXPINT_PACKET @NXTPacketIn2Prop.register_type(nicira_ext.NXPINT_FULL_LEN) class NXTPacketIn2PropFullLen(NXTPacketIn2Prop): _PROP_TYPE = nicira_ext.NXPINT_FULL_LEN @NXTPacketIn2Prop.register_type(nicira_ext.NXPINT_BUFFER_ID) class NXTPacketIn2PropBufferId(NXTPacketIn2Prop): _PROP_TYPE = nicira_ext.NXPINT_BUFFER_ID @NXTPacketIn2Prop.register_type(nicira_ext.NXPINT_TABLE_ID) class NXTPacketIn2PropTableId(NXTPacketIn2Prop): _PROP_TYPE = nicira_ext.NXPINT_TABLE_ID @NXTPacketIn2Prop.register_type(nicira_ext.NXPINT_COOKIE) class NXTPacketIn2PropCookie(NXTPacketIn2Prop): _PROP_TYPE = nicira_ext.NXPINT_COOKIE @NXTPacketIn2Prop.register_type(nicira_ext.NXPINT_REASON) class NXTPacketIn2PropReason(NXTPacketIn2Prop): _PROP_TYPE = nicira_ext.NXPINT_REASON @NXTPacketIn2Prop.register_type(nicira_ext.NXPINT_METADATA) class NXTPacketIn2PropMetadata(NXTPacketIn2Prop): _PROP_TYPE = nicira_ext.NXPINT_METADATA @NXTPacketIn2Prop.register_type(nicira_ext.NXPINT_USERDATA) class NXTPacketIn2PropUserData(NXTPacketIn2Prop): _PROP_TYPE = nicira_ext.NXPINT_USERDATA @NXTPacketIn2Prop.register_type(nicira_ext.NXPINT_CONTINUATION) class NXTPacketIn2PropContinuation(NXTPacketIn2Prop): _PROP_TYPE = nicira_ext.NXPINT_CONTINUATION nx_actions.generate( 'os_ken.ofproto.ofproto_v1_5', 'os_ken.ofproto.ofproto_v1_5_parser' )