class TableStats(GenericStruct): """Body of reply to OFPST_TABLE request.""" table_id = UBInt8() #: Align to 32-bits. pad = Pad(3) name = Char(length=OFP_MAX_TABLE_NAME_LEN) wildcards = UBInt32(enum_ref=FlowWildCards) max_entries = UBInt32() active_count = UBInt32() count_lookup = UBInt64() count_matched = UBInt64() def __init__(self, table_id=None, name=None, wildcards=None, max_entries=None, active_count=None, count_lookup=None, count_matched=None): """Create a TableStats with the optional parameters below. Args: table_id (int): Identifier of table. Lower numbered tables are consulted first. name (str): Table name. wildcards (:class:`~pyof.v0x01.common.flow_match.FlowWildCards`): Bitmap of OFPFW_* wildcards that are supported by the table. max_entries (int): Max number of entries supported. active_count (int): Number of active entries. count_lookup (int): Number of packets looked up in table. count_matched (int): Number of packets that hit table. """ super().__init__() self.table_id = table_id self.name = name self.wildcards = wildcards self.max_entries = max_entries self.active_count = active_count self.count_lookup = count_lookup self.count_matched = count_matched
class BandStats(GenericStruct): """Band Statistics. Statistics for each meter band. """ packet_band_count = UBInt64() byte_band_count = UBInt64() def __init__(self, packet_band_count=None, byte_band_count=None): """Create a BandStats with the optional parameters below. Args: packet_band_count(int): Number of packets in band. byte_band_count(int): Number of bytes in band. """ super().__init__() self.packet_band_count = packet_band_count self.byte_band_count = byte_band_count
class InstructionWriteMetadata(Instruction): """Instruction structure for OFPIT_WRITE_METADATA.""" #: Align to 64-bits pad = Pad(4) #: Metadata value to write metadata = UBInt64() #: Metadata write bitmask metadata_mask = UBInt64() def __init__(self, metadata=0, metadata_mask=0): """Create InstructionWriteMetadata with the optional parameters below. Args: metadata (int): Metadata value to write. metadata_mask (int): Metadata write bitmask. """ super().__init__(InstructionType.OFPIT_WRITE_METADATA) self.metadata = metadata self.metadata_mask = metadata_mask
class AggregateStatsReply(GenericStruct): """Body of reply to OFPST_AGGREGATE request.""" packet_count = UBInt64() byte_count = UBInt64() flow_count = UBInt32() #: Align to 64 bits pad = Pad(4) def __init__(self, packet_count=None, byte_count=None, flow_count=None): """The constructor just assings parameters to object attributes. Args: packet_count (int): Number of packets in flows byte_count (int): Number of bytes in flows flow_count (int): Number of flows """ super().__init__() self.packet_count = packet_count self.byte_count = byte_count self.flow_count = flow_count
class AggregateStatsReply(GenericStruct): """Body of reply to OFPST_AGGREGATE request.""" packet_count = UBInt64() byte_count = UBInt64() flow_count = UBInt32() #: Align to 64 bits pad = Pad(4) def __init__(self, packet_count=None, byte_count=None, flow_count=None): """Create a AggregateStatsReply with the optional parameters below. Args: packet_count (int): Number of packets in flows byte_count (int): Number of bytes in flows flow_count (int): Number of flows """ super().__init__() self.packet_count = packet_count self.byte_count = byte_count self.flow_count = flow_count
class QueueStats(GenericStruct): """Implements the reply body of a port_no.""" port_no = UBInt32() queue_id = UBInt32() tx_bytes = UBInt64() tx_packets = UBInt64() tx_errors = UBInt64() duration_sec = UBInt32() duration_nsec = UBInt32() def __init__(self, port_no=None, queue_id=None, tx_bytes=None, tx_packets=None, tx_errors=None, duration_sec=None, duration_nsec=None): """Create a QueueStats with the optional parameters below. Args: port_no (:class:`int`, :class:`~pyof.v0x05.common.port.Port`): Port Number. queue_id (int): Queue ID. tx_bytes (int): Number of transmitted bytes. tx_packets (int): Number of transmitted packets. tx_errors (int): Number of packets dropped due to overrun. duration_sec (int): Time queue has been alive in seconds. duration_nsec (int): Time queue has been alive in nanoseconds beyond duration_sec. """ super().__init__() 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
class FlowStatsRequest(GenericStruct): """Body for ofp_stats_request of type OFPST_FLOW.""" table_id = UBInt8() #: Align to 32 bits. pad = Pad(3) out_port = UBInt32() out_group = UBInt32() pad2 = Pad(4) cookie = UBInt64() cookie_mask = UBInt64() match = Match() def __init__(self, table_id=Table.OFPTT_ALL, out_port=PortNo.OFPP_ANY, out_group=Group.OFPG_ANY, cookie=0, cookie_mask=0, match=None): """Create a FlowStatsRequest with the optional parameters below. Args: table_id (int): ID of table to read (from pyof_table_stats) 0xff for all tables or 0xfe for emergency. out_port (:class:`int`, :class:`~pyof.v0x05.common.port.PortNo`): Require matching entries to include this as an output port. A value of :attr:`.PortNo.OFPP_ANY` indicates no restriction. out_group: Require matching entries to include this as an output group. A value of :attr:`Group.OFPG_ANY` indicates no restriction. cookie: Requires matching entries to contain this cookie value cookie_mask: Mask used to restrict the cookie bits that must match. A value of 0 indicates no restriction. match (~pyof.v0x05.common.flow_match.Match): Fields to match. """ super().__init__() 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() if match is None else match
class PacketIn(GenericMessage): """Packet received on port (datapath -> controller).""" #: :class:`~.header.Header`: OpenFlow Header header = Header(message_type=Type.OFPT_PACKET_IN) #: ID assigned by datapath. buffer_id = UBInt32() #: Full length of frame. total_len = UBInt16() #: Reason packet is being sent (one of OFPR_*), reason = UBInt8(enum_ref=PacketInReason) #: ID of the table that was looked up. table_id = UBInt8() #: Cookie of the flow entry that was looked up. cookie = UBInt64() #: Packet metadata. Variable size. match = Match() #: Align to 64 bit + 16 bit pad = Pad(2) #: Ethernet frame whose length is inferred from header.length. #: The padding bytes preceding the Ethernet frame ensure that the IP #: header (if any) following the Ethernet header is 32-bit aligned. data = BinaryData() def __init__(self, xid=None, buffer_id=None, total_len=None, reason=None, table_id=None, cookie=None, match=None, data=b''): """Assign parameters to object attributes. Args: xid (int): Header's xid. buffer_id (int): ID assigned by datapath. total_len (int): Full length of frame. reason (PacketInReason): The reason why the packet is being sent table_id (int): ID of the table that was looked up cookie (int): Cookie of the flow entry that was looked up match (:class:`~.common.flow_match.Match`): Packet metadata. Variable size. data (bytes): Ethernet frame, halfway through 32-bit word, so the IP header is 32-bit aligned. The amount of data is inferred from the length field in the header. Because of padding, offsetof(struct ofp_packet_in, data) == sizeof(struct ofp_packet_in) - 2. """ super().__init__(xid) 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
class SwitchFeatures(GenericMessage): """Message sent by the switch device to the controller. This message is the response for a features_request message, sent by the controller to the switch device. The 'OFPT_FEATURES_REPLY' message inherits from this class, despite the strange name. """ header = Header(message_type=Type.OFPT_FEATURES_REPLY) datapath_id = UBInt64() n_buffers = UBInt32() n_tables = UBInt8() auxiliary_id = UBInt8() #: Align to 64-bits. pad = Pad(2) # Features capabilities = UBInt32(enum_ref=Capabilities) reserved = UBInt32() def __init__(self, xid=None, datapath_id=None, n_buffers=None, n_tables=None, auxiliary_id=None, capabilities=None, reserved=None): """The constructor just assings parameters to object attributes. Args: xid (int): xid to be used on the message header. datapath_id (int): Datapath unique ID. The lower 48-bits are for MAC address, while the upper 16-bits are implementer-defined. n_buffers (int): Max packets buffered at once. n_tables (int): Number of tables supported by datapath. auxiliary_id (int): Identify auxiliary connections. capabilities (int): bitmap of supported capabilities. reserved (int): Reserved. """ super().__init__(xid) self.datapath_id = datapath_id self.n_buffers = n_buffers self.n_tables = n_tables self.auxiliary_id = auxiliary_id self.capabilities = capabilities self.reserved = reserved
class FlowStatsRequest(GenericStruct): """Body for ofp_stats_request of type OFPST_FLOW.""" table_id = UBInt8() #: Align to 32 bits. pad = Pad(3) out_port = UBInt32() out_group = UBInt32() pad2 = Pad(4) cookie = UBInt64() cookie_mask = UBInt64() match = Match() def __init__(self, table_id=None, out_port=None, out_group=None, cookie=None, cookie_mask=None, match=None): """The constructor just assings parameters to object attributes. Args: table_id (int): ID of table to read (from pyof_table_stats) 0xff for all tables or 0xfe for emergency. out_port (:class:`int`, :class:`.Port`): Require matching entries to include this as an output port. A value of :attr:`.Port.OFPP_NONE` indicates no restriction. out_group: Require matching entries to include this as an output group. A value of OFPG_ANY indicates no restriction. cookie: Requires matching entries to contain this cookie value cookie_mask: Mask used to restrict the cookie bits that must match. A value of 0 indicates no restriction. match (Match): Fields to match. """ super().__init__() 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
class FlowMod(GenericMessage): """Modifies the flow table from the controller.""" header = Header(message_type=Type.OFPT_FLOW_MOD) match = Match() cookie = UBInt64() command = UBInt16(enum_ref=FlowModCommand) idle_timeout = UBInt16() hard_timeout = UBInt16() priority = UBInt16() buffer_id = UBInt32() out_port = UBInt16(enum_ref=Port) flags = UBInt16(enum_ref=FlowModFlags) actions = ListOfActions() def __init__(self, xid=None, match=None, cookie=0, command=None, idle_timeout=0, hard_timeout=0, priority=0, buffer_id=NO_BUFFER, out_port=Port.OFPP_NONE, flags=FlowModFlags.OFPFF_CHECK_OVERLAP, actions=None): """The constructor just assings parameters to object attributes. Args: xid (int): xid to be used on the message header. match (Match): Fields to match. cookie (int): Opaque controller-issued identifier. command (FlowModCommand): One of OFPFC_*. idle_timeout (int): Idle time before discarding (seconds). hard_timeout (int): Max time before discarding (seconds). priority (int): Priority level of flow entry. buffer_idle (int): Buffered packet to apply to (or -1). Not meaningful for OFPFC_DELETE*. out_port (Port): For OFPFC_DELETE* commands, require matching entries to include this as an output port. A value of OFPP_NONE indicates no restriction. flags (FlowModFlags): One of OFPFF_*. actions (ListOfActions): The action length is inferred from the length field in the header. """ super().__init__(xid) self.match = match self.cookie = cookie 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.flags = flags self.actions = [] if actions is None else actions
class RoleRequest(RoleBaseMessage): """RoleRequest Message. When the controller wants to change its role, it uses the OFPT_ROLE_REQUEST message. """ header = Header(message_type=Type.OFPT_ROLE_REQUEST) role = UBInt32(enum_ref=ControllerRole) pad = Pad(4) generation_id = UBInt64() def __init__(self, xid=None, role=None, generation_id=None): """Create a RoleRequest with the optional parameters below. Args: xid (int): OpenFlow xid to the header. role (:class:`~.controller2switch.common.ControllerRole`): Is the new role that the controller wants to assume. generation_id (int): Master Election Generation Id. """ super().__init__(xid, role, generation_id)
class RoleStatusMsg(GenericMessage): """OpenFlow Controller Role Status Message OFPT_ROLE_REQUEST. """ #: Type OFPT_ROLE_STATUS header = Header(message_type=Type.OFPT_ROLE_STATUS) #: One of OFPCR_ROLE_* role = UBInt32(enum_ref=ControllerRole) #: One of OFPCRR_*. reason = UBInt8(enum_ref=RoleReason) #: Align to 64 bits pad = Pad(3) #: Master Election Generation Id generation_id = UBInt64() #: Role Property list properties = ListOfRoleProperties() def __init__(self, xid=None, role=ControllerRole, reason=RoleReason, generation_id=None, properties=None): """Create a message with the optional parameters below. Args: xid (int): xid to be used on the message header. role (int): the new role of the controller reason (int): one of RoleReason generation_id (int): the generation ID that was included in the role request message that triggered the role change properties: a list of role properties, describing dynamic parameters of table configuration """ super().__init__() self.header.xid = xid self.role = role self.reason = reason self.generation_id = generation_id self.properties = properties if properties else []
class RoleBaseMessage(GenericMessage): """Role basic structure for RoleRequest and RoleReply messages.""" #: :class:`~.common.header.Header` #: Type OFPT_ROLE_REQUEST/OFPT_ROLE_REPLY. header = Header() #: One of NX_ROLE_*. (:class:`~.controller2switch.common.ControllerRole`) role = UBInt32(enum_ref=ControllerRole) #: Align to 64 bits. pad = Pad(4) #: Master Election Generation Id. generation_id = UBInt64() def __init__(self, xid=None, role=None, generation_id=None): """The constructor just assings parameters to object attributes. Args: xid (int): OpenFlow xid to the header. role (:class:`~.controller2switch.common.ControllerRole`): . generation_id (int): Master Election Generation Id. """ super().__init__(xid) self.role = role self.generation_id = generation_id
class PortStats(GenericStruct): """Body of reply to OFPST_PORT request. If a counter is unsupported, set the field to all ones. """ port_no = UBInt32() #: Align to 64-bits. pad = Pad(4) rx_packets = UBInt64() tx_packets = UBInt64() rx_bytes = UBInt64() tx_bytes = UBInt64() rx_dropped = UBInt64() tx_dropped = UBInt64() rx_errors = UBInt64() tx_errors = UBInt64() rx_frame_err = UBInt64() rx_over_err = UBInt64() rx_crc_err = UBInt64() collisions = UBInt64() duration_sec = UBInt32() duration_nsec = UBInt32() def __init__(self, port_no=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, rx_frame_err=None, rx_over_err=None, rx_crc_err=None, collisions=None, duration_sec=None, duration_nsec=None): """The constructor assigns parameters to object attributes. Args: port_no (:class:`int`, :class:`.Port`): Port number. rx_packets (int): Number of received packets. tx_packets (int): Number of transmitted packets. rx_bytes (int): Number of received bytes. tx_bytes (int): Number of transmitted bytes. rx_dropped (int): Number of packets dropped by RX. tx_dropped (int): Number of packets dropped by TX. rx_errors (int): Number of receive errors. This is a super-set of more specific receive errors and should be greater than or equal to the sum of all rx_*_err values. tx_errors (int): Number of transmit errors. This is a super-set of more specific transmit errors and should be greater than or equal to the sum of all tx_*_err values (none currently defined). rx_frame_err (int): Number of frame alignment errors. rx_over_err (int): Number of packets with RX overrun. rx_crc_err (int): Number of CRC errors. collisions (int): Number of collisions. duration_sec (int): Time port has been alive in seconds duration_nsec (int): Time port has been alive in nanoseconds beyond duration_sec """ super().__init__() self.port_no = port_no 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.rx_frame_err = rx_frame_err self.rx_over_err = rx_over_err self.rx_crc_err = rx_crc_err self.collisions = collisions self.duration_sec = duration_sec self.duration_nsec = duration_nsec
class FlowStats(GenericStruct): """Body of reply to OFPST_FLOW request.""" length = UBInt16() table_id = UBInt8() #: Align to 32 bits. pad = Pad(1) duration_sec = UBInt32() duration_nsec = UBInt32() priority = UBInt16() idle_timeout = UBInt16() hard_timeout = UBInt16() flags = UBInt16() importance = UBInt16() #: Align to 64-bits pad2 = Pad(2) cookie = UBInt64() packet_count = UBInt64() byte_count = UBInt64() match = Match() #: instructions = ListOfInstruction() def __init__(self, length=None, table_id=None, duration_sec=None, duration_nsec=None, priority=None, idle_timeout=None, hard_timeout=None, flags=None, importance=None, cookie=None, packet_count=None, byte_count=None, match=None): """Create a FlowStats with the optional parameters below. Args: length (int): Length of this entry. table_id (int): ID of table flow came from. duration_sec (int): Time flow has been alive in seconds. duration_nsec (int): Time flow has been alive in nanoseconds in addition to duration_sec. priority (int): Priority of the entry. Only meaningful when this is not an exact-match entry. idle_timeout (int): Number of seconds idle before expiration. hard_timeout (int): Number of seconds before expiration. flags (int): Bitmap of OFPFF_* flags. importance (int): Eviction precedence. cookie (int): Opaque controller-issued identifier. packet_count (int): Number of packets in flow. byte_count (int): Number of bytes in flow. match (~pyof.v0x05.common.flow_match.Match): Description of fields. """ super().__init__() self.length = length self.table_id = table_id self.duration_sec = duration_sec self.duration_nsec = duration_nsec self.priority = priority self.idle_timeout = idle_timeout self.hard_timeout = hard_timeout self.flags = flags self.importance = importance self.cookie = cookie self.packet_count = packet_count self.byte_count = byte_count self.match = match #: self.instructions = instructions or [] def unpack(self, buff, offset=0): """Unpack a binary message into this object's attributes. Pass the correct length for list unpacking. Args: buff (bytes): Binary data package to be unpacked. offset (int): Where to begin unpacking. """ unpack_length = UBInt16() unpack_length.unpack(buff, offset) super().unpack(buff[:offset + unpack_length], offset)
class TableFeatures(GenericStruct): """Abstraction of common class Table Features. Body for MultipartRequest of type OFPMP_TABLE_FEATURES. Body of reply to OFPMP_TABLE_FEATURES request. """ length = UBInt16() # /* Identifier of table. Lower numbered tables are consulted first. */ table_id = UBInt8() # /* Align to 64-bits. */ pad = Pad(5) name = Char(length=OFP_MAX_TABLE_NAME_LEN) # /* Bits of metadata table can match. */ metadata_match = UBInt64() # /* Bits of metadata table can write. */ metadata_write = UBInt64() # /* Bitmap of OFPTC_* values */ config = UBInt32() # /* Max number of entries supported. */ max_entries = UBInt32() # /* Table Feature Property list */ properties = ListOfProperty() def __init__(self, table_id=Table.OFPTT_ALL, name="", metadata_match=0xFFFFFFFFFFFFFFFF, metadata_write=0xFFFFFFFFFFFFFFFF, config=0, max_entries=0, properties=None): """Create a TableFeatures with the optional parameters below. Args: table_id(int): Indetifier of table.The default value OFPTT_ALL(``0xff``) will apply the configuration to all tables in the switch. name(Char): Characters representing the table name. metadata_match(int): Indicate the bits of the metadata field that the table can match on.The default value ``0xFFFFFFFFFFFFFFFF`` indicates that the table can match the full metadata field. metadata_write(int): Indicates the bits of the metadata field that the table can write using the OFPIT_WRITE_METADATA instruction. The default value ``0xFFFFFFFFFFFFFFFF`` indicates that the table can write the full metadata field. config(int): Field reseved for future use. max_entries(int): Describe the maximum number of flow entries that can be inserted into that table. properties(~pyof.v0x04.controller2switch.common.ListOfProperty): List of Property intances. """ super().__init__() self.table_id = table_id self.name = name self.metadata_match = metadata_match self.metadata_write = metadata_write self.config = config self.max_entries = max_entries self.properties = (ListOfProperty() if properties is None else properties) self.update_length() def pack(self, value=None): """Pack method used to update the length of instance and packing. Args: value: Structure to be packed. """ self.update_length() return super().pack(value) def update_length(self): """Update the length of current instance.""" self.length = self.get_size() def unpack(self, buff=None, offset=0): """Unpack *buff* into this object. This method will convert a binary data into a readable value according to the attribute format. Args: buff (bytes): Binary buffer. offset (int): Where to begin unpacking. Raises: :exc:`~.exceptions.UnpackException`: If unpack fails. """ length = UBInt16() length.unpack(buff, offset) super().unpack(buff[:offset+length.value], offset)
class FlowMod(GenericMessage): """Flow setup and teardown (controller -> datapath).""" header = Header(message_type=Type.OFPT_FLOW_MOD) #: Opaque controller-issued identifier. cookie = UBInt64() #: Mask used to restrict the cookie bits that must match when the command is #: OFPFC_MODIFY* or OFPFC_DELETE*. A value of 0 indicates no restriction. cookie_mask = UBInt64() #: ID of the table to put the flow in. For OFPFC_DELETE_* commands, OFPTT_ALL #: can also be used to delete matching flows from all tables. table_id = UBInt8() #: One of OFPFC_*. command = UBInt8(enum_ref=FlowModCommand) #: Idle time before discarding (seconds). idle_timeout = UBInt16() #: Max time before discarding (seconds). hard_timeout = UBInt16() #: Priority level of flow entry priority = UBInt16() #: Buffered packet to apply to, or OFP_NO_BUFFER. #: Not meaningful for OFPFC_DELETE*. buffer_id = UBInt32() #: For OFPFC_DELETE* commands, require matching entries to include this as an output port. #: A value of OFPP_ANY indicates no restrictions. out_port = UBInt32() #: For OFPFC_DELETE* commands, require matching entries to include this as an output group. #: A value of OFPP_ANY indicates no restrictions. out_group = UBInt32() #: Bitmap of OFPFF_* flags. flags = UBInt16(enum_ref=FlowModFlags) #: Eviction precedence (optional). importance = UBInt16() #: Fields to match. Variable size. match = Match() #: The variable size and padded match is always followed by instructions. #: Instruction set - 0 or more. The length of the instruction set is inferred from the length field in the header. #: instructions = ListOfInstruction() def __init__(self, xid=None, cookie=0, cookie_mask=0, table_id=0, command=None, idle_timeout=0, hard_timeout=0, priority=0, buffer_id=OFP_NO_BUFFER, out_port=PortNo.OFPP_ANY, out_group=Group.OFPG_ANY, flags=FlowModFlags.OFPFF_SEND_FLOW_REM, importance=None, match=None): """Create a FlowMod with the optional parameters below. Args: xid (int): xid to be used on the message header. cookie (int): Opaque controller-issued identifier. cookie_mask (int): Mask used to restrict the cookie bits that must match when the command is OFPFC_MODIFY* or OFPFC_DELETE*. A value of 0 indicates no restriction. table_id (int): ID of the table to put the flow in. For OFPFC_DELETE_* commands, OFPTT_ALL can also be used to delete matching flows from all tables. command (~pyof.v0x05.controller2switch.flow_mod.FlowModCommand): One of OFPFC_*. idle_timeout (int): Idle time before discarding (seconds). hard_timeout (int): Max time before discarding (seconds). priority (int): Priority level of flow entry. buffer_id (int): Buffered packet to apply to, or OFP_NO_BUFFER. Not meaningful for OFPFC_DELETE*. out_port (int): For OFPFC_DELETE* commands, require matching entries to include this as an output port. A value of OFPP_ANY indicates no restriction. out_group (int): For OFPFC_DELETE* commands, require matching entries to include this as an output group. A value of OFPG_ANY indicates no restriction. flags (~pyof.v0x05.controller2switch.flow_mod.FlowModFlags): One of OFPFF_*. importance (int): Eviction precedence (optional) match (~pyof.v0x05.common.flow_match.Match): Fields to match. Variable size. """ super().__init__(xid) 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 self.match = Match() if match is None else match
class PacketIn(GenericMessage): """Packet received on port (datapath -> controller).""" #: :class:`~pyof.v0x04.common.header.Header`: OpenFlow Header header = Header(message_type=Type.OFPT_PACKET_IN) #: ID assigned by datapath. buffer_id = UBInt32() #: Full length of frame. total_len = UBInt16() #: Reason packet is being sent (one of OFPR_*), reason = UBInt8(enum_ref=PacketInReason) #: ID of the table that was looked up. table_id = UBInt8() #: Cookie of the flow entry that was looked up. cookie = UBInt64() #: Packet metadata. Variable size. match = Match() #: Align to 64 bit + 16 bit pad = Pad(2) #: Ethernet frame whose length is inferred from header.length. #: The padding bytes preceding the Ethernet frame ensure that the IP #: header (if any) following the Ethernet header is 32-bit aligned. data = BinaryData() def __init__(self, xid=None, buffer_id=None, total_len=None, reason=None, table_id=None, cookie=None, match=None, data=b''): """Assign parameters to object attributes. Args: xid (int): Header's xid. buffer_id (int): ID assigned by datapath. total_len (int): Full length of frame. reason (~pyof.v0x04.asynchronous.packet_in.PacketInReason): The reason why the packet is being sent table_id (int): ID of the table that was looked up cookie (int): Cookie of the flow entry that was looked up match (:class:`~pyof.v0x04.common.flow_match.Match`): Packet metadata with variable size. data (bytes): Ethernet frame, halfway through 32-bit word, so the IP header is 32-bit aligned. The amount of data is inferred from the length field in the header. Because of padding, offsetof(struct ofp_packet_in, data) == sizeof(struct ofp_packet_in) - 2. """ super().__init__(xid) 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 @property def in_port(self): """Retrieve the 'in_port' that generated the PacketIn. This method will look for the OXM_TLV with type OFPXMT_OFB_IN_PORT on the `oxm_match_fields` field from `match` field and return its value, if the OXM exists. Returns: The integer number of the 'in_port' that generated the PacketIn if it exists. Otherwise return None. """ in_port = self.match.get_field(OxmOfbMatchField.OFPXMT_OFB_IN_PORT) return int.from_bytes(in_port, 'big')
class PortStats(GenericStruct): """Body of reply to OFPST_PORT request. If a counter is unsupported, set the field to all ones. """ port_no = UBInt16() #: Align to 64-bits. pad = Pad(6) rx_packets = UBInt64() tx_packets = UBInt64() rx_bytes = UBInt64() tx_bytes = UBInt64() rx_dropped = UBInt64() tx_dropped = UBInt64() rx_errors = UBInt64() tx_errors = UBInt64() rx_frame_err = UBInt64() rx_over_err = UBInt64() rx_crc_err = UBInt64() collisions = UBInt64() def __init__(self, port_no=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, rx_frame_err=None, rx_over_err=None, rx_crc_err=None, collisions=None): """Create a PortStats with the optional parameters below. Args: port_no (:class:`int`, :class:`~pyof.v0x01.common.phy_port.Port`): Port number. rx_packets (int): Number of received packets. tx_packets (int): Number of transmitted packets. rx_bytes (int): Number of received bytes. tx_bytes (int): Number of transmitted bytes. rx_dropped (int): Number of packets dropped by RX. tx_dropped (int): Number of packets dropped by TX. rx_errors (int): Number of receive errors. This is a super-set of more specific receive errors and should be greater than or equal to the sum of all rx_*_err values. tx_errors (int): Number of transmit errors. This is a super-set of more specific transmit errors and should be greater than or equal to the sum of all tx_*_err values (none currently defined). rx_frame_err (int): Number of frame alignment errors. rx_over_err (int): Number of packets with RX overrun. rx_crc_err (int): Number of CRC errors. collisions (int): Number of collisions. """ super().__init__() self.port_no = port_no 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.rx_frame_err = rx_frame_err self.rx_over_err = rx_over_err self.rx_crc_err = rx_crc_err self.collisions = collisions
class FlowStats(GenericStruct): """Body of reply to OFPST_FLOW request.""" length = UBInt16() table_id = UBInt8() #: Align to 32 bits. pad = Pad(1) match = Match() duration_sec = UBInt32() duration_nsec = UBInt32() priority = UBInt16() idle_timeout = UBInt16() hard_timeout = UBInt16() #: Align to 64-bits pad2 = Pad(6) cookie = UBInt64() packet_count = UBInt64() byte_count = UBInt64() actions = ListOfActions() def __init__(self, length=None, table_id=None, match=None, duration_sec=None, duration_nsec=None, priority=None, idle_timeout=None, hard_timeout=None, cookie=None, packet_count=None, byte_count=None, actions=None): """Create a FlowStats with the optional parameters below. Args: length (int): Length of this entry. table_id (int): ID of table flow came from. match (~pyof.v0x01.common.flow_match.Match): Description of fields. duration_sec (int): Time flow has been alive in seconds. duration_nsec (int): Time flow has been alive in nanoseconds in addition to duration_sec. priority (int): Priority of the entry. Only meaningful when this is not an exact-match entry. idle_timeout (int): Number of seconds idle before expiration. hard_timeout (int): Number of seconds before expiration. cookie (int): Opaque controller-issued identifier. packet_count (int): Number of packets in flow. byte_count (int): Number of bytes in flow. actions (:class:`~pyof.v0x01.common.actions.ListOfActions`): List of Actions. """ super().__init__() self.length = length self.table_id = table_id self.match = match self.duration_sec = duration_sec self.duration_nsec = duration_nsec self.priority = priority self.idle_timeout = idle_timeout self.hard_timeout = hard_timeout self.cookie = cookie self.packet_count = packet_count self.byte_count = byte_count self.actions = [] if actions is None else actions def unpack(self, buff, offset=0): """Unpack *buff* into this object. Do nothing, since the _length is already defined and it is just a Pad. Keep buff and offset just for compability with other unpack methods. Args: buff (bytes): Buffer where data is located. offset (int): Where data stream begins. """ self.length = UBInt16() self.length.unpack(buff, offset) max_length = offset + self.length.value super().unpack(buff[:max_length], offset)
class MeterStats(GenericStruct): """Meter Statistics. Body of reply to OFPMP_METER request. """ meter_id = UBInt32() length = UBInt16() pad = Pad(6) flow_count = UBInt32() packet_in_count = UBInt64() byte_in_count = UBInt64() duration_sec = UBInt32() duration_nsec = UBInt32() band_stats = ListOfBandStats() def __init__(self, meter_id=None, flow_count=None, packet_in_count=None, byte_in_count=None, duration_sec=None, duration_nsec=None, band_stats=None): """Create a MeterStats with the optional parameters below. Args: meter_id (|Meter_v0x05|): Meter instance. flow_count(int): Number of flows bound to meter. packet_in_count(int): Number of packets in input. byte_in_count(int): Number of bytes in input. duration_sec(int): Time meter has been alive in seconds. duration_nsec(int): Time meter has been alive in nanoseconds beyond duration_sec. band_stats(list): Instances of BandStats """ super().__init__() self.meter_id = meter_id self.flow_count = flow_count self.packet_in_count = packet_in_count self.byte_in_count = byte_in_count self.duration_sec = duration_sec self.duration_nsec = duration_nsec self.band_stats = band_stats if band_stats else [] self.update_length() def update_length(self): """Update length attribute with current struct length.""" self.length = self.get_size() def pack(self, value=None): """Pack method used to update the length of instance and packing. Args: value: Structure to be packed. """ self.update_length() return super().pack(value) def unpack(self, buff=None, offset=0): """Unpack *buff* into this object. This method will convert a binary data into a readable value according to the attribute format. Args: buff (bytes): Binary buffer. offset (int): Where to begin unpacking. Raises: :exc:`~.exceptions.UnpackException`: If unpack fails. """ length = UBInt16() length.unpack(buff, offset) length.unpack(buff, offset=offset + MeterStats.meter_id.get_size()) super().unpack(buff[:offset + length.value], offset=offset)
def generate_messages(self): """ Generate Messages to be tested. All messages will be added to a list. :return: None """ for index in range(0, self.max_num_of_mesg): version = b'\x05' msg_type = UBInt8(self.type_of_mesg).pack() if self.xid is None: self.xid = UBInt32(random.randint(0, self.MAX_32BITS_VALUE)) if self.type_of_mesg == Type.OFPT_GET_CONFIG_REPLY: test_length = b'\x00\x00' test_header = version + msg_type + test_length + self.xid.pack( ) flags = UBInt16(random.randint(0, 3)).pack() miss_send = UBInt16(random.randint(0, 0xffe5)).pack() test_value = test_header + flags + miss_send length = UBInt16(len(test_value)).pack() header = version + msg_type + length + self.xid.pack() value = header + flags + miss_send self.item = (self.xid, value) elif self.type_of_mesg == Type.OFPT_PACKET_IN: test_length = b'\x00\x00' header = version + msg_type + test_length + self.xid.pack() buffer_id = UBInt32(random.randint( 0, self.MAX_32BITS_VALUE)).pack() total_len = UBInt16(random.randint( 0, self.MAX_16BITS_VALUE)).pack() reason = UBInt8(random.randint(0, 5)).pack() table_id = UBInt8(random.randint(0, self.MAX_8BITS_VALUE)).pack() cookie = UBInt64(random.randint(0, self.MAX_64BITS_VALUE)).pack() oxmtlv = b'' for i in range(1, random.randint(1, self.MAX_NUM_OF_OXMTLV)): oxm_class = UBInt16(0x8000).pack() oxm_field_and_mask = UBInt8(0).pack() oxm_length = UBInt8(0) oxm_value = UBInt32( random.randint(1, self.MAX_32BITS_VALUE)).pack() test_value = oxm_class + oxm_field_and_mask + oxm_length.pack( ) oxm_length = UBInt8(len(test_value)).pack() val = oxm_class + oxm_field_and_mask + oxm_length + oxm_value oxmtlv += val match_type = UBInt16(1).pack() match_length = UBInt16(0) match_pad = UBInt32(0).pack() test_length = match_type + match_length.pack( ) + oxmtlv + match_pad match_length = UBInt16(len(test_length)).pack() matchVal = match_type + match_length + oxmtlv + match_pad test_value = header + buffer_id + total_len + reason + table_id + cookie + matchVal length = UBInt16(len(test_value)).pack() header = version + msg_type + length + self.xid.pack() value = header + buffer_id + total_len + reason + table_id + cookie + matchVal self.item = (self.xid, value) elif self.type_of_mesg == Type.OFPT_ECHO_REPLY: test_length = b'\x00\x00' header = version + msg_type + test_length + self.xid.pack() buffer_id = UBInt32(random.randint( 0, self.MAX_32BITS_VALUE)).pack() total_len = UBInt16(random.randint( 0, self.MAX_16BITS_VALUE)).pack() reason = UBInt8(random.randint(0, 5)).pack() table_id = UBInt8(random.randint(0, self.MAX_8BITS_VALUE)).pack() cookie = UBInt64(random.randint(0, self.MAX_64BITS_VALUE)).pack() oxmtlv = b'' for i in range(0, random.randint(1, self.MAX_NUM_OF_OXMTLV)): oxm_class = UBInt16(0x8000).pack() oxm_field_and_mask = UBInt8(0).pack() oxm_length = UBInt8(0) oxm_value = UBInt32( random.randint(1, self.MAX_32BITS_VALUE)).pack() test_value = oxm_class + oxm_field_and_mask + oxm_length.pack( ) oxm_length = UBInt8(len(test_value)).pack() val = oxm_class + oxm_field_and_mask + oxm_length + oxm_value oxmtlv += val match_type = UBInt16(1).pack() match_length = UBInt16(0) match_pad = UBInt32(0).pack() test_length = match_type + match_length.pack( ) + oxmtlv + match_pad match_length = UBInt16(len(test_length)).pack() matchVal = match_type + match_length + oxmtlv + match_pad test_value = header + buffer_id + total_len + reason + table_id + cookie + matchVal length = UBInt16(len(test_value)).pack() header = version + msg_type + length + self.xid.pack() value = header + buffer_id + total_len + reason + table_id + cookie + matchVal self.item = (self.xid, value) elif self.type_of_mesg == Type.OFPT_PACKET_OUT: test_length = b'\x00\x00' header = version + msg_type + test_length + self.xid.pack() buffer_id = UBInt32(random.randint( 0, self.MAX_32BITS_VALUE)).pack() in_port = UBInt32(random.randint(0xfffffffd, 0xffffffff)).pack() actions_len = UBInt16(0).pack() pad = b'\00\00\00\00\00\00' list_of_actions = b'' for i in range(1, random.randint(1, self.MAX_NUM_OF_ACTIONS)): random_type = random.randint(15, 27) #: there is message 25 that needs revision while random_type == 25: random_type = random.randint(15, 27) action_type = UBInt16(random_type).pack() action_length = UBInt16(8) action_val = b'' if random_type in (15, 23): action_ttl = UBInt8( random.randint(0, self.MAX_8BITS_VALUE)).pack() action_pad = b'\00\00\00' action_val = action_ttl + action_pad elif random_type in (16, 18, 24, 27): action_val = b'\00\00\00\00' elif random_type in (17, 19, 20, 26): ethertype = UBInt16( random.randint(0, self.MAX_16BITS_VALUE)).pack() action_pad = b'\00\00' action_val = ethertype + action_pad elif random_type in (21, 22): action_id = UBInt32( random.randint(0, self.MAX_32BITS_VALUE)).pack() action_val = action_id elif random_type == 25: oxm_class = UBInt16(0x8000).pack() oxm_field_and_mask = UBInt8(random.randint(0, 39)).pack() oxm_length = UBInt8(0).pack() oxm_value = UBInt32( random.randint(1, self.MAX_32BITS_VALUE)).pack() test_value = oxm_class + oxm_field_and_mask + oxm_length oxm_length = UBInt8(len(test_value)) field = oxm_class + oxm_field_and_mask + oxm_length.pack( ) + oxm_value #: For update the length on the message pack but the the unpack doesn't have the function #: to unpack the padding # update_length = 4 + len(field) # overflow = update_length % 8 # action_length = update_length # if overflow: # action_length = update_length + 8 - overflow # # padded_size = action_length # padding_bytes = padded_size - len(field) # if padding_bytes > 0: # field += Pad(padding_bytes).pack() #action_length = UBInt16(len(action_type + action_length + field)).pack() action_val = field val = action_type + action_length.pack() + action_val list_of_actions += val actions_len = UBInt16(len(list_of_actions)).pack() test_value = header + buffer_id + in_port + actions_len + pad + list_of_actions length = UBInt16(len(test_value)).pack() header = version + msg_type + length + self.xid.pack() value = header + buffer_id + in_port + actions_len + pad + list_of_actions self.item = (self.xid, value) else: pass self.listOfConfigMessage.append(self.item)
class FlowMod(GenericMessage): """Modifies the flow table from the controller.""" header = Header(message_type=Type.OFPT_FLOW_MOD) cookie = UBInt64() cookie_mask = UBInt64() # Flow actions table_id = UBInt8() command = UBInt8(enum_ref=FlowModCommand) idle_timeout = UBInt16() hard_timeout = UBInt16() priority = UBInt16() buffer_id = UBInt32() out_port = UBInt32() out_group = UBInt32() flags = UBInt16(enum_ref=FlowModFlags) pad = Pad(2) match = Match() def __init__(self, xid=None, cookie=None, cookie_mask=None, table_id=None, command=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, out_group=None, flags=None, match=None): """The constructor just assings parameters to object attributes. Args: xid (int): xid to be used on the message header. cookie (int): Opaque controller-issued identifier. cookie_mask (int): Mask used to restrict the cookie bits that must match when the command is OFPFC_MODIFY* or OFPFC_DELETE*. A value of 0 indicates no restriction. table_id (int): ID of the table to put the flow in. For OFPFC_DELETE_* commands, OFPTT_ALL can also be used to delete matching flows from all tables. command (FlowModCommand): One of OFPFC_*. idle_timeout (int): Idle time before discarding (seconds). hard_timeout (int): Max time before discarding (seconds). priority (int): Priority level of flow entry. buffer_id (int): Buffered packet to apply to, or OFP_NO_BUFFER. Not meaningful for OFPFC_DELETE*. out_port (int): For OFPFC_DELETE* commands, require matching entries to include this as an output port. A value of OFPP_ANY indicates no restriction. out_group (int): For OFPFC_DELETE* commands, require matching entries to include this as an output group. A value of OFPG_ANY indicates no restriction. flags (FlowModFlags): One of OFPFF_*. match (Match): Fields to match. Variable size. """ super().__init__(xid) 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.match = match
class FlowMod(GenericMessage): """Modifies the flow table from the controller.""" header = Header(message_type=Type.OFPT_FLOW_MOD) match = Match() cookie = UBInt64() command = UBInt16(enum_ref=FlowModCommand) idle_timeout = UBInt16() hard_timeout = UBInt16() priority = UBInt16() buffer_id = UBInt32() out_port = UBInt16(enum_ref=Port) flags = UBInt16(enum_ref=FlowModFlags) actions = ListOfActions() def __init__(self, xid=None, match=None, cookie=0, command=None, idle_timeout=0, hard_timeout=0, priority=0, buffer_id=NO_BUFFER, out_port=Port.OFPP_NONE, flags=FlowModFlags.OFPFF_SEND_FLOW_REM, actions=None): """Create a FlowMod with the optional parameters below. Args: xid (int): xid to be used on the message header. match (~pyof.v0x01.common.flow_match.Match): Fields to match. cookie (int): Opaque controller-issued identifier. command (~pyof.v0x01.controller2switch.flow_mod.FlowModCommand): One of OFPFC_*. idle_timeout (int): Idle time before discarding (seconds). hard_timeout (int): Max time before discarding (seconds). priority (int): Priority level of flow entry. buffer_idle (int): Buffered packet to apply to (or -1). Not meaningful for OFPFC_DELETE*. out_port (~pyof.v0x01.common.phy_port.Port): For OFPFC_DELETE* commands, require matching entries to include this as an output port. A value of OFPP_NONE indicates no restriction. flags (~pyof.v0x01.controller2switch.flow_mod.FlowModFlags): One of OFPFF_*. actions (~pyof.v0x01.common.action.ListOfActions): The action length is inferred from the length field in the header. """ super().__init__(xid) self.match = match or Match() self.cookie = cookie 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.flags = flags self.actions = actions or []
class FlowRemoved(GenericMessage): """Flow removed (datapath -> controller). If the controller has requested to be notified when flow entries time out or are deleted from tables, the datapath does this with the OFPT_FLOW_REMOVED message. """ #: :class:`~.header.Header`: OpenFlow Header header = Header(message_type=Type.OFPT_FLOW_REMOVED) #: Opaque controller-issued identifier. cookie = UBInt64() #: Priority level of flow entry. priority = UBInt16() #: One of OFPRR_*. reason = UBInt8(enum_ref=FlowRemovedReason) #: ID of the table table_id = UBInt8() #: Time flow was alive in seconds. duration_sec = UBInt32() #: Time flow was alive in nanoseconds beyond duration_sec. duration_nsec = UBInt32() #: Idle timeout from original flow mod. idle_timeout = UBInt16() #: Hard timeout from original flow mod. hard_timeout = UBInt16() packet_count = UBInt64() byte_count = UBInt64() #: Description of fields. Variable size. #: :class:`~.common.flow_match.Match` match = Match() def __init__(self, xid=None, cookie=None, priority=None, reason=None, table_id=None, duration_sec=None, duration_nsec=None, idle_timeout=None, hard_timeout=None, packet_count=None, byte_count=None, match=None): """Assign parameters to object attributes. Args: xid (int): OpenFlow Header's xid. cookie (int): Opaque controller-issued identifier. priority (int): Priority level of flow entry. reason (FlowRemovedReason): Why the flow was removed. table_id (int): ID of the table. duration_sec (int): Time the flow was alive in seconds. duration_nsec (int): Time the flow was alive in nanoseconds in addition to duration_sec. idle_timeout (int): Idle timeout from original flow mod. hard_timeout (int): Hard timeout from original flow mod. packet_count (int): Number of packets. byte_count (int): Byte count. match (Match): Fields' description. """ super().__init__(xid) self.cookie = cookie self.priority = priority self.reason = reason self.duration_sec = duration_sec self.duration_nsec = duration_nsec self.idle_timeout = idle_timeout self.hard_timeout = hard_timeout self.packet_count = packet_count self.byte_count = byte_count self.match = match
class PortStats(GenericStruct): """Body of reply to OFPMP_PORT_STATS request. If a counter is unsupported, set the field to all ones. """ length = UBInt16() #: Align to 64-bits. pad = Pad(2) port_no = UBInt32() duration_sec = UBInt32() duration_nsec = UBInt32() rx_packets = UBInt64() tx_packets = UBInt64() rx_bytes = UBInt64() tx_bytes = UBInt64() rx_dropped = UBInt64() tx_dropped = UBInt64() rx_errors = UBInt64() tx_errors = UBInt64() properties = ListOfPortDescProperty() # rx_frame_err = UBInt64() # rx_over_err = UBInt64() # rx_crc_err = UBInt64() # collisions = UBInt64() def __init__(self, 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): """ Create a PortStats with the optional parameters below. :param port_no: (:class:`~pyof.v0x05.common.port.Port`): Port number. :param duration_sec: Time port has been alive in seconds. :param duration_nsec: Time port has been alive in nanoseconds beyond duration_sec :param rx_packets: Number of received packets. :param tx_packets: Number of transmitted packets. :param rx_bytes: Number of received bytes. :param tx_bytes: Number of transmitted bytes. :param rx_dropped: Number of packets dropped by RX. :param tx_dropped: Number of packets dropped by TX. :param rx_errors: Number of receive errors. This is a super-set of more specific receive errors and should be greater than or equal to the sum of all rx_*_err values. :param tx_errors: Number of transmit errors. This is a super-set of more specific transmit errors and should be greater than or equal to the sum of all tx_*_err values (none currently defined). :param properties: Port description property list - 0 or more properties. """ super().__init__() 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 if properties else []