# Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. # Copyright (C) 2015 YAMAMOTO Takashi # # 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. import struct from os_ken import utils from os_ken.lib import type_desc from os_ken.ofproto import nicira_ext from os_ken.ofproto import ofproto_common from os_ken.lib.pack_utils import msg_pack_into from os_ken.ofproto.ofproto_parser import StringifyMixin def generate(ofp_name, ofpp_name): import sys ofp = sys.modules[ofp_name] ofpp = sys.modules[ofpp_name] class _NXFlowSpec(StringifyMixin): _hdr_fmt_str = '!H' # 2 bit 0s, 1 bit src, 2 bit dst, 11 bit n_bits _dst_type = None _subclasses = {} _TYPE = { 'nx-flow-spec-field': [ 'src', 'dst', ] } def __init__(self, src, dst, n_bits): self.src = src self.dst = dst self.n_bits = n_bits @classmethod def register(cls, subcls): assert issubclass(subcls, cls) assert subcls._dst_type not in cls._subclasses cls._subclasses[subcls._dst_type] = subcls @classmethod def parse(cls, buf): (hdr,) = struct.unpack_from(cls._hdr_fmt_str, buf, 0) rest = buf[struct.calcsize(cls._hdr_fmt_str):] if hdr == 0: return None, rest # all-0 header is no-op for padding src_type = (hdr >> 13) & 0x1 dst_type = (hdr >> 11) & 0x3 n_bits = hdr & 0x3ff subcls = cls._subclasses[dst_type] if src_type == 0: # subfield src = cls._parse_subfield(rest) rest = rest[6:] elif src_type == 1: # immediate src_len = (n_bits + 15) // 16 * 2 src_bin = rest[:src_len] src = type_desc.IntDescr(size=src_len).to_user(src_bin) rest = rest[src_len:] if dst_type == 0: # match dst = cls._parse_subfield(rest) rest = rest[6:] elif dst_type == 1: # load dst = cls._parse_subfield(rest) rest = rest[6:] elif dst_type == 2: # output dst = '' # empty return subcls(src=src, dst=dst, n_bits=n_bits), rest def serialize(self): buf = bytearray() if isinstance(self.src, tuple): src_type = 0 # subfield else: src_type = 1 # immediate # header val = (src_type << 13) | (self._dst_type << 11) | self.n_bits msg_pack_into(self._hdr_fmt_str, buf, 0, val) # src if src_type == 0: # subfield buf += self._serialize_subfield(self.src) elif src_type == 1: # immediate src_len = (self.n_bits + 15) // 16 * 2 buf += type_desc.IntDescr(size=src_len).from_user(self.src) # dst if self._dst_type == 0: # match buf += self._serialize_subfield(self.dst) elif self._dst_type == 1: # load buf += self._serialize_subfield(self.dst) elif self._dst_type == 2: # output pass # empty return buf @staticmethod def _parse_subfield(buf): (n, len) = ofp.oxm_parse_header(buf, 0) assert len == 4 # only 4-bytes NXM/OXM are defined field = ofp.oxm_to_user_header(n) rest = buf[len:] (ofs,) = struct.unpack_from('!H', rest, 0) return (field, ofs) @staticmethod def _serialize_subfield(subfield): (field, ofs) = subfield buf = bytearray() n = ofp.oxm_from_user_header(field) ofp.oxm_serialize_header(n, buf, 0) assert len(buf) == 4 # only 4-bytes NXM/OXM are defined msg_pack_into('!H', buf, 4, ofs) return buf class NXFlowSpecMatch(_NXFlowSpec): """ Specification for adding match criterion This class is used by ``NXActionLearn``. For the usage of this class, please refer to ``NXActionLearn``. ================ ====================================================== Attribute Description ================ ====================================================== src OXM/NXM header and Start bit for source field dst OXM/NXM header and Start bit for destination field n_bits The number of bits from the start bit ================ ====================================================== """ # Add a match criteria # an example of the corresponding ovs-ofctl syntax: # NXM_OF_VLAN_TCI[0..11] _dst_type = 0 class NXFlowSpecLoad(_NXFlowSpec): """ Add NXAST_REG_LOAD actions This class is used by ``NXActionLearn``. For the usage of this class, please refer to ``NXActionLearn``. ================ ====================================================== Attribute Description ================ ====================================================== src OXM/NXM header and Start bit for source field dst OXM/NXM header and Start bit for destination field n_bits The number of bits from the start bit ================ ====================================================== """ # Add NXAST_REG_LOAD actions # an example of the corresponding ovs-ofctl syntax: # NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[] _dst_type = 1 class NXFlowSpecOutput(_NXFlowSpec): """ Add an OFPAT_OUTPUT action This class is used by ``NXActionLearn``. For the usage of this class, please refer to ``NXActionLearn``. ================ ====================================================== Attribute Description ================ ====================================================== src OXM/NXM header and Start bit for source field dst Must be '' n_bits The number of bits from the start bit ================ ====================================================== """ # Add an OFPAT_OUTPUT action # an example of the corresponding ovs-ofctl syntax: # output:NXM_OF_IN_PORT[] _dst_type = 2 def __init__(self, src, n_bits, dst=''): assert dst == '' super(NXFlowSpecOutput, self).__init__(src=src, dst=dst, n_bits=n_bits) class NXAction(ofpp.OFPActionExperimenter): _fmt_str = '!H' # subtype _subtypes = {} _experimenter = ofproto_common.NX_EXPERIMENTER_ID def __init__(self): super(NXAction, self).__init__(self._experimenter) self.subtype = self._subtype @classmethod def parse(cls, buf): fmt_str = NXAction._fmt_str (subtype,) = struct.unpack_from(fmt_str, buf, 0) subtype_cls = cls._subtypes.get(subtype) rest = buf[struct.calcsize(fmt_str):] if subtype_cls is None: return NXActionUnknown(subtype, rest) return subtype_cls.parser(rest) def serialize(self, buf, offset): data = self.serialize_body() payload_offset = ( ofp.OFP_ACTION_EXPERIMENTER_HEADER_SIZE + struct.calcsize(NXAction._fmt_str) ) self.len = utils.round_up(payload_offset + len(data), 8) super(NXAction, self).serialize(buf, offset) msg_pack_into(NXAction._fmt_str, buf, offset + ofp.OFP_ACTION_EXPERIMENTER_HEADER_SIZE, self.subtype) buf += data @classmethod def register(cls, subtype_cls): assert subtype_cls._subtype is not cls._subtypes cls._subtypes[subtype_cls._subtype] = subtype_cls class NXActionUnknown(NXAction): def __init__(self, subtype, data=None, type_=None, len_=None, experimenter=None): self._subtype = subtype super(NXActionUnknown, self).__init__() self.data = data @classmethod def parser(cls, buf): return cls(data=buf) def serialize_body(self): # fixup return bytearray() if self.data is None else self.data # For OpenFlow1.0 only class NXActionSetQueue(NXAction): r""" Set queue action This action sets the queue that should be used to queue when packets are output. And equivalent to the followings action of ovs-ofctl command. .. set_queue:queue .. +-------------------------+ | **set_queue**\:\ *queue*| +-------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== queue_id Queue ID for the packets ================ ====================================================== .. note:: This actions is supported by ``OFPActionSetQueue`` in OpenFlow1.2 or later. Example:: actions += [parser.NXActionSetQueue(queue_id=10)] """ _subtype = nicira_ext.NXAST_SET_QUEUE # queue_id _fmt_str = '!2xI' def __init__(self, queue_id, type_=None, len_=None, vendor=None, subtype=None): super(NXActionSetQueue, self).__init__() self.queue_id = queue_id @classmethod def parser(cls, buf): (queue_id,) = struct.unpack_from(cls._fmt_str, buf, 0) return cls(queue_id) def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0, self.queue_id) return data class NXActionPopQueue(NXAction): """ Pop queue action This action restors the queue to the value it was before any set_queue actions were applied. And equivalent to the followings action of ovs-ofctl command. .. pop_queue .. +---------------+ | **pop_queue** | +---------------+ Example:: actions += [parser.NXActionPopQueue()] """ _subtype = nicira_ext.NXAST_POP_QUEUE _fmt_str = '!6x' def __init__(self, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionPopQueue, self).__init__() @classmethod def parser(cls, buf): return cls() def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0) return data class NXActionRegLoad(NXAction): r""" Load literal value action This action loads a literal value into a field or part of a field. And equivalent to the followings action of ovs-ofctl command. .. load:value->dst[start..end] .. +-----------------------------------------------------------------+ | **load**\:\ *value*\->\ *dst*\ **[**\ *start*\..\ *end*\ **]** | +-----------------------------------------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== ofs_nbits Start and End for the OXM/NXM field. Setting method refer to the ``nicira_ext.ofs_nbits`` dst OXM/NXM header for destination field value OXM/NXM value to be loaded ================ ====================================================== Example:: actions += [parser.NXActionRegLoad( ofs_nbits=nicira_ext.ofs_nbits(4, 31), dst="eth_dst", value=0x112233)] """ _subtype = nicira_ext.NXAST_REG_LOAD _fmt_str = '!HIQ' # ofs_nbits, dst, value _TYPE = { 'ascii': [ 'dst', ] } def __init__(self, ofs_nbits, dst, value, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionRegLoad, self).__init__() self.ofs_nbits = ofs_nbits self.dst = dst self.value = value @classmethod def parser(cls, buf): (ofs_nbits, dst, value,) = struct.unpack_from( cls._fmt_str, buf, 0) # Right-shift instead of using oxm_parse_header for simplicity... dst_name = ofp.oxm_to_user_header(dst >> 9) return cls(ofs_nbits, dst_name, value) def serialize_body(self): hdr_data = bytearray() n = ofp.oxm_from_user_header(self.dst) ofp.oxm_serialize_header(n, hdr_data, 0) (dst_num,) = struct.unpack_from('!I', bytes(hdr_data), 0) data = bytearray() msg_pack_into(self._fmt_str, data, 0, self.ofs_nbits, dst_num, self.value) return data class NXActionRegLoad2(NXAction): r""" Load literal value action This action loads a literal value into a field or part of a field. And equivalent to the followings action of ovs-ofctl command. .. set_field:value[/mask]->dst .. +------------------------------------------------------------+ | **set_field**\:\ *value*\ **[**\/\ *mask*\ **]**\->\ *dst* | +------------------------------------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== value OXM/NXM value to be loaded mask Mask for destination field dst OXM/NXM header for destination field ================ ====================================================== Example:: actions += [parser.NXActionRegLoad2(dst="tun_ipv4_src", value="192.168.10.0", mask="255.255.255.0")] """ _subtype = nicira_ext.NXAST_REG_LOAD2 _TYPE = { 'ascii': [ 'dst', 'value', ] } def __init__(self, dst, value, mask=None, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionRegLoad2, self).__init__() self.dst = dst self.value = value self.mask = mask @classmethod def parser(cls, buf): (n, uv, mask, _len) = ofp.oxm_parse(buf, 0) dst, value = ofp.oxm_to_user(n, uv, mask) if isinstance(value, (tuple, list)): return cls(dst, value[0], value[1]) else: return cls(dst, value, None) def serialize_body(self): data = bytearray() if self.mask is None: value = self.value else: value = (self.value, self.mask) self._TYPE['ascii'].append('mask') n, value, mask = ofp.oxm_from_user(self.dst, value) len_ = ofp.oxm_serialize(n, value, mask, data, 0) msg_pack_into("!%dx" % (14 - len_), data, len_) return data class NXActionNote(NXAction): r""" Note action This action does nothing at all. And equivalent to the followings action of ovs-ofctl command. .. note:[hh].. .. +-----------------------------------+ | **note**\:\ **[**\ *hh*\ **]**\.. | +-----------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== note A list of integer type values ================ ====================================================== Example:: actions += [parser.NXActionNote(note=[0xaa,0xbb,0xcc,0xdd])] """ _subtype = nicira_ext.NXAST_NOTE # note _fmt_str = '!%dB' # set the integer array in a note def __init__(self, note, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionNote, self).__init__() self.note = note @classmethod def parser(cls, buf): note = struct.unpack_from( cls._fmt_str % len(buf), buf, 0) return cls(list(note)) def serialize_body(self): assert isinstance(self.note, (tuple, list)) for n in self.note: assert isinstance(n, int) pad = (len(self.note) + nicira_ext.NX_ACTION_HEADER_0_SIZE) % 8 if pad: self.note += [0x0 for i in range(8 - pad)] note_len = len(self.note) data = bytearray() msg_pack_into(self._fmt_str % note_len, data, 0, *self.note) return data class _NXActionSetTunnelBase(NXAction): # _subtype, _fmt_str must be attributes of subclass. def __init__(self, tun_id, type_=None, len_=None, experimenter=None, subtype=None): super(_NXActionSetTunnelBase, self).__init__() self.tun_id = tun_id @classmethod def parser(cls, buf): (tun_id,) = struct.unpack_from( cls._fmt_str, buf, 0) return cls(tun_id) def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0, self.tun_id) return data class NXActionSetTunnel(_NXActionSetTunnelBase): r""" Set Tunnel action This action sets the identifier (such as GRE) to the specified id. And equivalent to the followings action of ovs-ofctl command. .. note:: This actions is supported by ``OFPActionSetField`` in OpenFlow1.2 or later. .. set_tunnel:id .. +------------------------+ | **set_tunnel**\:\ *id* | +------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== tun_id Tunnel ID(32bits) ================ ====================================================== Example:: actions += [parser.NXActionSetTunnel(tun_id=0xa)] """ _subtype = nicira_ext.NXAST_SET_TUNNEL # tun_id _fmt_str = '!2xI' class NXActionSetTunnel64(_NXActionSetTunnelBase): r""" Set Tunnel action This action outputs to a port that encapsulates the packet in a tunnel. And equivalent to the followings action of ovs-ofctl command. .. note:: This actions is supported by ``OFPActionSetField`` in OpenFlow1.2 or later. .. set_tunnel64:id .. +--------------------------+ | **set_tunnel64**\:\ *id* | +--------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== tun_id Tunnel ID(64bits) ================ ====================================================== Example:: actions += [parser.NXActionSetTunnel64(tun_id=0xa)] """ _subtype = nicira_ext.NXAST_SET_TUNNEL64 # tun_id _fmt_str = '!6xQ' class NXActionRegMove(NXAction): r""" Move register action This action copies the src to dst. And equivalent to the followings action of ovs-ofctl command. .. move:src[start..end]->dst[start..end] .. +--------------------------------------------------------+ | **move**\:\ *src*\ **[**\ *start*\..\ *end*\ **]**\->\ | | *dst*\ **[**\ *start*\..\ *end* \ **]** | +--------------------------------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== src_field OXM/NXM header for source field dst_field OXM/NXM header for destination field n_bits Number of bits src_ofs Starting bit offset in source dst_ofs Starting bit offset in destination ================ ====================================================== .. CAUTION:: **src_start**\ and \ **src_end**\ difference and \ **dst_start**\ and \ **dst_end**\ difference must be the same. Example:: actions += [parser.NXActionRegMove(src_field="reg0", dst_field="reg1", n_bits=5, src_ofs=0 dst_ofs=10)] """ _subtype = nicira_ext.NXAST_REG_MOVE _fmt_str = '!HHH' # n_bits, src_ofs, dst_ofs # Followed by OXM fields (src, dst) and padding to 8 bytes boundary _TYPE = { 'ascii': [ 'src_field', 'dst_field', ] } def __init__(self, src_field, dst_field, n_bits, src_ofs=0, dst_ofs=0, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionRegMove, self).__init__() self.n_bits = n_bits self.src_ofs = src_ofs self.dst_ofs = dst_ofs self.src_field = src_field self.dst_field = dst_field @classmethod def parser(cls, buf): (n_bits, src_ofs, dst_ofs,) = struct.unpack_from( cls._fmt_str, buf, 0) rest = buf[struct.calcsize(NXActionRegMove._fmt_str):] # src field (n, len) = ofp.oxm_parse_header(rest, 0) src_field = ofp.oxm_to_user_header(n) rest = rest[len:] # dst field (n, len) = ofp.oxm_parse_header(rest, 0) dst_field = ofp.oxm_to_user_header(n) rest = rest[len:] # ignore padding return cls(src_field, dst_field=dst_field, n_bits=n_bits, src_ofs=src_ofs, dst_ofs=dst_ofs) def serialize_body(self): # fixup data = bytearray() msg_pack_into(self._fmt_str, data, 0, self.n_bits, self.src_ofs, self.dst_ofs) # src field n = ofp.oxm_from_user_header(self.src_field) ofp.oxm_serialize_header(n, data, len(data)) # dst field n = ofp.oxm_from_user_header(self.dst_field) ofp.oxm_serialize_header(n, data, len(data)) return data class NXActionResubmit(NXAction): r""" Resubmit action This action searches one of the switch's flow tables. And equivalent to the followings action of ovs-ofctl command. .. resubmit:port .. +------------------------+ | **resubmit**\:\ *port* | +------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== in_port New in_port for checking flow table ================ ====================================================== Example:: actions += [parser.NXActionResubmit(in_port=8080)] """ _subtype = nicira_ext.NXAST_RESUBMIT # in_port _fmt_str = '!H4x' def __init__(self, in_port=0xfff8, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionResubmit, self).__init__() self.in_port = in_port @classmethod def parser(cls, buf): (in_port,) = struct.unpack_from( cls._fmt_str, buf, 0) return cls(in_port) def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0, self.in_port) return data class NXActionResubmitTable(NXAction): r""" Resubmit action This action searches one of the switch's flow tables. And equivalent to the followings action of ovs-ofctl command. .. resubmit([port],[table]) .. +------------------------------------------------+ | **resubmit(**\[\ *port*\]\,[\ *table*\]\ **)** | +------------------------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== in_port New in_port for checking flow table table_id Checking flow tables ================ ====================================================== Example:: actions += [parser.NXActionResubmitTable(in_port=8080, table_id=10)] """ _subtype = nicira_ext.NXAST_RESUBMIT_TABLE # in_port, table_id _fmt_str = '!HB3x' def __init__(self, in_port=0xfff8, table_id=0xff, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionResubmitTable, self).__init__() self.in_port = in_port self.table_id = table_id @classmethod def parser(cls, buf): (in_port, table_id) = struct.unpack_from( cls._fmt_str, buf, 0) return cls(in_port, table_id) def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0, self.in_port, self.table_id) return data class NXActionOutputReg(NXAction): r""" Add output action This action outputs the packet to the OpenFlow port number read from src. And equivalent to the followings action of ovs-ofctl command. .. output:src[start...end] .. +-------------------------------------------------------+ | **output**\:\ *src*\ **[**\ *start*\...\ *end*\ **]** | +-------------------------------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== ofs_nbits Start and End for the OXM/NXM field. Setting method refer to the ``nicira_ext.ofs_nbits`` src OXM/NXM header for source field max_len Max length to send to controller ================ ====================================================== Example:: actions += [parser.NXActionOutputReg( ofs_nbits=nicira_ext.ofs_nbits(4, 31), src="reg0", max_len=1024)] """ _subtype = nicira_ext.NXAST_OUTPUT_REG # ofs_nbits, src, max_len _fmt_str = '!H4sH6x' _TYPE = { 'ascii': [ 'src', ] } def __init__(self, ofs_nbits, src, max_len, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionOutputReg, self).__init__() self.ofs_nbits = ofs_nbits self.src = src self.max_len = max_len @classmethod def parser(cls, buf): (ofs_nbits, oxm_data, max_len) = struct.unpack_from( cls._fmt_str, buf, 0) (n, len_) = ofp.oxm_parse_header(oxm_data, 0) src = ofp.oxm_to_user_header(n) return cls(ofs_nbits, src, max_len) def serialize_body(self): data = bytearray() src = bytearray() oxm = ofp.oxm_from_user_header(self.src) ofp.oxm_serialize_header(oxm, src, 0), msg_pack_into(self._fmt_str, data, 0, self.ofs_nbits, bytes(src), self.max_len) return data class NXActionOutputReg2(NXAction): r""" Add output action This action outputs the packet to the OpenFlow port number read from src. And equivalent to the followings action of ovs-ofctl command. .. output:src[start...end] .. +-------------------------------------------------------+ | **output**\:\ *src*\ **[**\ *start*\...\ *end*\ **]** | +-------------------------------------------------------+ .. NOTE:: Like the ``NXActionOutputReg`` but organized so that there is room for a 64-bit experimenter OXM as 'src'. ================ ====================================================== Attribute Description ================ ====================================================== ofs_nbits Start and End for the OXM/NXM field. Setting method refer to the ``nicira_ext.ofs_nbits`` src OXM/NXM header for source field max_len Max length to send to controller ================ ====================================================== Example:: actions += [parser.NXActionOutputReg2( ofs_nbits=nicira_ext.ofs_nbits(4, 31), src="reg0", max_len=1024)] """ _subtype = nicira_ext.NXAST_OUTPUT_REG2 # ofs_nbits, src, max_len _fmt_str = '!HH4s' _TYPE = { 'ascii': [ 'src', ] } def __init__(self, ofs_nbits, src, max_len, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionOutputReg2, self).__init__() self.ofs_nbits = ofs_nbits self.src = src self.max_len = max_len @classmethod def parser(cls, buf): (ofs_nbits, max_len, oxm_data) = struct.unpack_from( cls._fmt_str, buf, 0) (n, len_) = ofp.oxm_parse_header(oxm_data, 0) src = ofp.oxm_to_user_header(n) return cls(ofs_nbits, src, max_len) def serialize_body(self): data = bytearray() oxm_data = bytearray() oxm = ofp.oxm_from_user_header(self.src) ofp.oxm_serialize_header(oxm, oxm_data, 0), msg_pack_into(self._fmt_str, data, 0, self.ofs_nbits, self.max_len, bytes(oxm_data)) offset = len(data) msg_pack_into("!%dx" % (14 - offset), data, offset) return data class NXActionLearn(NXAction): r""" Adds or modifies flow action This action adds or modifies a flow in OpenFlow table. And equivalent to the followings action of ovs-ofctl command. .. learn(argument[,argument]...) .. +---------------------------------------------------+ | **learn(**\ *argument*\[,\ *argument*\]...\ **)** | +---------------------------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== table_id The table in which the new flow should be inserted specs Adds a match criterion to the new flow Please use the ``NXFlowSpecMatch`` in order to set the following format .. field=value field[start..end]=src[start..end] field[start..end] .. | *field*\=\ *value* | *field*\ **[**\ *start*\..\ *end*\ **]**\ =\ *src*\ **[**\ *start*\..\ *end*\ **]** | *field*\ **[**\ *start*\..\ *end*\ **]** | Please use the ``NXFlowSpecLoad`` in order to set the following format .. load:value->dst[start..end] load:src[start..end]->dst[start..end] .. | **load**\:\ *value*\ **->**\ *dst*\ **[**\ *start*\..\ *end*\ **]** | **load**\:\ *src*\ **[**\ *start*\..\ *end*\ **] ->**\ *dst*\ **[**\ *start*\..\ *end*\ **]** | Please use the ``NXFlowSpecOutput`` in order to set the following format .. output:field[start..end] .. | **output:**\ field\ **[**\ *start*\..\ *end*\ **]** idle_timeout Idle time before discarding(seconds) hard_timeout Max time before discarding(seconds) priority Priority level of flow entry cookie Cookie for new flow flags send_flow_rem fin_idle_timeout Idle timeout after FIN(seconds) fin_hard_timeout Hard timeout after FIN(seconds) ================ ====================================================== .. CAUTION:: The arguments specify the flow's match fields, actions, and other properties, as follows. At least one match criterion and one action argument should ordinarily be specified. Example:: actions += [ parser.NXActionLearn(able_id=10, specs=[parser.NXFlowSpecMatch(src=0x800, dst=('eth_type_nxm', 0), n_bits=16), parser.NXFlowSpecMatch(src=('reg1', 1), dst=('reg2', 3), n_bits=5), parser.NXFlowSpecMatch(src=('reg3', 1), dst=('reg3', 1), n_bits=5), parser.NXFlowSpecLoad(src=0, dst=('reg4', 3), n_bits=5), parser.NXFlowSpecLoad(src=('reg5', 1), dst=('reg6', 3), n_bits=5), parser.NXFlowSpecOutput(src=('reg7', 1), dst="", n_bits=5)], idle_timeout=180, hard_timeout=300, priority=1, cookie=0x64, flags=ofproto.OFPFF_SEND_FLOW_REM, fin_idle_timeout=180, fin_hard_timeout=300)] """ _subtype = nicira_ext.NXAST_LEARN # idle_timeout, hard_timeout, priority, cookie, flags, # table_id, pad, fin_idle_timeout, fin_hard_timeout _fmt_str = '!HHHQHBxHH' # Followed by flow_mod_specs def __init__(self, table_id, specs, idle_timeout=0, hard_timeout=0, priority=ofp.OFP_DEFAULT_PRIORITY, cookie=0, flags=0, fin_idle_timeout=0, fin_hard_timeout=0, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionLearn, self).__init__() self.idle_timeout = idle_timeout self.hard_timeout = hard_timeout self.priority = priority self.cookie = cookie self.flags = flags self.table_id = table_id self.fin_idle_timeout = fin_idle_timeout self.fin_hard_timeout = fin_hard_timeout self.specs = specs @classmethod def parser(cls, buf): (idle_timeout, hard_timeout, priority, cookie, flags, table_id, fin_idle_timeout, fin_hard_timeout,) = struct.unpack_from( cls._fmt_str, buf, 0) rest = buf[struct.calcsize(cls._fmt_str):] # specs specs = [] while len(rest) > 0: spec, rest = _NXFlowSpec.parse(rest) if spec is None: continue specs.append(spec) return cls(idle_timeout=idle_timeout, hard_timeout=hard_timeout, priority=priority, cookie=cookie, flags=flags, table_id=table_id, fin_idle_timeout=fin_idle_timeout, fin_hard_timeout=fin_hard_timeout, specs=specs) def serialize_body(self): # fixup data = bytearray() msg_pack_into(self._fmt_str, data, 0, self.idle_timeout, self.hard_timeout, self.priority, self.cookie, self.flags, self.table_id, self.fin_idle_timeout, self.fin_hard_timeout) for spec in self.specs: data += spec.serialize() return data class NXActionExit(NXAction): """ Halt action This action causes OpenvSwitch to immediately halt execution of further actions. And equivalent to the followings action of ovs-ofctl command. .. exit .. +----------+ | **exit** | +----------+ Example:: actions += [parser.NXActionExit()] """ _subtype = nicira_ext.NXAST_EXIT _fmt_str = '!6x' def __init__(self, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionExit, self).__init__() @classmethod def parser(cls, buf): return cls() def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0) return data # For OpenFlow1.0 only class NXActionDecTtl(NXAction): """ Decrement IP TTL action This action decrements TTL of IPv4 packet or hop limit of IPv6 packet. And equivalent to the followings action of ovs-ofctl command. .. dec_ttl .. +-------------+ | **dec_ttl** | +-------------+ .. NOTE:: This actions is supported by ``OFPActionDecNwTtl`` in OpenFlow1.2 or later. Example:: actions += [parser.NXActionDecTtl()] """ _subtype = nicira_ext.NXAST_DEC_TTL _fmt_str = '!6x' def __init__(self, type_=None, len_=None, vendor=None, subtype=None): super(NXActionDecTtl, self).__init__() @classmethod def parser(cls, buf): return cls() def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0) return data class NXActionController(NXAction): r""" Send packet in message action This action sends the packet to the OpenFlow controller as a packet in message. And equivalent to the followings action of ovs-ofctl command. .. controller(key=value...) .. +----------------------------------------------+ | **controller(**\ *key*\=\ *value*\...\ **)** | +----------------------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== max_len Max length to send to controller controller_id Controller ID to send packet-in reason Reason for sending the message ================ ====================================================== Example:: actions += [ parser.NXActionController(max_len=1024, controller_id=1, reason=ofproto.OFPR_INVALID_TTL)] """ _subtype = nicira_ext.NXAST_CONTROLLER # max_len, controller_id, reason _fmt_str = '!HHBx' def __init__(self, max_len, controller_id, reason, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionController, self).__init__() self.max_len = max_len self.controller_id = controller_id self.reason = reason @classmethod def parser(cls, buf): (max_len, controller_id, reason) = struct.unpack_from( cls._fmt_str, buf) return cls(max_len, controller_id, reason) def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0, self.max_len, self.controller_id, self.reason) return data class NXActionController2(NXAction): r""" Send packet in message action This action sends the packet to the OpenFlow controller as a packet in message. And equivalent to the followings action of ovs-ofctl command. .. controller(key=value...) .. +----------------------------------------------+ | **controller(**\ *key*\=\ *value*\...\ **)** | +----------------------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== max_len Max length to send to controller controller_id Controller ID to send packet-in reason Reason for sending the message userdata Additional data to the controller in the packet-in message pause Flag to pause pipeline to resume later ================ ====================================================== Example:: actions += [ parser.NXActionController(max_len=1024, controller_id=1, reason=ofproto.OFPR_INVALID_TTL, userdata=[0xa,0xb,0xc], pause=True)] """ _subtype = nicira_ext.NXAST_CONTROLLER2 _fmt_str = '!6x' _PACK_STR = '!HH' def __init__(self, type_=None, len_=None, vendor=None, subtype=None, **kwargs): super(NXActionController2, self).__init__() for arg in kwargs: if arg in NXActionController2Prop._NAMES: setattr(self, arg, kwargs[arg]) @classmethod def parser(cls, buf): cls_data = {} offset = 6 buf_len = len(buf) while buf_len > offset: (type_, length) = struct.unpack_from(cls._PACK_STR, buf, offset) offset += 4 try: subcls = NXActionController2Prop._TYPES[type_] except KeyError: subcls = NXActionController2PropUnknown data, size = subcls.parser_prop(buf[offset:], length - 4) offset += size cls_data[subcls._arg_name] = data return cls(**cls_data) def serialize_body(self): body = bytearray() msg_pack_into(self._fmt_str, body, 0) prop_list = [] for arg in self.__dict__: if arg in NXActionController2Prop._NAMES: prop_list.append((NXActionController2Prop._NAMES[arg], self.__dict__[arg])) prop_list.sort(key=lambda x: x[0].type) for subcls, value in prop_list: body += subcls.serialize_prop(value) return body class NXActionController2Prop(object): _TYPES = {} _NAMES = {} @classmethod def register_type(cls, type_): def _register_type(subcls): subcls.type = type_ NXActionController2Prop._TYPES[type_] = subcls NXActionController2Prop._NAMES[subcls._arg_name] = subcls return subcls return _register_type class NXActionController2PropUnknown(NXActionController2Prop): @classmethod def parser_prop(cls, buf, length): size = 4 return buf, size @classmethod def serialize_prop(cls, argment): data = bytearray() return data @NXActionController2Prop.register_type(nicira_ext.NXAC2PT_MAX_LEN) class NXActionController2PropMaxLen(NXActionController2Prop): # max_len _fmt_str = "!H2x" _arg_name = "max_len" @classmethod def parser_prop(cls, buf, length): size = 4 (max_len,) = struct.unpack_from( cls._fmt_str, buf, 0) return max_len, size @classmethod def serialize_prop(cls, max_len): data = bytearray() msg_pack_into("!HHH2x", data, 0, nicira_ext.NXAC2PT_MAX_LEN, 8, max_len) return data @NXActionController2Prop.register_type(nicira_ext.NXAC2PT_CONTROLLER_ID) class NXActionController2PropControllerId(NXActionController2Prop): # controller_id _fmt_str = "!H2x" _arg_name = "controller_id" @classmethod def parser_prop(cls, buf, length): size = 4 (controller_id,) = struct.unpack_from( cls._fmt_str, buf, 0) return controller_id, size @classmethod def serialize_prop(cls, controller_id): data = bytearray() msg_pack_into("!HHH2x", data, 0, nicira_ext.NXAC2PT_CONTROLLER_ID, 8, controller_id) return data @NXActionController2Prop.register_type(nicira_ext.NXAC2PT_REASON) class NXActionController2PropReason(NXActionController2Prop): # reason _fmt_str = "!B3x" _arg_name = "reason" @classmethod def parser_prop(cls, buf, length): size = 4 (reason,) = struct.unpack_from( cls._fmt_str, buf, 0) return reason, size @classmethod def serialize_prop(cls, reason): data = bytearray() msg_pack_into("!HHB3x", data, 0, nicira_ext.NXAC2PT_REASON, 5, reason) return data @NXActionController2Prop.register_type(nicira_ext.NXAC2PT_USERDATA) class NXActionController2PropUserData(NXActionController2Prop): # userdata _fmt_str = "!B" _arg_name = "userdata" @classmethod def parser_prop(cls, buf, length): userdata = [] offset = 0 while offset < length: u = struct.unpack_from(cls._fmt_str, buf, offset) userdata.append(u[0]) offset += 1 user_size = utils.round_up(length, 4) if user_size > 4 and (user_size % 8) == 0: size = utils.round_up(length, 4) + 4 else: size = utils.round_up(length, 4) return userdata, size @classmethod def serialize_prop(cls, userdata): data = bytearray() user_buf = bytearray() user_offset = 0 for user in userdata: msg_pack_into('!B', user_buf, user_offset, user) user_offset += 1 msg_pack_into("!HH", data, 0, nicira_ext.NXAC2PT_USERDATA, 4 + user_offset) data += user_buf if user_offset > 4: user_len = utils.round_up(user_offset, 4) brank_size = 0 if (user_len % 8) == 0: brank_size = 4 msg_pack_into("!%dx" % (user_len - user_offset + brank_size), data, 4 + user_offset) else: user_len = utils.round_up(user_offset, 4) msg_pack_into("!%dx" % (user_len - user_offset), data, 4 + user_offset) return data @NXActionController2Prop.register_type(nicira_ext.NXAC2PT_PAUSE) class NXActionController2PropPause(NXActionController2Prop): _arg_name = "pause" @classmethod def parser_prop(cls, buf, length): pause = True size = 4 return pause, size @classmethod def serialize_prop(cls, pause): data = bytearray() msg_pack_into("!HH4x", data, 0, nicira_ext.NXAC2PT_PAUSE, 4) return data class NXActionDecTtlCntIds(NXAction): r""" Decrement TTL action This action decrements TTL of IPv4 packet or hop limits of IPv6 packet. And equivalent to the followings action of ovs-ofctl command. .. dec_ttl(id1[,id2]...) .. +-------------------------------------------+ | **dec_ttl(**\ *id1*\[,\ *id2*\]...\ **)** | +-------------------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== cnt_ids Controller ids ================ ====================================================== Example:: actions += [parser.NXActionDecTtlCntIds(cnt_ids=[1,2,3])] .. NOTE:: If you want to set the following ovs-ofctl command. Please use ``OFPActionDecNwTtl``. +-------------+ | **dec_ttl** | +-------------+ """ _subtype = nicira_ext.NXAST_DEC_TTL_CNT_IDS # controllers _fmt_str = '!H4x' _fmt_len = 6 def __init__(self, cnt_ids, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionDecTtlCntIds, self).__init__() self.cnt_ids = cnt_ids @classmethod def parser(cls, buf): (controllers,) = struct.unpack_from( cls._fmt_str, buf) offset = cls._fmt_len cnt_ids = [] for i in range(0, controllers): id_ = struct.unpack_from('!H', buf, offset) cnt_ids.append(id_[0]) offset += 2 return cls(cnt_ids) def serialize_body(self): assert isinstance(self.cnt_ids, (tuple, list)) for i in self.cnt_ids: assert isinstance(i, int) controllers = len(self.cnt_ids) data = bytearray() msg_pack_into(self._fmt_str, data, 0, controllers) offset = self._fmt_len for id_ in self.cnt_ids: msg_pack_into('!H', data, offset, id_) offset += 2 id_len = (utils.round_up(controllers, 4) - controllers) if id_len != 0: msg_pack_into('%dx' % id_len * 2, data, offset) return data # Use in only OpenFlow1.0 class NXActionMplsBase(NXAction): # ethertype _fmt_str = '!H4x' def __init__(self, ethertype, type_=None, len_=None, vendor=None, subtype=None): super(NXActionMplsBase, self).__init__() self.ethertype = ethertype @classmethod def parser(cls, buf): (ethertype,) = struct.unpack_from( cls._fmt_str, buf) return cls(ethertype) def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0, self.ethertype) return data # For OpenFlow1.0 only class NXActionPushMpls(NXActionMplsBase): r""" Push MPLS action This action pushes a new MPLS header to the packet. And equivalent to the followings action of ovs-ofctl command. .. push_mpls:ethertype .. +-------------------------------+ | **push_mpls**\:\ *ethertype* | +-------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== ethertype Ether type(The value must be either 0x8847 or 0x8848) ================ ====================================================== .. NOTE:: This actions is supported by ``OFPActionPushMpls`` in OpenFlow1.2 or later. Example:: match = parser.OFPMatch(dl_type=0x0800) actions += [parser.NXActionPushMpls(ethertype=0x8847)] """ _subtype = nicira_ext.NXAST_PUSH_MPLS # For OpenFlow1.0 only class NXActionPopMpls(NXActionMplsBase): r""" Pop MPLS action This action pops the MPLS header from the packet. And equivalent to the followings action of ovs-ofctl command. .. pop_mpls:ethertype .. +------------------------------+ | **pop_mpls**\:\ *ethertype* | +------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== ethertype Ether type ================ ====================================================== .. NOTE:: This actions is supported by ``OFPActionPopMpls`` in OpenFlow1.2 or later. Example:: match = parser.OFPMatch(dl_type=0x8847) actions += [parser.NXActionPushMpls(ethertype=0x0800)] """ _subtype = nicira_ext.NXAST_POP_MPLS # For OpenFlow1.0 only class NXActionSetMplsTtl(NXAction): r""" Set MPLS TTL action This action sets the MPLS TTL. And equivalent to the followings action of ovs-ofctl command. .. set_mpls_ttl:ttl .. +---------------------------+ | **set_mpls_ttl**\:\ *ttl* | +---------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== ttl MPLS TTL ================ ====================================================== .. NOTE:: This actions is supported by ``OFPActionSetMplsTtl`` in OpenFlow1.2 or later. Example:: actions += [parser.NXActionSetMplsTil(ttl=128)] """ _subtype = nicira_ext.NXAST_SET_MPLS_TTL # ethertype _fmt_str = '!B5x' def __init__(self, ttl, type_=None, len_=None, vendor=None, subtype=None): super(NXActionSetMplsTtl, self).__init__() self.ttl = ttl @classmethod def parser(cls, buf): (ttl,) = struct.unpack_from( cls._fmt_str, buf) return cls(ttl) def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0, self.ttl) return data # For OpenFlow1.0 only class NXActionDecMplsTtl(NXAction): """ Decrement MPLS TTL action This action decrements the MPLS TTL. And equivalent to the followings action of ovs-ofctl command. .. dec_mpls_ttl .. +------------------+ | **dec_mpls_ttl** | +------------------+ .. NOTE:: This actions is supported by ``OFPActionDecMplsTtl`` in OpenFlow1.2 or later. Example:: actions += [parser.NXActionDecMplsTil()] """ _subtype = nicira_ext.NXAST_DEC_MPLS_TTL # ethertype _fmt_str = '!6x' def __init__(self, type_=None, len_=None, vendor=None, subtype=None): super(NXActionDecMplsTtl, self).__init__() @classmethod def parser(cls, buf): return cls() def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0) return data # For OpenFlow1.0 only class NXActionSetMplsLabel(NXAction): r""" Set MPLS Lavel action This action sets the MPLS Label. And equivalent to the followings action of ovs-ofctl command. .. set_mpls_label:label .. +-------------------------------+ | **set_mpls_label**\:\ *label* | +-------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== label MPLS Label ================ ====================================================== .. NOTE:: This actions is supported by ``OFPActionSetField(mpls_label=label)`` in OpenFlow1.2 or later. Example:: actions += [parser.NXActionSetMplsLabel(label=0x10)] """ _subtype = nicira_ext.NXAST_SET_MPLS_LABEL # ethertype _fmt_str = '!2xI' def __init__(self, label, type_=None, len_=None, vendor=None, subtype=None): super(NXActionSetMplsLabel, self).__init__() self.label = label @classmethod def parser(cls, buf): (label,) = struct.unpack_from( cls._fmt_str, buf) return cls(label) def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0, self.label) return data # For OpenFlow1.0 only class NXActionSetMplsTc(NXAction): r""" Set MPLS Tc action This action sets the MPLS Tc. And equivalent to the followings action of ovs-ofctl command. .. set_mpls_tc:tc .. +-------------------------+ | **set_mpls_tc**\:\ *tc* | +-------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== tc MPLS Tc ================ ====================================================== .. NOTE:: This actions is supported by ``OFPActionSetField(mpls_label=tc)`` in OpenFlow1.2 or later. Example:: actions += [parser.NXActionSetMplsLabel(tc=0x10)] """ _subtype = nicira_ext.NXAST_SET_MPLS_TC # ethertype _fmt_str = '!B5x' def __init__(self, tc, type_=None, len_=None, vendor=None, subtype=None): super(NXActionSetMplsTc, self).__init__() self.tc = tc @classmethod def parser(cls, buf): (tc,) = struct.unpack_from( cls._fmt_str, buf) return cls(tc) def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0, self.tc) return data class NXActionStackBase(NXAction): # start, field, end _fmt_str = '!H4sH' _TYPE = { 'ascii': [ 'field', ] } def __init__(self, field, start, end, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionStackBase, self).__init__() self.field = field self.start = start self.end = end @classmethod def parser(cls, buf): (start, oxm_data, end) = struct.unpack_from( cls._fmt_str, buf, 0) (n, len_) = ofp.oxm_parse_header(oxm_data, 0) field = ofp.oxm_to_user_header(n) return cls(field, start, end) def serialize_body(self): data = bytearray() oxm_data = bytearray() oxm = ofp.oxm_from_user_header(self.field) ofp.oxm_serialize_header(oxm, oxm_data, 0) msg_pack_into(self._fmt_str, data, 0, self.start, bytes(oxm_data), self.end) offset = len(data) msg_pack_into("!%dx" % (12 - offset), data, offset) return data class NXActionStackPush(NXActionStackBase): r""" Push field action This action pushes field to top of the stack. And equivalent to the followings action of ovs-ofctl command. .. pop:dst[start...end] .. +----------------------------------------------------+ | **pop**\:\ *dst*\ **[**\ *start*\...\ *end*\ **]** | +----------------------------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== field OXM/NXM header for source field start Start bit for source field end End bit for source field ================ ====================================================== Example:: actions += [parser.NXActionStackPush(field="reg2", start=0, end=5)] """ _subtype = nicira_ext.NXAST_STACK_PUSH class NXActionStackPop(NXActionStackBase): r""" Pop field action This action pops field from top of the stack. And equivalent to the followings action of ovs-ofctl command. .. pop:src[start...end] .. +----------------------------------------------------+ | **pop**\:\ *src*\ **[**\ *start*\...\ *end*\ **]** | +----------------------------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== field OXM/NXM header for destination field start Start bit for destination field end End bit for destination field ================ ====================================================== Example:: actions += [parser.NXActionStackPop(field="reg2", start=0, end=5)] """ _subtype = nicira_ext.NXAST_STACK_POP class NXActionSample(NXAction): r""" Sample packets action This action samples packets and sends one sample for every sampled packet. And equivalent to the followings action of ovs-ofctl command. .. sample(argument[,argument]...) .. +----------------------------------------------------+ | **sample(**\ *argument*\[,\ *argument*\]...\ **)** | +----------------------------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== probability The number of sampled packets collector_set_id The unsigned 32-bit integer identifier of the set of sample collectors to send sampled packets to obs_domain_id The Unsigned 32-bit integer Observation Domain ID obs_point_id The unsigned 32-bit integer Observation Point ID ================ ====================================================== Example:: actions += [parser.NXActionSample(probability=3, collector_set_id=1, obs_domain_id=2, obs_point_id=3,)] """ _subtype = nicira_ext.NXAST_SAMPLE # probability, collector_set_id, obs_domain_id, obs_point_id _fmt_str = '!HIII' def __init__(self, probability, collector_set_id=0, obs_domain_id=0, obs_point_id=0, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionSample, self).__init__() self.probability = probability self.collector_set_id = collector_set_id self.obs_domain_id = obs_domain_id self.obs_point_id = obs_point_id @classmethod def parser(cls, buf): (probability, collector_set_id, obs_domain_id, obs_point_id) = struct.unpack_from( cls._fmt_str, buf, 0) return cls(probability, collector_set_id, obs_domain_id, obs_point_id) def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0, self.probability, self.collector_set_id, self.obs_domain_id, self.obs_point_id) return data class NXActionSample2(NXAction): r""" Sample packets action This action samples packets and sends one sample for every sampled packet. 'sampling_port' can be equal to ingress port or one of egress ports. And equivalent to the followings action of ovs-ofctl command. .. sample(argument[,argument]...) .. +----------------------------------------------------+ | **sample(**\ *argument*\[,\ *argument*\]...\ **)** | +----------------------------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== probability The number of sampled packets collector_set_id The unsigned 32-bit integer identifier of the set of sample collectors to send sampled packets to obs_domain_id The Unsigned 32-bit integer Observation Domain ID obs_point_id The unsigned 32-bit integer Observation Point ID sampling_port Sampling port number ================ ====================================================== Example:: actions += [parser.NXActionSample2(probability=3, collector_set_id=1, obs_domain_id=2, obs_point_id=3, sampling_port=8080)] """ _subtype = nicira_ext.NXAST_SAMPLE2 # probability, collector_set_id, obs_domain_id, # obs_point_id, sampling_port _fmt_str = '!HIIIH6x' def __init__(self, probability, collector_set_id=0, obs_domain_id=0, obs_point_id=0, sampling_port=0, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionSample2, self).__init__() self.probability = probability self.collector_set_id = collector_set_id self.obs_domain_id = obs_domain_id self.obs_point_id = obs_point_id self.sampling_port = sampling_port @classmethod def parser(cls, buf): (probability, collector_set_id, obs_domain_id, obs_point_id, sampling_port) = struct.unpack_from( cls._fmt_str, buf, 0) return cls(probability, collector_set_id, obs_domain_id, obs_point_id, sampling_port) def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0, self.probability, self.collector_set_id, self.obs_domain_id, self.obs_point_id, self.sampling_port) return data class NXActionFinTimeout(NXAction): r""" Change TCP timeout action This action changes the idle timeout or hard timeout or both, of this OpenFlow rule when the rule matches a TCP packet with the FIN or RST flag. And equivalent to the followings action of ovs-ofctl command. .. fin_timeout(argument[,argument]...) .. +---------------------------------------------------------+ | **fin_timeout(**\ *argument*\[,\ *argument*\]...\ **)** | +---------------------------------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== fin_idle_timeout Causes the flow to expire after the given number of seconds of inactivity fin_idle_timeout Causes the flow to expire after the given number of second, regardless of activity ================ ====================================================== Example:: match = parser.OFPMatch(ip_proto=6, eth_type=0x0800) actions += [parser.NXActionFinTimeout(fin_idle_timeout=30, fin_hard_timeout=60)] """ _subtype = nicira_ext.NXAST_FIN_TIMEOUT # fin_idle_timeout, fin_hard_timeout _fmt_str = '!HH2x' def __init__(self, fin_idle_timeout, fin_hard_timeout, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionFinTimeout, self).__init__() self.fin_idle_timeout = fin_idle_timeout self.fin_hard_timeout = fin_hard_timeout @classmethod def parser(cls, buf): (fin_idle_timeout, fin_hard_timeout) = struct.unpack_from( cls._fmt_str, buf, 0) return cls(fin_idle_timeout, fin_hard_timeout) def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0, self.fin_idle_timeout, self.fin_hard_timeout) return data class NXActionConjunction(NXAction): r""" Conjunctive matches action This action ties groups of individual OpenFlow flows into higher-level conjunctive flows. Please refer to the ovs-ofctl command manual for details. And equivalent to the followings action of ovs-ofctl command. .. conjunction(id,k/n) .. +--------------------------------------------------+ | **conjunction(**\ *id*\,\ *k*\ **/**\ *n*\ **)** | +--------------------------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== clause Number assigned to the flow's dimension n_clauses Specify the conjunctive flow's match condition id\_ Conjunction ID ================ ====================================================== Example:: actions += [parser.NXActionConjunction(clause=1, n_clauses=2, id_=10)] """ _subtype = nicira_ext.NXAST_CONJUNCTION # clause, n_clauses, id _fmt_str = '!BBI' def __init__(self, clause, n_clauses, id_, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionConjunction, self).__init__() self.clause = clause self.n_clauses = n_clauses self.id = id_ @classmethod def parser(cls, buf): (clause, n_clauses, id_,) = struct.unpack_from( cls._fmt_str, buf, 0) return cls(clause, n_clauses, id_) def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0, self.clause, self.n_clauses, self.id) return data class NXActionMultipath(NXAction): r""" Select multipath link action This action selects multipath link based on the specified parameters. Please refer to the ovs-ofctl command manual for details. And equivalent to the followings action of ovs-ofctl command. .. multipath(fields, basis, algorithm, n_links, arg, dst[start..end]) .. +-------------------------------------------------------------+ | **multipath(**\ *fields*\, \ *basis*\, \ *algorithm*\, | | *n_links*\, \ *arg*\, \ *dst*\[\ *start*\..\ *end*\]\ **)** | +-------------------------------------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== fields One of NX_HASH_FIELDS_* basis Universal hash parameter algorithm One of NX_MP_ALG_*. max_link Number of output links arg Algorithm-specific argument ofs_nbits Start and End for the OXM/NXM field. Setting method refer to the ``nicira_ext.ofs_nbits`` dst OXM/NXM header for source field ================ ====================================================== Example:: actions += [parser.NXActionMultipath( fields=nicira_ext.NX_HASH_FIELDS_SYMMETRIC_L4, basis=1024, algorithm=nicira_ext.NX_MP_ALG_HRW, max_link=5, arg=0, ofs_nbits=nicira_ext.ofs_nbits(4, 31), dst="reg2")] """ _subtype = nicira_ext.NXAST_MULTIPATH # fields, basis, algorithm, max_link, # arg, ofs_nbits, dst _fmt_str = '!HH2xHHI2xH4s' _TYPE = { 'ascii': [ 'dst', ] } def __init__(self, fields, basis, algorithm, max_link, arg, ofs_nbits, dst, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionMultipath, self).__init__() self.fields = fields self.basis = basis self.algorithm = algorithm self.max_link = max_link self.arg = arg self.ofs_nbits = ofs_nbits self.dst = dst @classmethod def parser(cls, buf): (fields, basis, algorithm, max_link, arg, ofs_nbits, oxm_data) = struct.unpack_from( cls._fmt_str, buf, 0) (n, len_) = ofp.oxm_parse_header(oxm_data, 0) dst = ofp.oxm_to_user_header(n) return cls(fields, basis, algorithm, max_link, arg, ofs_nbits, dst) def serialize_body(self): data = bytearray() dst = bytearray() oxm = ofp.oxm_from_user_header(self.dst) ofp.oxm_serialize_header(oxm, dst, 0), msg_pack_into(self._fmt_str, data, 0, self.fields, self.basis, self.algorithm, self.max_link, self.arg, self.ofs_nbits, bytes(dst)) return data class _NXActionBundleBase(NXAction): # algorithm, fields, basis, slave_type, n_slaves # ofs_nbits _fmt_str = '!HHHIHH' def __init__(self, algorithm, fields, basis, slave_type, n_slaves, ofs_nbits, dst, slaves): super(_NXActionBundleBase, self).__init__() self.len = utils.round_up( nicira_ext.NX_ACTION_BUNDLE_0_SIZE + len(slaves) * 2, 8) self.algorithm = algorithm self.fields = fields self.basis = basis self.slave_type = slave_type self.n_slaves = n_slaves self.ofs_nbits = ofs_nbits self.dst = dst assert isinstance(slaves, (list, tuple)) for s in slaves: assert isinstance(s, int) self.slaves = slaves @classmethod def parser(cls, buf): # Add dst ('I') to _fmt_str (algorithm, fields, basis, slave_type, n_slaves, ofs_nbits, dst) = struct.unpack_from( cls._fmt_str + 'I', buf, 0) offset = (nicira_ext.NX_ACTION_BUNDLE_0_SIZE - nicira_ext.NX_ACTION_HEADER_0_SIZE - 8) if dst != 0: (n, len_) = ofp.oxm_parse_header(buf, offset) dst = ofp.oxm_to_user_header(n) slave_offset = (nicira_ext.NX_ACTION_BUNDLE_0_SIZE - nicira_ext.NX_ACTION_HEADER_0_SIZE) slaves = [] for i in range(0, n_slaves): s = struct.unpack_from('!H', buf, slave_offset) slaves.append(s[0]) slave_offset += 2 return cls(algorithm, fields, basis, slave_type, n_slaves, ofs_nbits, dst, slaves) def serialize_body(self): data = bytearray() slave_offset = (nicira_ext.NX_ACTION_BUNDLE_0_SIZE - nicira_ext.NX_ACTION_HEADER_0_SIZE) self.n_slaves = len(self.slaves) for s in self.slaves: msg_pack_into('!H', data, slave_offset, s) slave_offset += 2 pad_len = (utils.round_up(self.n_slaves, 4) - self.n_slaves) if pad_len != 0: msg_pack_into('%dx' % pad_len * 2, data, slave_offset) msg_pack_into(self._fmt_str, data, 0, self.algorithm, self.fields, self.basis, self.slave_type, self.n_slaves, self.ofs_nbits) offset = (nicira_ext.NX_ACTION_BUNDLE_0_SIZE - nicira_ext.NX_ACTION_HEADER_0_SIZE - 8) if self.dst == 0: msg_pack_into('I', data, offset, self.dst) else: oxm_data = ofp.oxm_from_user_header(self.dst) ofp.oxm_serialize_header(oxm_data, data, offset) return data class NXActionBundle(_NXActionBundleBase): r""" Select bundle link action This action selects bundle link based on the specified parameters. Please refer to the ovs-ofctl command manual for details. And equivalent to the followings action of ovs-ofctl command. .. bundle(fields, basis, algorithm, slave_type, slaves:[ s1, s2,...]) .. +-----------------------------------------------------------+ | **bundle(**\ *fields*\, \ *basis*\, \ *algorithm*\, | | *slave_type*\, \ *slaves*\:[ \ *s1*\, \ *s2*\,...]\ **)** | +-----------------------------------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== algorithm One of NX_MP_ALG_*. fields One of NX_HASH_FIELDS_* basis Universal hash parameter slave_type Type of slaves(must be NXM_OF_IN_PORT) n_slaves Number of slaves ofs_nbits Start and End for the OXM/NXM field. (must be zero) dst OXM/NXM header for source field(must be zero) slaves List of slaves ================ ====================================================== Example:: actions += [parser.NXActionBundle( algorithm=nicira_ext.NX_MP_ALG_HRW, fields=nicira_ext.NX_HASH_FIELDS_ETH_SRC, basis=0, slave_type=nicira_ext.NXM_OF_IN_PORT, n_slaves=2, ofs_nbits=0, dst=0, slaves=[2, 3])] """ _subtype = nicira_ext.NXAST_BUNDLE def __init__(self, algorithm, fields, basis, slave_type, n_slaves, ofs_nbits, dst, slaves): # NXAST_BUNDLE actions should have 'sofs_nbits' and 'dst' zeroed. super(NXActionBundle, self).__init__( algorithm, fields, basis, slave_type, n_slaves, ofs_nbits=0, dst=0, slaves=slaves) class NXActionBundleLoad(_NXActionBundleBase): r""" Select bundle link action This action has the same behavior as the bundle action, with one exception. Please refer to the ovs-ofctl command manual for details. And equivalent to the followings action of ovs-ofctl command. .. bundle_load(fields, basis, algorithm, slave_type, dst[start..end], slaves:[ s1, s2,...]) .. +-----------------------------------------------------------+ | **bundle_load(**\ *fields*\, \ *basis*\, \ *algorithm*\, | | *slave_type*\, \ *dst*\[\ *start*\... \*emd*\], | | \ *slaves*\:[ \ *s1*\, \ *s2*\,...]\ **)** | | +-----------------------------------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== algorithm One of NX_MP_ALG_*. fields One of NX_HASH_FIELDS_* basis Universal hash parameter slave_type Type of slaves(must be NXM_OF_IN_PORT) n_slaves Number of slaves ofs_nbits Start and End for the OXM/NXM field. Setting method refer to the ``nicira_ext.ofs_nbits`` dst OXM/NXM header for source field slaves List of slaves ================ ====================================================== Example:: actions += [parser.NXActionBundleLoad( algorithm=nicira_ext.NX_MP_ALG_HRW, fields=nicira_ext.NX_HASH_FIELDS_ETH_SRC, basis=0, slave_type=nicira_ext.NXM_OF_IN_PORT, n_slaves=2, ofs_nbits=nicira_ext.ofs_nbits(4, 31), dst="reg0", slaves=[2, 3])] """ _subtype = nicira_ext.NXAST_BUNDLE_LOAD _TYPE = { 'ascii': [ 'dst', ] } def __init__(self, algorithm, fields, basis, slave_type, n_slaves, ofs_nbits, dst, slaves): super(NXActionBundleLoad, self).__init__( algorithm, fields, basis, slave_type, n_slaves, ofs_nbits, dst, slaves) class NXActionCT(NXAction): r""" Pass traffic to the connection tracker action This action sends the packet through the connection tracker. And equivalent to the followings action of ovs-ofctl command. .. ct(argument[,argument]...) .. +------------------------------------------------+ | **ct(**\ *argument*\[,\ *argument*\]...\ **)** | +------------------------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== flags Zero or more(Unspecified flag bits must be zero.) zone_src OXM/NXM header for source field zone_ofs_nbits Start and End for the OXM/NXM field. Setting method refer to the ``nicira_ext.ofs_nbits``. If you need set the Immediate value for zone, zone_src must be set to None or empty character string. recirc_table Recirculate to a specific table alg Well-known port number for the protocol actions Zero or more actions may immediately follow this action ================ ====================================================== .. NOTE:: If you set number to zone_src, Traceback occurs when you run the to_jsondict. Example:: match = parser.OFPMatch(eth_type=0x0800, ct_state=(0,32)) actions += [parser.NXActionCT( flags = 1, zone_src = "reg0", zone_ofs_nbits = nicira_ext.ofs_nbits(4, 31), recirc_table = 4, alg = 0, actions = [])] """ _subtype = nicira_ext.NXAST_CT # flags, zone_src, zone_ofs_nbits, recirc_table, # pad, alg _fmt_str = '!H4sHB3xH' _TYPE = { 'ascii': [ 'zone_src', ] } # Followed by actions def __init__(self, flags, zone_src, zone_ofs_nbits, recirc_table, alg, actions, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionCT, self).__init__() self.flags = flags self.zone_src = zone_src self.zone_ofs_nbits = zone_ofs_nbits self.recirc_table = recirc_table self.alg = alg self.actions = actions @classmethod def parser(cls, buf): (flags, oxm_data, zone_ofs_nbits, recirc_table, alg,) = struct.unpack_from( cls._fmt_str, buf, 0) rest = buf[struct.calcsize(cls._fmt_str):] # OXM/NXM field if oxm_data == b'\x00' * 4: zone_src = "" else: (n, len_) = ofp.oxm_parse_header(oxm_data, 0) zone_src = ofp.oxm_to_user_header(n) # actions actions = [] while len(rest) > 0: action = ofpp.OFPAction.parser(rest, 0) actions.append(action) rest = rest[action.len:] return cls(flags, zone_src, zone_ofs_nbits, recirc_table, alg, actions) def serialize_body(self): data = bytearray() # If zone_src is zero, zone_ofs_nbits is zone_imm if not self.zone_src: zone_src = b'\x00' * 4 elif isinstance(self.zone_src, int): zone_src = struct.pack("!I", self.zone_src) else: zone_src = bytearray() oxm = ofp.oxm_from_user_header(self.zone_src) ofp.oxm_serialize_header(oxm, zone_src, 0) msg_pack_into(self._fmt_str, data, 0, self.flags, bytes(zone_src), self.zone_ofs_nbits, self.recirc_table, self.alg) for a in self.actions: a.serialize(data, len(data)) return data class NXActionCTClear(NXAction): """ Clear connection tracking state action This action clears connection tracking state from packets. And equivalent to the followings action of ovs-ofctl command. .. ct_clear .. +--------------+ | **ct_clear** | +--------------+ Example:: actions += [parser.NXActionCTClear()] """ _subtype = nicira_ext.NXAST_CT_CLEAR _fmt_str = '!6x' def __init__(self, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionCTClear, self).__init__() @classmethod def parser(cls, buf): return cls() def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0) return data class NXActionNAT(NXAction): r""" Network address translation action This action sends the packet through the connection tracker. And equivalent to the followings action of ovs-ofctl command. .. NOTE:: The following command image does not exist in ovs-ofctl command manual and has been created from the command response. .. nat(src=ip_min-ip_max : proto_min-proto-max) .. +--------------------------------------------------+ | **nat(src**\=\ *ip_min*\ **-**\ *ip_max*\ **:** | | *proto_min*\ **-**\ *proto-max*\ **)** | +--------------------------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== flags Zero or more(Unspecified flag bits must be zero.) range_ipv4_min Range ipv4 address minimun range_ipv4_max Range ipv4 address maximun range_ipv6_min Range ipv6 address minimun range_ipv6_max Range ipv6 address maximun range_proto_min Range protocol minimum range_proto_max Range protocol maximun ================ ====================================================== .. CAUTION:: ``NXActionNAT`` must be defined in the actions in the ``NXActionCT``. Example:: match = parser.OFPMatch(eth_type=0x0800) actions += [ parser.NXActionCT( flags = 1, zone_src = "reg0", zone_ofs_nbits = nicira_ext.ofs_nbits(4, 31), recirc_table = 255, alg = 0, actions = [ parser.NXActionNAT( flags = 1, range_ipv4_min = "10.1.12.0", range_ipv4_max = "10.1.13.255", range_ipv6_min = "", range_ipv6_max = "", range_proto_min = 1, range_proto_max = 1023 ) ] ) ] """ _subtype = nicira_ext.NXAST_NAT # pad, flags, range_present _fmt_str = '!2xHH' # Followed by optional parameters _TYPE = { 'ascii': [ 'range_ipv4_max', 'range_ipv4_min', 'range_ipv6_max', 'range_ipv6_min', ] } def __init__(self, flags, range_ipv4_min='', range_ipv4_max='', range_ipv6_min='', range_ipv6_max='', range_proto_min=None, range_proto_max=None, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionNAT, self).__init__() self.flags = flags self.range_ipv4_min = range_ipv4_min self.range_ipv4_max = range_ipv4_max self.range_ipv6_min = range_ipv6_min self.range_ipv6_max = range_ipv6_max self.range_proto_min = range_proto_min self.range_proto_max = range_proto_max @classmethod def parser(cls, buf): (flags, range_present) = struct.unpack_from( cls._fmt_str, buf, 0) rest = buf[struct.calcsize(cls._fmt_str):] # optional parameters kwargs = dict() if range_present & nicira_ext.NX_NAT_RANGE_IPV4_MIN: kwargs['range_ipv4_min'] = type_desc.IPv4Addr.to_user(rest[:4]) rest = rest[4:] if range_present & nicira_ext.NX_NAT_RANGE_IPV4_MAX: kwargs['range_ipv4_max'] = type_desc.IPv4Addr.to_user(rest[:4]) rest = rest[4:] if range_present & nicira_ext.NX_NAT_RANGE_IPV6_MIN: kwargs['range_ipv6_min'] = ( type_desc.IPv6Addr.to_user(rest[:16])) rest = rest[16:] if range_present & nicira_ext.NX_NAT_RANGE_IPV6_MAX: kwargs['range_ipv6_max'] = ( type_desc.IPv6Addr.to_user(rest[:16])) rest = rest[16:] if range_present & nicira_ext.NX_NAT_RANGE_PROTO_MIN: kwargs['range_proto_min'] = type_desc.Int2.to_user(rest[:2]) rest = rest[2:] if range_present & nicira_ext.NX_NAT_RANGE_PROTO_MAX: kwargs['range_proto_max'] = type_desc.Int2.to_user(rest[:2]) return cls(flags, **kwargs) def serialize_body(self): # Pack optional parameters first, as range_present needs # to be calculated. optional_data = b'' range_present = 0 if self.range_ipv4_min != '': range_present |= nicira_ext.NX_NAT_RANGE_IPV4_MIN optional_data += type_desc.IPv4Addr.from_user( self.range_ipv4_min) if self.range_ipv4_max != '': range_present |= nicira_ext.NX_NAT_RANGE_IPV4_MAX optional_data += type_desc.IPv4Addr.from_user( self.range_ipv4_max) if self.range_ipv6_min != '': range_present |= nicira_ext.NX_NAT_RANGE_IPV6_MIN optional_data += type_desc.IPv6Addr.from_user( self.range_ipv6_min) if self.range_ipv6_max != '': range_present |= nicira_ext.NX_NAT_RANGE_IPV6_MAX optional_data += type_desc.IPv6Addr.from_user( self.range_ipv6_max) if self.range_proto_min is not None: range_present |= nicira_ext.NX_NAT_RANGE_PROTO_MIN optional_data += type_desc.Int2.from_user( self.range_proto_min) if self.range_proto_max is not None: range_present |= nicira_ext.NX_NAT_RANGE_PROTO_MAX optional_data += type_desc.Int2.from_user( self.range_proto_max) data = bytearray() msg_pack_into(self._fmt_str, data, 0, self.flags, range_present) msg_pack_into('!%ds' % len(optional_data), data, len(data), optional_data) return data class NXActionOutputTrunc(NXAction): r""" Truncate output action This action truncate a packet into the specified size and outputs it. And equivalent to the followings action of ovs-ofctl command. .. output(port=port,max_len=max_len) .. +--------------------------------------------------------------+ | **output(port**\=\ *port*\,\ **max_len**\=\ *max_len*\ **)** | +--------------------------------------------------------------+ ================ ====================================================== Attribute Description ================ ====================================================== port Output port max_len Max bytes to send ================ ====================================================== Example:: actions += [parser.NXActionOutputTrunc(port=8080, max_len=1024)] """ _subtype = nicira_ext.NXAST_OUTPUT_TRUNC # port, max_len _fmt_str = '!HI' def __init__(self, port, max_len, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionOutputTrunc, self).__init__() self.port = port self.max_len = max_len @classmethod def parser(cls, buf): (port, max_len) = struct.unpack_from( cls._fmt_str, buf, 0) return cls(port, max_len) def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0, self.port, self.max_len) return data class NXActionEncapEther(NXAction): """ Encap Ether This action encaps package with ethernet And equivalent to the followings action of ovs-ofctl command. :: encap(ethernet) Example:: actions += [parser.NXActionEncapEther()] """ _subtype = nicira_ext.NXAST_RAW_ENCAP _fmt_str = '!HI' def __init__(self, type_=None, len_=None, vendor=None, subtype=None): super(NXActionEncapEther, self).__init__() self.hdr_size = 0 self.new_pkt_type = 0x00000000 @classmethod def parser(cls, buf): return cls() def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0, self.hdr_size, self.new_pkt_type) return data class NXActionEncapNsh(NXAction): """ Encap nsh This action encaps package with nsh And equivalent to the followings action of ovs-ofctl command. :: encap(nsh(md_type=1)) Example:: actions += [parser.NXActionEncapNsh()] """ _subtype = nicira_ext.NXAST_RAW_ENCAP _fmt_str = '!HI' def __init__(self, type_=None, len_=None, vendor=None, subtype=None): super(NXActionEncapNsh, self).__init__() self.hdr_size = hdr_size self.new_pkt_type = 0x0001894F @classmethod def parser(cls, buf): return cls() def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0, self.hdr_size, self.new_pkt_type) return data class NXActionDecNshTtl(NXAction): """ Decrement NSH TTL action This action decrements the TTL in the Network Service Header(NSH). This action was added in OVS v2.9. And equivalent to the followings action of ovs-ofctl command. :: dec_nsh_ttl Example:: actions += [parser.NXActionDecNshTtl()] """ _subtype = nicira_ext.NXAST_DEC_NSH_TTL _fmt_str = '!6x' def __init__(self, type_=None, len_=None, vendor=None, subtype=None): super(NXActionDecNshTtl, self).__init__() @classmethod def parser(cls, buf): return cls() def serialize_body(self): data = bytearray() msg_pack_into(self._fmt_str, data, 0) return data def add_attr(k, v): v.__module__ = ofpp.__name__ # Necessary for stringify stuff setattr(ofpp, k, v) add_attr('NXAction', NXAction) add_attr('NXActionUnknown', NXActionUnknown) classes = [ 'NXActionSetQueue', 'NXActionPopQueue', 'NXActionRegLoad', 'NXActionRegLoad2', 'NXActionNote', 'NXActionSetTunnel', 'NXActionSetTunnel64', 'NXActionRegMove', 'NXActionResubmit', 'NXActionResubmitTable', 'NXActionOutputReg', 'NXActionOutputReg2', 'NXActionLearn', 'NXActionExit', 'NXActionDecTtl', 'NXActionController', 'NXActionController2', 'NXActionDecTtlCntIds', 'NXActionPushMpls', 'NXActionPopMpls', 'NXActionSetMplsTtl', 'NXActionDecMplsTtl', 'NXActionSetMplsLabel', 'NXActionSetMplsTc', 'NXActionStackPush', 'NXActionStackPop', 'NXActionSample', 'NXActionSample2', 'NXActionFinTimeout', 'NXActionConjunction', 'NXActionMultipath', 'NXActionBundle', 'NXActionBundleLoad', 'NXActionCT', 'NXActionCTClear', 'NXActionNAT', 'NXActionOutputTrunc', '_NXFlowSpec', # exported for testing 'NXFlowSpecMatch', 'NXFlowSpecLoad', 'NXFlowSpecOutput', 'NXActionEncapNsh', 'NXActionEncapEther', 'NXActionDecNshTtl', ] vars = locals() for name in classes: cls = vars[name] add_attr(name, cls) if issubclass(cls, NXAction): NXAction.register(cls) if issubclass(cls, _NXFlowSpec): _NXFlowSpec.register(cls)