import OpenFlow 1.2 protocol module and basic test cases from CPqD/oftest12
For now these tests will live in a separate directory. The goal is to merge
them where possible but this has to wait for an OpenFlow protocol module that
supports all versions of OpenFlow.
diff --git a/src/python/of12/message.py b/src/python/of12/message.py
new file mode 100644
index 0000000..1525b63
--- /dev/null
+++ b/src/python/of12/message.py
@@ -0,0 +1,3814 @@
+
+# Python OpenFlow message wrapper classes
+
+from cstruct import *
+from match import oxm_tlv
+from match import roundup
+from match_list import match_list
+from action_list import action_list
+from instruction_list import instruction_list
+from bucket_list import bucket_list
+from error import *
+
+# Define templates for documentation
+class ofp_template_msg(object):
+ """
+ Sample base class for template_msg; normally auto generated
+ This class should live in the of_header name space and provides the
+ base class for this type of message. It will be wrapped for the
+ high level API.
+
+ """
+ def __init__(self):
+ """
+ Constructor for base class
+
+ """
+ self.header = ofp_header()
+ # Additional base data members declared here
+
+ # Normally will define pack, unpack, __len__ functions
+
+class template_msg(ofp_template_msg):
+ """
+ Sample class wrapper for template_msg
+ This class should live in the of_message name space and provides the
+ high level API for an OpenFlow message object. These objects must
+ implement the functions indicated in this template.
+
+ """
+ def __init__(self):
+ """
+ Constructor
+ Must set the header type value appropriately for the message
+
+ """
+
+ ##@var header
+ # OpenFlow message header: length, version, xid, type
+ ofp_template_msg.__init__(self)
+ self.header = ofp_header()
+ # For a real message, will be set to an integer
+ self.header.type = "TEMPLATE_MSG_VALUE"
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ pass
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+
+ @return Typically returns the remainder of binary_string that
+ was not parsed. May give a warning if that string is non-empty
+
+ """
+ pass
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ pass
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+ pass
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ pass
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ pass
+
+
+################################################################
+#
+# OpenFlow Message Definitions
+#
+################################################################
+
+class barrier_reply(object):
+ """
+ Wrapper class for barrier_reply
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_BARRIER_REPLY=21)
+
+
+ """
+
+ def __init__(self):
+ self.header = ofp_header()
+ self.header.type = OFPT_BARRIER_REPLY
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ packed = self.header.pack()
+
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+
+ # Fixme: If no self.data, add check for data remaining
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'barrier_reply (OFPT_BARRIER_REPLY)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class barrier_request(object):
+ """
+ Wrapper class for barrier_request
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_BARRIER_REQUEST=20)
+
+
+ """
+
+ def __init__(self):
+ self.header = ofp_header()
+ self.header.type = OFPT_BARRIER_REQUEST
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ packed = self.header.pack()
+
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+
+ # Fixme: If no self.data, add check for data remaining
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'barrier_request (OFPT_BARRIER_REQUEST)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class echo_reply(object):
+ """
+ Wrapper class for echo_reply
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_ECHO_REPLY=3)
+
+ @arg data: Binary string following message members
+
+ """
+
+ def __init__(self):
+ self.header = ofp_header()
+ self.header.type = OFPT_ECHO_REPLY
+ self.data = ""
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ packed = self.header.pack()
+
+ packed += self.data
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+
+ self.data = binary_string
+ binary_string = ''
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ length += len(self.data)
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'echo_reply (OFPT_ECHO_REPLY)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ outstr += prefix + 'data is of length ' + str(len(self.data)) + '\n'
+ ##@todo Fix this circular reference
+ # if len(self.data) > 0:
+ # obj = of_message_parse(self.data)
+ # if obj != None:
+ # outstr += obj.show(prefix)
+ # else:
+ # outstr += prefix + "Unable to parse data\n"
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ if self.data != other.data: return False
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class echo_request(object):
+ """
+ Wrapper class for echo_request
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_ECHO_REQUEST=2)
+
+ @arg data: Binary string following message members
+
+ """
+
+ def __init__(self):
+ self.header = ofp_header()
+ self.header.type = OFPT_ECHO_REQUEST
+ self.data = ""
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ packed = self.header.pack()
+
+ packed += self.data
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+
+ self.data = binary_string
+ binary_string = ''
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ length += len(self.data)
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'echo_request (OFPT_ECHO_REQUEST)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ outstr += prefix + 'data is of length ' + str(len(self.data)) + '\n'
+ ##@todo Fix this circular reference
+ # if len(self.data) > 0:
+ # obj = of_message_parse(self.data)
+ # if obj != None:
+ # outstr += obj.show(prefix)
+ # else:
+ # outstr += prefix + "Unable to parse data\n"
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ if self.data != other.data: return False
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class error(ofp_error_msg):
+ """
+ Wrapper class for error
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_ERROR=1)
+
+ Data members inherited from ofp_error_msg:
+ @arg type
+ @arg code
+ @arg data: Binary string following message members
+
+ """
+
+ def __init__(self):
+ ofp_error_msg.__init__(self)
+ self.header = ofp_header()
+ self.header.type = OFPT_ERROR
+ self.data = ""
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ packed = self.header.pack()
+
+ packed += ofp_error_msg.pack(self)
+ packed += self.data
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+
+ binary_string = ofp_error_msg.unpack(self, binary_string)
+ self.data = binary_string
+ binary_string = ''
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ length += ofp_error_msg.__len__(self)
+ length += len(self.data)
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'error (OFPT_ERROR)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_error_msg.show(self, prefix)
+ outstr += prefix + 'data is of length ' + str(len(self.data)) + '\n'
+ ##@todo Fix this circular reference
+ # if len(self.data) > 0:
+ # obj = of_message_parse(self.data)
+ # if obj != None:
+ # outstr += obj.show(prefix)
+ # else:
+ # outstr += prefix + "Unable to parse data\n"
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ if not ofp_error_msg.__eq__(self, other): return False
+ if self.data != other.data: return False
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class experimenter(ofp_experimenter_header):
+ """
+ Wrapper class for experimenter
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_EXPERIMENTER=4)
+
+ Data members inherited from ofp_experimenter_header:
+ @arg experimenter
+ @arg exp_type
+ @arg data: Binary string following message members
+
+ """
+
+ def __init__(self):
+ ofp_experimenter_header.__init__(self)
+ self.header = ofp_header()
+ self.header.type = OFPT_EXPERIMENTER
+ self.data = ""
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ packed = self.header.pack()
+
+ packed += ofp_experimenter_header.pack(self)
+ packed += self.data
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+
+ binary_string = ofp_experimenter_header.unpack(self, binary_string)
+ self.data = binary_string
+ binary_string = ''
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ length += ofp_experimenter_header.__len__(self)
+ length += len(self.data)
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'experimenter (OFPT_EXPERIMENTER)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_experimenter_header.show(self, prefix)
+ outstr += prefix + 'data is of length ' + str(len(self.data)) + '\n'
+ ##@todo Fix this circular reference
+ # if len(self.data) > 0:
+ # obj = of_message_parse(self.data)
+ # if obj != None:
+ # outstr += obj.show(prefix)
+ # else:
+ # outstr += prefix + "Unable to parse data\n"
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ if not ofp_experimenter_header.__eq__(self, other): return False
+ if self.data != other.data: return False
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class features_reply(ofp_switch_features):
+ """
+ Wrapper class for features_reply
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_FEATURES_REPLY=6)
+
+ Data members inherited from ofp_switch_features:
+ @arg datapath_id
+ @arg n_buffers
+ @arg n_tables
+ @arg capabilities
+ @arg reserved
+ @arg ports: Variable length array of TBD
+
+ """
+
+ def __init__(self):
+ ofp_switch_features.__init__(self)
+ self.header = ofp_header()
+ self.header.type = OFPT_FEATURES_REPLY
+ self.ports = []
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ packed = self.header.pack()
+
+ packed += ofp_switch_features.pack(self)
+ for obj in self.ports:
+ packed += obj.pack()
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+
+ binary_string = ofp_switch_features.unpack(self, binary_string)
+ while len(binary_string) >= OFP_PORT_BYTES:
+ new_port = ofp_port()
+ binary_string = new_port.unpack(binary_string)
+ self.ports.append(new_port)
+ # Fixme: If no self.data, add check for data remaining
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ length += ofp_switch_features.__len__(self)
+ for obj in self.ports:
+ length += len(obj)
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'features_reply (OFPT_FEATURES_REPLY)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_switch_features.show(self, prefix)
+ outstr += prefix + "Array ports\n"
+ for obj in self.ports:
+ outstr += obj.show(prefix + ' ')
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ if not ofp_switch_features.__eq__(self, other): return False
+ if self.ports != other.ports: return False
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class features_request(object):
+ """
+ Wrapper class for features_request
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_FEATURES_REQUEST=5)
+
+
+ """
+
+ def __init__(self):
+ self.header = ofp_header()
+ self.header.type = OFPT_FEATURES_REQUEST
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ packed = self.header.pack()
+
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+
+ # Fixme: If no self.data, add check for data remaining
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'features_request (OFPT_FEATURES_REQUEST)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class flow_mod(ofp_flow_mod):
+ """
+ Wrapper class for flow_mod
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_FLOW_MOD=14)
+
+ Data members inherited from ofp_flow_mod:
+ @arg cookie
+ @arg cookie_mask
+ @arg table_id
+ @arg command
+ @arg idle_timeout
+ @arg hard_timeout
+ @arg priority
+ @arg buffer_id
+ @arg out_port
+ @arg out_group
+ @arg flags
+ @arg match
+ @arg instructions: Object of type instruction_list
+
+ """
+
+ def __init__(self):
+ ofp_flow_mod.__init__(self)
+ self.header = ofp_header()
+ self.header.type = OFPT_FLOW_MOD
+ self.buffer_id = 0xffffffff #no buffer
+ self.out_port = OFPP_ANY
+ self.out_group = OFPG_ANY
+ self.match_fields = match_list()
+ self.instructions = instruction_list()
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ if not len(self.match_fields):
+ tlv_pad = oxm_tlv(0,0,0,0,0,0)
+ self.match_fields.tlvs.append(tlv_pad)
+ else:
+ if len(self.match_fields) > 4:
+ self.match.length += len(self.match_fields)
+ packed = self.header.pack()
+ packed += ofp_flow_mod.pack(self)
+ self.match_fields.tlvs.sort(key=lambda x : x.field)
+ packed += self.match_fields.pack()
+ padding_size = roundup( len(self.match) + len(self.match_fields),8) - (len(self.match) + len(self.match_fields))
+ padding = [0] * padding_size
+ if padding_size:
+ packed += struct.pack("!" + str(padding_size) + "B", *padding)
+ packed += self.instructions.pack()
+ return packed
+
+
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_flow_mod.unpack(self, binary_string)
+ binary_string = self.match_fields.unpack(binary_string, bytes = self.match.length - 4)
+ padding = roundup(OFP_FLOW_MOD_BYTES + len(self.match_fields),8) - (OFP_FLOW_MOD_BYTES + len(self.match_fields))
+ if padding:
+ binary_string = binary_string[padding:]
+ ai_len = self.length - roundup(OFP_FLOW_MOD_BYTES + len(self.match_fields),8)
+ binary_string = self.instructions.unpack(binary_string, bytes=ai_len)
+ # Fixme: If no self.data, add check for data remaining
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ length += ofp_flow_mod.__len__(self)
+ length = roundup(length + len(self.match_fields), 8)
+ length += len(self.instructions)
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'flow_mod (OFPT_FLOW_MOD)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_flow_mod.show(self, prefix)
+ outstr += self.match_fields.show(prefix + ' ')
+ outstr += prefix + "List instructions\n"
+ outstr += self.instructions.show(prefix + ' ')
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ if not ofp_flow_mod.__eq__(self, other): return False
+ if self.match_fields != other.match_fields: return False
+ if self.instructions != other.instructions: return False
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class flow_removed(ofp_flow_removed):
+ """
+ Wrapper class for flow_removed
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_FLOW_REMOVED=11)
+
+ Data members inherited from ofp_flow_removed:
+ @arg cookie
+ @arg priority
+ @arg reason
+ @arg table_id
+ @arg duration_sec
+ @arg duration_nsec
+ @arg idle_timeout
+ @arg hard_timeout
+ @arg packet_count
+ @arg byte_count
+ @arg match
+
+ """
+
+ def __init__(self):
+ ofp_flow_removed.__init__(self)
+ self.header = ofp_header()
+ self.header.type = OFPT_FLOW_REMOVED
+ self.match_fields = match_list()
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ if not len(self.match_fields):
+ tlv_pad = oxm_tlv(0,0,0,0,0,0)
+ self.match.length += 4
+ self.match_fields.tlvs.append(tlv_pad)
+ else:
+ if len(self.match_fields) > 4:
+ self.match.length += len(self.match_fields)
+ packed = self.header.pack()
+ packed += ofp_flow_removed.pack(self)
+ packed += self.match_fields.pack()
+ padding_size = roundup( len(self.match) + len(self.match_fields),8) - (len(self.match) + len(self.match_fields))
+ padding = [0] * padding_size
+ if padding_size:
+ packed += struct.pack("!" + str(padding_size) + "B", *padding)
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_flow_removed.unpack(self, binary_string)
+ binary_string = self.match_fields.unpack(binary_string, bytes = self.match.length - 4)
+ padding = roundup(OFP_FLOW_REMOVED_BYTES + len(self.match_fields),8) - (OFP_FLOW_REMOVED_BYTES + len(self.match_fields))
+ if padding:
+ binary_string = binary_string[padding:]
+ # Fixme: If no self.data, add check for data remaining
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+ length += roundup(ofp_flow_removed.__len__(self) + len(self.match_fields),8)
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'flow_removed (OFPT_FLOW_REMOVED)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_flow_removed.show(self, prefix)
+ outstr += self.match_fields.show(prefix + ' ')
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+ if not ofp_flow_removed.__eq__(self, other): return False
+ if self.match_fields != other.match_fields: return False
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class get_config_reply(ofp_switch_config):
+ """
+ Wrapper class for get_config_reply
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_GET_CONFIG_REPLY=8)
+
+ Data members inherited from ofp_switch_config:
+ @arg flags
+ @arg miss_send_len
+
+ """
+
+ def __init__(self):
+ ofp_switch_config.__init__(self)
+ self.header = ofp_header()
+ self.header.type = OFPT_GET_CONFIG_REPLY
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ packed = self.header.pack()
+
+ packed += ofp_switch_config.pack(self)
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+
+ binary_string = ofp_switch_config.unpack(self, binary_string)
+ # Fixme: If no self.data, add check for data remaining
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ length += ofp_switch_config.__len__(self)
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'get_config_reply (OFPT_GET_CONFIG_REPLY)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_switch_config.show(self, prefix)
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ if not ofp_switch_config.__eq__(self, other): return False
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class get_config_request(object):
+ """
+ Wrapper class for get_config_request
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_GET_CONFIG_REQUEST=7)
+
+
+ """
+
+ def __init__(self):
+ self.header = ofp_header()
+ self.header.type = OFPT_GET_CONFIG_REQUEST
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ packed = self.header.pack()
+
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+
+ # Fixme: If no self.data, add check for data remaining
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'get_config_request (OFPT_GET_CONFIG_REQUEST)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class group_mod(ofp_group_mod):
+ """
+ Wrapper class for group_mod
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_GROUP_MOD=15)
+
+ Data members inherited from ofp_group_mod:
+ @arg command
+ @arg type
+ @arg group_id
+ @arg buckets: Object of type bucket_list
+
+ """
+
+ def __init__(self):
+ ofp_group_mod.__init__(self)
+ self.header = ofp_header()
+ self.header.type = OFPT_GROUP_MOD
+ self.buckets = bucket_list()
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ packed = self.header.pack()
+
+ packed += ofp_group_mod.pack(self)
+ packed += self.buckets.pack()
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+
+ binary_string = ofp_group_mod.unpack(self, binary_string)
+ binary_string = self.buckets.unpack(binary_string)
+ # Fixme: If no self.data, add check for data remaining
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ length += ofp_group_mod.__len__(self)
+ length += len(self.buckets)
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'group_mod (OFPT_GROUP_MOD)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_group_mod.show(self, prefix)
+ outstr += prefix + "List buckets\n"
+ outstr += self.buckets.show(prefix + ' ')
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ if not ofp_group_mod.__eq__(self, other): return False
+ if self.buckets != other.buckets: return False
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class hello(object):
+ """
+ Wrapper class for hello
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_HELLO=0)
+
+ @arg data: Binary string following message members
+
+ """
+
+ def __init__(self):
+ self.header = ofp_header()
+ self.header.type = OFPT_HELLO
+ self.data = ""
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ packed = self.header.pack()
+
+ packed += self.data
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+
+ self.data = binary_string
+ binary_string = ''
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ length += len(self.data)
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'hello (OFPT_HELLO)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ outstr += prefix + 'data is of length ' + str(len(self.data)) + '\n'
+ ##@todo Fix this circular reference
+ # if len(self.data) > 0:
+ # obj = of_message_parse(self.data)
+ # if obj != None:
+ # outstr += obj.show(prefix)
+ # else:
+ # outstr += prefix + "Unable to parse data\n"
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ if self.data != other.data: return False
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class packet_in(ofp_packet_in):
+ """
+ Wrapper class for packet_in
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_PACKET_IN=10)
+
+ Data members inherited from ofp_packet_in:
+ @arg buffer_id
+ @arg total_len
+ @arg reason
+ @arg table_id
+ @arg match
+ @arg data: Binary string following message members
+
+ """
+
+ def __init__(self):
+ ofp_packet_in.__init__(self)
+ self.header = ofp_header()
+ self.header.type = OFPT_PACKET_IN
+ self.match_fields = match_list()
+ self.data = ""
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ if len(self.match_fields) < 4:
+ tlv_pad = oxm_tlv(0,0,0,0,0,0)
+ self.match.length += 4
+ self.match_fields.tlvs.append(tlv_pad)
+ else:
+ if len(self.match_fields) > 4:
+ self.match.length += len(self.match_fields)
+ packed = self.header.pack()
+ packed += ofp_packet_in.pack(self)
+ packed += self.match_fields.pack()
+ padding_size = roundup( len(self.match) + len(self.match_fields),8) - (len(self.match) + len(self.match_fields))
+ padding = [0] * padding_size
+ if padding_size:
+ packed += struct.pack("!" + str(padding_size) + "B", *padding)
+ packed += self.data
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_packet_in.unpack(self, binary_string)
+ binary_string = self.match_fields.unpack(binary_string, bytes = self.match.length - 4)
+ padding = roundup(OFP_PACKET_IN_BYTES + len(self.match_fields),8) - (OFP_PACKET_IN_BYTES + len(self.match_fields))
+ if padding:
+ binary_string = binary_string[padding:]
+ binary_string = binary_string[2:]
+ self.data = binary_string
+ binary_string = ''
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ length += roundup(ofp_packet_in.__len__(self) + len(self.match_fields),8)
+ length += len(self.data)
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'packet_in (OFPT_PACKET_IN)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_packet_in.show(self, prefix)
+ outstr += prefix + 'data is of length ' + str(len(self.data)) + '\n'
+ ##@todo Fix this circular reference
+ # if len(self.data) > 0:
+ # obj = of_message_parse(self.data)
+ # if obj != None:
+ # outstr += obj.show(prefix)
+ # else:
+ # outstr += prefix + "Unable to parse data\n"
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ if not ofp_packet_in.__eq__(self, other): return False
+ if self.data != other.data: return False
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class packet_out(ofp_packet_out):
+ """
+ Wrapper class for packet_out
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_PACKET_OUT=13)
+
+ Data members inherited from ofp_packet_out:
+ @arg buffer_id
+ @arg in_port
+ @arg actions_len
+ @arg actions: Object of type action_list
+ @arg data: Binary string following message members
+
+ """
+
+ def __init__(self):
+ ofp_packet_out.__init__(self)
+ self.header = ofp_header()
+ self.header.type = OFPT_PACKET_OUT
+ self.actions = action_list()
+ self.data = ""
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ packed = self.header.pack()
+
+ self.actions_len = len(self.actions)
+ packed += ofp_packet_out.pack(self)
+ packed += self.actions.pack()
+ packed += self.data
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+
+ binary_string = ofp_packet_out.unpack(self, binary_string)
+ binary_string = self.actions.unpack(binary_string, bytes=self.actions_len)
+ self.data = binary_string
+ binary_string = ''
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ length += ofp_packet_out.__len__(self)
+ length += len(self.actions)
+ length += len(self.data)
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'packet_out (OFPT_PACKET_OUT)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_packet_out.show(self, prefix)
+ outstr += prefix + "List actions\n"
+ outstr += self.actions.show(prefix + ' ')
+ outstr += prefix + 'data is of length ' + str(len(self.data)) + '\n'
+ ##@todo Fix this circular reference
+ # if len(self.data) > 0:
+ # obj = of_message_parse(self.data)
+ # if obj != None:
+ # outstr += obj.show(prefix)
+ # else:
+ # outstr += prefix + "Unable to parse data\n"
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ if not ofp_packet_out.__eq__(self, other): return False
+ if self.data != other.data: return False
+ if self.actions != other.actions: return False
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class port_mod(ofp_port_mod):
+ """
+ Wrapper class for port_mod
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_PORT_MOD=16)
+
+ Data members inherited from ofp_port_mod:
+ @arg port_no
+ @arg hw_addr
+ @arg config
+ @arg mask
+ @arg advertise
+
+ """
+
+ def __init__(self):
+ ofp_port_mod.__init__(self)
+ self.header = ofp_header()
+ self.header.type = OFPT_PORT_MOD
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ packed = self.header.pack()
+
+ packed += ofp_port_mod.pack(self)
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+
+ binary_string = ofp_port_mod.unpack(self, binary_string)
+ # Fixme: If no self.data, add check for data remaining
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ length += ofp_port_mod.__len__(self)
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'port_mod (OFPT_PORT_MOD)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_port_mod.show(self, prefix)
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ if not ofp_port_mod.__eq__(self, other): return False
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class port_status(ofp_port_status):
+ """
+ Wrapper class for port_status
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_PORT_STATUS=12)
+
+ Data members inherited from ofp_port_status:
+ @arg reason
+ @arg desc
+
+ """
+
+ def __init__(self):
+ ofp_port_status.__init__(self)
+ self.header = ofp_header()
+ self.header.type = OFPT_PORT_STATUS
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ packed = self.header.pack()
+
+ packed += ofp_port_status.pack(self)
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+
+ binary_string = ofp_port_status.unpack(self, binary_string)
+ # Fixme: If no self.data, add check for data remaining
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ length += ofp_port_status.__len__(self)
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'port_status (OFPT_PORT_STATUS)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_port_status.show(self, prefix)
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ if not ofp_port_status.__eq__(self, other): return False
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class queue_get_config_reply(ofp_queue_get_config_reply):
+ """
+ Wrapper class for queue_get_config_reply
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_QUEUE_GET_CONFIG_REPLY=23)
+
+ Data members inherited from ofp_queue_get_config_reply:
+ @arg port
+ @arg queues: Variable length array of TBD
+
+ """
+
+ def __init__(self):
+ ofp_queue_get_config_reply.__init__(self)
+ self.header = ofp_header()
+ self.header.type = OFPT_QUEUE_GET_CONFIG_REPLY
+ self.queues = []
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ packed = self.header.pack()
+
+ packed += ofp_queue_get_config_reply.pack(self)
+ for obj in self.queues:
+ packed += obj.pack()
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+
+ binary_string = ofp_queue_get_config_reply.unpack(self, binary_string)
+ for obj in self.queues:
+ binary_string = obj.unpack(binary_string)
+ # Fixme: If no self.data, add check for data remaining
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ length += ofp_queue_get_config_reply.__len__(self)
+ for obj in self.queues:
+ length += len(obj)
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'queue_get_config_reply (OFPT_QUEUE_GET_CONFIG_REPLY)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_queue_get_config_reply.show(self, prefix)
+ outstr += prefix + "Array queues\n"
+ for obj in self.queues:
+ outstr += obj.show(prefix + ' ')
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ if not ofp_queue_get_config_reply.__eq__(self, other): return False
+ if self.queues != other.queues: return False
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class queue_get_config_request(ofp_queue_get_config_request):
+ """
+ Wrapper class for queue_get_config_request
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_QUEUE_GET_CONFIG_REQUEST=22)
+
+ Data members inherited from ofp_queue_get_config_request:
+ @arg port
+
+ """
+
+ def __init__(self):
+ ofp_queue_get_config_request.__init__(self)
+ self.header = ofp_header()
+ self.header.type = OFPT_QUEUE_GET_CONFIG_REQUEST
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ packed = self.header.pack()
+
+ packed += ofp_queue_get_config_request.pack(self)
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+
+ binary_string = ofp_queue_get_config_request.unpack(self, binary_string)
+ # Fixme: If no self.data, add check for data remaining
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ length += ofp_queue_get_config_request.__len__(self)
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'queue_get_config_request (OFPT_QUEUE_GET_CONFIG_REQUEST)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_queue_get_config_request.show(self, prefix)
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ if not ofp_queue_get_config_request.__eq__(self, other): return False
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class set_config(ofp_switch_config):
+ """
+ Wrapper class for set_config
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_SET_CONFIG=9)
+
+ Data members inherited from ofp_switch_config:
+ @arg flags
+ @arg miss_send_len
+
+ """
+
+ def __init__(self):
+ ofp_switch_config.__init__(self)
+ self.header = ofp_header()
+ self.header.type = OFPT_SET_CONFIG
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ packed = self.header.pack()
+
+ packed += ofp_switch_config.pack(self)
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+
+ binary_string = ofp_switch_config.unpack(self, binary_string)
+ # Fixme: If no self.data, add check for data remaining
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ length += ofp_switch_config.__len__(self)
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'set_config (OFPT_SET_CONFIG)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_switch_config.show(self, prefix)
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ if not ofp_switch_config.__eq__(self, other): return False
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class stats_reply(ofp_stats_reply):
+ """
+ Wrapper class for stats_reply
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_STATS_REPLY=19)
+
+ Data members inherited from ofp_stats_reply:
+ @arg type
+ @arg flags
+
+ """
+
+ def __init__(self):
+ ofp_stats_reply.__init__(self)
+ self.header = ofp_header()
+ self.header.type = OFPT_STATS_REPLY
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ packed = self.header.pack()
+
+ packed += ofp_stats_reply.pack(self)
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+
+ binary_string = ofp_stats_reply.unpack(self, binary_string)
+ # Fixme: If no self.data, add check for data remaining
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ length += ofp_stats_reply.__len__(self)
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'stats_reply (OFPT_STATS_REPLY)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_stats_reply.show(self, prefix)
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ if not ofp_stats_reply.__eq__(self, other): return False
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class stats_request(ofp_stats_request):
+ """
+ Wrapper class for stats_request
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_STATS_REQUEST=18)
+
+ Data members inherited from ofp_stats_request:
+ @arg type
+ @arg flags
+
+ """
+
+ def __init__(self):
+ ofp_stats_request.__init__(self)
+ self.header = ofp_header()
+ self.header.type = OFPT_STATS_REQUEST
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ packed = self.header.pack()
+
+ packed += ofp_stats_request.pack(self)
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+
+ binary_string = ofp_stats_request.unpack(self, binary_string)
+ # Fixme: If no self.data, add check for data remaining
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ length += ofp_stats_request.__len__(self)
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'stats_request (OFPT_STATS_REQUEST)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_stats_request.show(self, prefix)
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ if not ofp_stats_request.__eq__(self, other): return False
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+class table_mod(ofp_table_mod):
+ """
+ Wrapper class for table_mod
+
+ OpenFlow message header: length, version, xid, type
+ @arg length: The total length of the message
+ @arg version: The OpenFlow version (3)
+ @arg xid: The transaction ID
+ @arg type: The message type (OFPT_TABLE_MOD=17)
+
+ Data members inherited from ofp_table_mod:
+ @arg table_id
+ @arg config
+
+ """
+
+ def __init__(self):
+ ofp_table_mod.__init__(self)
+ self.header = ofp_header()
+ self.header.type = OFPT_TABLE_MOD
+
+
+ def pack(self):
+ """
+ Pack object into string
+
+ @return The packed string which can go on the wire
+
+ """
+ self.header.length = len(self)
+ packed = self.header.pack()
+
+ packed += ofp_table_mod.pack(self)
+ return packed
+
+ def unpack(self, binary_string):
+ """
+ Unpack object from a binary string
+
+ @param binary_string The wire protocol byte string holding the object
+ represented as an array of bytes.
+ @return The remainder of binary_string that was not parsed.
+
+ """
+ binary_string = self.header.unpack(binary_string)
+
+ binary_string = ofp_table_mod.unpack(self, binary_string)
+ # Fixme: If no self.data, add check for data remaining
+ return binary_string
+
+ def __len__(self):
+ """
+ Return the length of this object once packed into a string
+
+ @return An integer representing the number bytes in the packed
+ string.
+
+ """
+ length = OFP_HEADER_BYTES
+
+ length += ofp_table_mod.__len__(self)
+ return length
+
+ def show(self, prefix=''):
+ """
+ Generate a string (with multiple lines) describing the contents
+ of the object in a readable manner
+
+ @param prefix Pre-pended at the beginning of each line.
+
+ """
+
+ outstr = prefix + 'table_mod (OFPT_TABLE_MOD)\n'
+ prefix += ' '
+ outstr += prefix + 'ofp header\n'
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_table_mod.show(self, prefix)
+ return outstr
+
+ def __eq__(self, other):
+ """
+ Return True if self and other hold the same data
+
+ @param other Other object in comparison
+
+ """
+ if type(self) != type(other): return False
+ if not self.header.__eq__(other.header): return False
+
+ if not ofp_table_mod.__eq__(self, other): return False
+ return True
+
+ def __ne__(self, other):
+ """
+ Return True if self and other do not hold the same data
+
+ @param other Other object in comparison
+
+ """
+ return not self.__eq__(other)
+
+
+
+################################################################
+#
+# Stats request and reply subclass definitions
+#
+################################################################
+
+
+# Stats request bodies for desc and table stats are not defined in the
+# OpenFlow header; We define them here. They are empty classes, really
+
+class ofp_desc_stats_request(object):
+ """
+ Forced definition of ofp_desc_stats_request (empty class)
+ """
+ def __init__(self):
+ pass
+ def pack(self, assertstruct=True):
+ return ""
+ def unpack(self, binary_string):
+ return binary_string
+ def __len__(self):
+ return 0
+ def show(self, prefix=''):
+ return prefix + "ofp_desc_stats_request (empty)\n"
+ def __eq__(self, other):
+ return type(self) == type(other)
+ def __ne__(self, other):
+ return type(self) != type(other)
+
+OFP_DESC_STATS_REQUEST_BYTES = 0
+
+class ofp_table_stats_request(object):
+ """
+ Forced definition of ofp_table_stats_request (empty class)
+ """
+ def __init__(self):
+ pass
+ def pack(self, assertstruct=True):
+ return ""
+ def unpack(self, binary_string):
+ return binary_string
+ def __len__(self):
+ return 0
+ def show(self, prefix=''):
+ return prefix + "ofp_table_stats_request (empty)\n"
+ def __eq__(self, other):
+ return type(self) == type(other)
+ def __ne__(self, other):
+ return type(self) != type(other)
+
+OFP_TABLE_STATS_REQUEST_BYTES = 0
+
+class ofp_group_desc_stats_request(object):
+ """
+ Forced definition of ofp_group_desc_stats_request (empty class)
+ """
+ def __init__(self):
+ pass
+ def pack(self, assertstruct=True):
+ return ""
+ def unpack(self, binary_string):
+ return binary_string
+ def __len__(self):
+ return 0
+ def show(self, prefix=''):
+ return prefix + "ofp_group_desc_stats_request (empty)\n"
+ def __eq__(self, other):
+ return type(self) == type(other)
+ def __ne__(self, other):
+ return type(self) != type(other)
+
+OFP_GROUP_DESC_STATS_REQUEST_BYTES = 0
+
+
+
+# Stats entries define the content of one element in a stats
+# reply for the indicated type; define _entry for consistency
+
+aggregate_stats_entry = ofp_aggregate_stats_reply
+desc_stats_entry = ofp_desc_stats
+port_stats_entry = ofp_port_stats
+queue_stats_entry = ofp_queue_stats
+table_stats_entry = ofp_table_stats
+group_stats_entry = ofp_group_stats
+group_desc_stats_entry = ofp_group_desc_stats
+
+
+#
+# Flow stats entry contains an action list of variable length, so
+# it is done by hand
+#
+
+class flow_stats_entry(ofp_flow_stats):
+ """
+ Special case flow stats entry to handle action list object
+ """
+ def __init__(self):
+ ofp_flow_stats.__init__(self)
+ self.match_fields = match_list()
+ self.instructions = instruction_list()
+
+ def pack(self, assertstruct=True):
+ self.length = len(self)
+ if not len(self.match_fields):
+ tlv_pad = oxm_tlv(0,0,0,0,0,0)
+ self.match.length += 4
+ self.match_fields.tlvs.append(tlv_pad)
+ else:
+ if len(self.match_fields) > 4:
+ self.match.length += len(self.match_fields)
+ packed = ofp_flow_stats.pack(self, assertstruct)
+ packed += self.match_fields.pack()
+ padding_size = roundup(len(self.match) + len(self.match_fields),8) - (len(self.match) + len(self.match_fields))
+ padding = [0] * padding_size
+ if padding_size:
+ packed += struct.pack("!" + str(padding_size) + "B", *padding)
+ packed += self.instructions.pack()
+ if len(packed) != self.length:
+ print("ERROR: flow_stats_entry pack length not equal",
+ self.length, len(packed))
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = ofp_flow_stats.unpack(self, binary_string)
+ binary_string = self.match_fields.unpack(binary_string, bytes = self.match.length - 4)
+ padding = roundup((OFP_FLOW_STATS_BYTES -4) + self.match.length,8) - ((OFP_FLOW_STATS_BYTES - 4) + self.match.length)
+ if padding:
+ binary_string = binary_string[padding:]
+ ai_len = self.length - roundup(OFP_FLOW_STATS_BYTES + len(self.match_fields),8)
+ if ai_len < 0:
+ print("ERROR: flow_stats_entry unpack length too small",
+ self.length)
+ binary_string = self.instructions.unpack(binary_string, bytes=ai_len)
+ return binary_string
+
+ def __len__(self):
+ return roundup(OFP_FLOW_STATS_BYTES + len(self.match_fields),8) + len(self.instructions)
+
+ def show(self, prefix=''):
+ outstr = prefix + "flow_stats_entry\n"
+ outstr += ofp_flow_stats.show(self, prefix + ' ')
+ outstr += self.match_fields.show(prefix + ' ')
+ outstr += self.instructions.show(prefix + ' ')
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (ofp_flow_stats.__eq__(self, other) and
+ self.instructions == other.instructions)
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class aggregate_stats_request(ofp_stats_request, ofp_aggregate_stats_request):
+ """
+ Wrapper class for aggregate stats request message
+ """
+ def __init__(self):
+ self.header = ofp_header()
+ ofp_stats_request.__init__(self)
+ ofp_aggregate_stats_request.__init__(self)
+ self.header.type = OFPT_STATS_REQUEST
+ self.type = OFPST_AGGREGATE
+ self.match_fields = match_list()
+
+ def pack(self, assertstruct=True):
+ self.header.length = len(self)
+ packed = self.header.pack()
+ packed += ofp_stats_request.pack(self)
+ if not len(self.match_fields):
+ tlv_pad = oxm_tlv(0,0,0,0,0,0)
+ self.match.length += 4
+ self.match_fields.tlvs.append(tlv_pad)
+ else:
+ if len(self.match_fields) > 4:
+ self.match.length += len(self.match_fields)
+ packed += ofp_aggregate_stats_request.pack(self, assertstruct)
+ packed += self.match_fields.pack()
+ padding_size = roundup(len(self.match) + len(self.match_fields),8) - (len(self.match) + len(self.match_fields))
+ padding = [0] * padding_size
+
+ if padding_size:
+ packed += struct.pack("!" + str(padding_size) + "B", *padding)
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_stats_request.unpack(self, binary_string)
+ binary_string = ofp_aggregate_stats_request.unpack(self, binary_string)
+ binary_string = self.match_fields.unpack(binary_string, bytes = self.match.length - 4)
+ padding = roundup(OFP_AGGREGATE_STATS_REQUEST_BYTES + len(self.match_fields),8) - (OFP_AGGREGATE_STATS_REQUEST_BYTES + len(self.match_fields))
+ if padding:
+ binary_string = binary_string[padding:]
+ if len(binary_string) != 0:
+ print "ERROR unpacking flow: extra data"
+ return binary_string
+
+
+ def __len__(self):
+ length = len(self.header) + OFP_STATS_REQUEST_BYTES + \
+ OFP_AGGREGATE_STATS_REQUEST_BYTES
+ if not len(self.match_fields):
+ return length + 4
+ else:
+ return roundup(length + len(self.match_fields),8)
+
+ def show(self, prefix=''):
+ outstr = prefix + "aggregate_stats_request\n"
+ outstr += prefix + "ofp header:\n"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_stats_request.show(self)
+ outstr += ofp_aggregate_stats_request.show(self)
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_stats_request.__eq__(self, other) and
+ ofp_aggregate_stats_request.__eq__(self, other))
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class aggregate_stats_reply(ofp_stats_reply):
+ """
+ Wrapper class for aggregate stats reply
+ """
+ def __init__(self):
+ self.header = ofp_header()
+ ofp_stats_reply.__init__(self)
+ self.header.type = OFPT_STATS_REPLY
+ self.type = OFPST_AGGREGATE
+ # stats: Array of type aggregate_stats_entry
+ self.stats = []
+
+ def pack(self, assertstruct=True):
+ self.header.length = len(self)
+ packed = self.header.pack()
+ packed += ofp_stats_reply.pack(self)
+ for obj in self.stats:
+ packed += obj.pack()
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_stats_reply.unpack(self, binary_string)
+ dummy = aggregate_stats_entry()
+ while len(binary_string) >= len(dummy):
+ obj = aggregate_stats_entry()
+ binary_string = obj.unpack(binary_string)
+ self.stats.append(obj)
+ if len(binary_string) != 0:
+ print "ERROR unpacking aggregate stats string: extra bytes"
+ return binary_string
+
+ def __len__(self):
+ length = len(self.header) + OFP_STATS_REPLY_BYTES
+ for obj in self.stats:
+ length += len(obj)
+ return length
+
+ def show(self, prefix=''):
+ outstr = prefix + "aggregate_stats_reply\n"
+ outstr += prefix + "ofp header:\n"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_stats_reply.show(self)
+ outstr += prefix + "Stats array of length " + str(len(self.stats)) + '\n'
+ for obj in self.stats:
+ outstr += obj.show()
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_stats_reply.__eq__(self, other) and
+ self.stats == other.stats)
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class desc_stats_request(ofp_stats_request, ofp_desc_stats_request):
+ """
+ Wrapper class for desc stats request message
+ """
+ def __init__(self):
+ self.header = ofp_header()
+ ofp_stats_request.__init__(self)
+ ofp_desc_stats_request.__init__(self)
+ self.header.type = OFPT_STATS_REQUEST
+ self.type = OFPST_DESC
+
+ def pack(self, assertstruct=True):
+ self.header.length = len(self)
+ packed = self.header.pack()
+ packed += ofp_stats_request.pack(self)
+ packed += ofp_desc_stats_request.pack(self)
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_stats_request.unpack(self, binary_string)
+ binary_string = ofp_desc_stats_request.unpack(self, binary_string)
+ if len(binary_string) != 0:
+ print "ERROR unpacking desc: extra data"
+ return binary_string
+
+ def __len__(self):
+ return len(self.header) + OFP_STATS_REQUEST_BYTES + \
+ OFP_DESC_STATS_REQUEST_BYTES
+
+ def show(self, prefix=''):
+ outstr = prefix + "desc_stats_request\n"
+ outstr += prefix + "ofp header:\n"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_stats_request.show(self)
+ outstr += ofp_desc_stats_request.show(self)
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_stats_request.__eq__(self, other) and
+ ofp_desc_stats_request.__eq__(self, other))
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class desc_stats_reply(ofp_stats_reply):
+ """
+ Wrapper class for desc stats reply
+ """
+ def __init__(self):
+ self.header = ofp_header()
+ ofp_stats_reply.__init__(self)
+ self.header.type = OFPT_STATS_REPLY
+ self.type = OFPST_DESC
+ # stats: Array of type desc_stats_entry
+ self.stats = []
+
+ def pack(self, assertstruct=True):
+ self.header.length = len(self)
+ packed = self.header.pack()
+ packed += ofp_stats_reply.pack(self)
+ for obj in self.stats:
+ packed += obj.pack()
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_stats_reply.unpack(self, binary_string)
+ dummy = desc_stats_entry()
+ while len(binary_string) >= len(dummy):
+ obj = desc_stats_entry()
+ binary_string = obj.unpack(binary_string)
+ self.stats.append(obj)
+ if len(binary_string) != 0:
+ print "ERROR unpacking desc stats string: extra bytes"
+ return binary_string
+
+ def __len__(self):
+ length = len(self.header) + OFP_STATS_REPLY_BYTES
+ for obj in self.stats:
+ length += len(obj)
+ return length
+
+ def show(self, prefix=''):
+ outstr = prefix + "desc_stats_reply\n"
+ outstr += prefix + "ofp header:\n"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_stats_reply.show(self)
+ outstr += prefix + "Stats array of length " + str(len(self.stats)) + '\n'
+ for obj in self.stats:
+ outstr += obj.show()
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_stats_reply.__eq__(self, other) and
+ self.stats == other.stats)
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class flow_stats_request(ofp_stats_request, ofp_flow_stats_request):
+ """
+ Wrapper class for flow stats request message
+ """
+ def __init__(self):
+ self.header = ofp_header()
+ ofp_stats_request.__init__(self)
+ ofp_flow_stats_request.__init__(self)
+ self.header.type = OFPT_STATS_REQUEST
+ self.type = OFPST_FLOW
+ self.match_fields = match_list()
+
+ def pack(self):
+ self.header.length = len(self)
+ packed = self.header.pack()
+ packed += ofp_stats_request.pack(self)
+ if not len(self.match_fields):
+ tlv_pad = oxm_tlv(0,0,0,0,0,0)
+ self.match.length += 4
+ self.match_fields.tlvs.append(tlv_pad)
+ else:
+ if len(self.match_fields) > 4:
+ self.match.length += len(self.match_fields)
+ packed += ofp_flow_stats_request.pack(self)
+ packed += self.match_fields.pack()
+ padding_size = roundup(len(self.match) + len(self.match_fields),8) - (len(self.match) + len(self.match_fields))
+ padding = [0] * padding_size
+ if padding_size:
+ packed += struct.pack("!" + str(padding_size) + "B", *padding)
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_stats_request.unpack(self, binary_string)
+ binary_string = ofp_flow_stats_request.unpack(self, binary_string)
+ binary_string = self.match_fields.unpack(binary_string, bytes = self.match.length - 4)
+ padding = roundup(OFP_FLOW_STATS_REQUEST_BYTES + len(self.match_fields),8) - (OFP_FLOW_STATS_REQUEST_BYTES + len(self.match_fields))
+ if padding:
+ binary_string = binary_string[padding:]
+ if len(binary_string) != 0:
+ print "ERROR unpacking flow: extra data"
+ return binary_string
+
+ def __len__(self):
+ length = len(self.header) + OFP_STATS_REQUEST_BYTES + \
+ OFP_FLOW_STATS_REQUEST_BYTES
+ if not len(self.match_fields):
+ return length + 4
+ else:
+ return roundup(length + len(self.match_fields),8)
+
+ def show(self, prefix=''):
+ outstr = prefix + "flow_stats_request\n"
+ outstr += prefix + "ofp header:\n"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_stats_request.show(self)
+ outstr += ofp_flow_stats_request.show(self)
+ outstr += self.match_fields.show(prefix + ' ')
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_stats_request.__eq__(self, other) and
+ ofp_flow_stats_request.__eq__(self, other) and
+ self.match_fields != other.match_fields)
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class flow_stats_reply(ofp_stats_reply):
+ """
+ Wrapper class for flow stats reply
+ """
+ def __init__(self):
+ self.header = ofp_header()
+ ofp_stats_reply.__init__(self)
+ self.header.type = OFPT_STATS_REPLY
+ self.type = OFPST_FLOW
+ # stats: Array of type flow_stats_entry
+ self.stats = []
+
+ def pack(self, assertstruct=True):
+ self.header.length = len(self)
+ packed = self.header.pack()
+ packed += ofp_stats_reply.pack(self)
+ for obj in self.stats:
+ packed += obj.pack()
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_stats_reply.unpack(self, binary_string)
+ dummy = flow_stats_entry()
+ while len(binary_string) >= len(dummy):
+ obj = flow_stats_entry()
+ binary_string = obj.unpack(binary_string)
+ self.stats.append(obj)
+ if len(binary_string) != 0:
+ print "ERROR unpacking flow stats string: extra bytes"
+ return binary_string
+
+ def __len__(self):
+ length = len(self.header) + OFP_STATS_REPLY_BYTES
+ for obj in self.stats:
+ length += len(obj)
+ return length
+
+ def show(self, prefix=''):
+ outstr = prefix + "flow_stats_reply\n"
+ outstr += prefix + "ofp header:\n"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_stats_reply.show(self)
+ outstr += prefix + "Stats array of length " + str(len(self.stats)) + '\n'
+ for obj in self.stats:
+ outstr += obj.show()
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_stats_reply.__eq__(self, other) and
+ self.stats == other.stats)
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class port_stats_request(ofp_stats_request, ofp_port_stats_request):
+ """
+ Wrapper class for port stats request message
+ """
+ def __init__(self):
+ self.header = ofp_header()
+ ofp_stats_request.__init__(self)
+ ofp_port_stats_request.__init__(self)
+ self.header.type = OFPT_STATS_REQUEST
+ self.type = OFPST_PORT
+
+ def pack(self, assertstruct=True):
+ self.header.length = len(self)
+ packed = self.header.pack()
+ packed += ofp_stats_request.pack(self)
+ packed += ofp_port_stats_request.pack(self)
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_stats_request.unpack(self, binary_string)
+ binary_string = ofp_port_stats_request.unpack(self, binary_string)
+ if len(binary_string) != 0:
+ print "ERROR unpacking port: extra data"
+ return binary_string
+
+ def __len__(self):
+ return len(self.header) + OFP_STATS_REQUEST_BYTES + \
+ OFP_PORT_STATS_REQUEST_BYTES
+
+ def show(self, prefix=''):
+ outstr = prefix + "port_stats_request\n"
+ outstr += prefix + "ofp header:\n"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_stats_request.show(self)
+ outstr += ofp_port_stats_request.show(self)
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_stats_request.__eq__(self, other) and
+ ofp_port_stats_request.__eq__(self, other))
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class port_stats_reply(ofp_stats_reply):
+ """
+ Wrapper class for port stats reply
+ """
+ def __init__(self):
+ self.header = ofp_header()
+ ofp_stats_reply.__init__(self)
+ self.header.type = OFPT_STATS_REPLY
+ self.type = OFPST_PORT
+ # stats: Array of type port_stats_entry
+ self.stats = []
+
+ def pack(self, assertstruct=True):
+ self.header.length = len(self)
+ packed = self.header.pack()
+ packed += ofp_stats_reply.pack(self)
+ for obj in self.stats:
+ packed += obj.pack()
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_stats_reply.unpack(self, binary_string)
+ dummy = port_stats_entry()
+ while len(binary_string) >= len(dummy):
+ obj = port_stats_entry()
+ binary_string = obj.unpack(binary_string)
+ self.stats.append(obj)
+ if len(binary_string) != 0:
+ print "ERROR unpacking port stats string: extra bytes"
+ return binary_string
+
+ def __len__(self):
+ length = len(self.header) + OFP_STATS_REPLY_BYTES
+ for obj in self.stats:
+ length += len(obj)
+ return length
+
+ def show(self, prefix=''):
+ outstr = prefix + "port_stats_reply\n"
+ outstr += prefix + "ofp header:\n"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_stats_reply.show(self)
+ outstr += prefix + "Stats array of length " + str(len(self.stats)) + '\n'
+ for obj in self.stats:
+ outstr += obj.show()
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_stats_reply.__eq__(self, other) and
+ self.stats == other.stats)
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class queue_stats_request(ofp_stats_request, ofp_queue_stats_request):
+ """
+ Wrapper class for queue stats request message
+ """
+ def __init__(self):
+ self.header = ofp_header()
+ ofp_stats_request.__init__(self)
+ ofp_queue_stats_request.__init__(self)
+ self.header.type = OFPT_STATS_REQUEST
+ self.type = OFPST_QUEUE
+
+ def pack(self, assertstruct=True):
+ self.header.length = len(self)
+ packed = self.header.pack()
+ packed += ofp_stats_request.pack(self)
+ packed += ofp_queue_stats_request.pack(self)
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_stats_request.unpack(self, binary_string)
+ binary_string = ofp_queue_stats_request.unpack(self, binary_string)
+ if len(binary_string) != 0:
+ print "ERROR unpacking queue: extra data"
+ return binary_string
+
+ def __len__(self):
+ return len(self.header) + OFP_STATS_REQUEST_BYTES + \
+ OFP_QUEUE_STATS_REQUEST_BYTES
+
+ def show(self, prefix=''):
+ outstr = prefix + "queue_stats_request\n"
+ outstr += prefix + "ofp header:\n"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_stats_request.show(self)
+ outstr += ofp_queue_stats_request.show(self)
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_stats_request.__eq__(self, other) and
+ ofp_queue_stats_request.__eq__(self, other))
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class queue_stats_reply(ofp_stats_reply):
+ """
+ Wrapper class for queue stats reply
+ """
+ def __init__(self):
+ self.header = ofp_header()
+ ofp_stats_reply.__init__(self)
+ self.header.type = OFPT_STATS_REPLY
+ self.type = OFPST_QUEUE
+ # stats: Array of type queue_stats_entry
+ self.stats = []
+
+ def pack(self, assertstruct=True):
+ self.header.length = len(self)
+ packed = self.header.pack()
+ packed += ofp_stats_reply.pack(self)
+ for obj in self.stats:
+ packed += obj.pack()
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_stats_reply.unpack(self, binary_string)
+ dummy = queue_stats_entry()
+ while len(binary_string) >= len(dummy):
+ obj = queue_stats_entry()
+ binary_string = obj.unpack(binary_string)
+ self.stats.append(obj)
+ if len(binary_string) != 0:
+ print "ERROR unpacking queue stats string: extra bytes"
+ return binary_string
+
+ def __len__(self):
+ length = len(self.header) + OFP_STATS_REPLY_BYTES
+ for obj in self.stats:
+ length += len(obj)
+ return length
+
+ def show(self, prefix=''):
+ outstr = prefix + "queue_stats_reply\n"
+ outstr += prefix + "ofp header:\n"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_stats_reply.show(self)
+ outstr += prefix + "Stats array of length " + str(len(self.stats)) + '\n'
+ for obj in self.stats:
+ outstr += obj.show()
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_stats_reply.__eq__(self, other) and
+ self.stats == other.stats)
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class group_stats_request(ofp_stats_request, ofp_group_stats_request):
+ """
+ Wrapper class for group stats request message
+ """
+ def __init__(self):
+ self.header = ofp_header()
+ ofp_stats_request.__init__(self)
+ ofp_group_stats_request.__init__(self)
+ self.header.type = OFPT_STATS_REQUEST
+ self.type = OFPST_GROUP
+
+ def pack(self, assertstruct=True):
+ self.header.length = len(self)
+ packed = self.header.pack()
+ packed += ofp_stats_request.pack(self)
+ packed += ofp_group_stats_request.pack(self)
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_stats_request.unpack(self, binary_string)
+ binary_string = ofp_group_stats_request.unpack(self, binary_string)
+ if len(binary_string) != 0:
+ print "ERROR unpacking group: extra data"
+ return binary_string
+
+ def __len__(self):
+ return len(self.header) + OFP_STATS_REQUEST_BYTES + \
+ OFP_GROUP_STATS_REQUEST_BYTES
+
+ def show(self, prefix=''):
+ outstr = prefix + "group_stats_request\n"
+ outstr += prefix + "ofp header:\n"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_stats_request.show(self)
+ outstr += ofp_group_stats_request.show(self)
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_stats_request.__eq__(self, other) and
+ ofp_group_stats_request.__eq__(self, other))
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class group_stats_reply(ofp_stats_reply):
+ """
+ Wrapper class for group stats reply
+ """
+ def __init__(self):
+ self.header = ofp_header()
+ ofp_stats_reply.__init__(self)
+ self.header.type = OFPT_STATS_REPLY
+ self.type = OFPST_GROUP
+ # stats: Array of type group_stats_entry
+ self.stats = []
+
+ def pack(self, assertstruct=True):
+ self.header.length = len(self)
+ packed = self.header.pack()
+ packed += ofp_stats_reply.pack(self)
+ for obj in self.stats:
+ packed += obj.pack()
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_stats_reply.unpack(self, binary_string)
+ dummy = group_stats_entry()
+ while len(binary_string) >= len(dummy):
+ obj = group_stats_entry()
+ binary_string = obj.unpack(binary_string)
+ self.stats.append(obj)
+ if len(binary_string) != 0:
+ print "ERROR unpacking group stats string: extra bytes"
+ return binary_string
+
+ def __len__(self):
+ length = len(self.header) + OFP_STATS_REPLY_BYTES
+ for obj in self.stats:
+ length += len(obj)
+ return length
+
+ def show(self, prefix=''):
+ outstr = prefix + "group_stats_reply\n"
+ outstr += prefix + "ofp header:\n"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_stats_reply.show(self)
+ outstr += prefix + "Stats array of length " + str(len(self.stats)) + '\n'
+ for obj in self.stats:
+ outstr += obj.show()
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_stats_reply.__eq__(self, other) and
+ self.stats == other.stats)
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class group_desc_stats_request(ofp_stats_request, ofp_group_desc_stats_request):
+ """
+ Wrapper class for group_desc stats request message
+ """
+ def __init__(self):
+ self.header = ofp_header()
+ ofp_stats_request.__init__(self)
+ ofp_group_desc_stats_request.__init__(self)
+ self.header.type = OFPT_STATS_REQUEST
+ self.type = OFPST_GROUP_DESC
+
+ def pack(self, assertstruct=True):
+ self.header.length = len(self)
+ packed = self.header.pack()
+ packed += ofp_stats_request.pack(self)
+ packed += ofp_group_desc_stats_request.pack(self)
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_stats_request.unpack(self, binary_string)
+ binary_string = ofp_group_desc_stats_request.unpack(self, binary_string)
+ if len(binary_string) != 0:
+ print "ERROR unpacking group_desc: extra data"
+ return binary_string
+
+ def __len__(self):
+ return len(self.header) + OFP_STATS_REQUEST_BYTES + \
+ OFP_GROUP_DESC_STATS_REQUEST_BYTES
+
+ def show(self, prefix=''):
+ outstr = prefix + "group_desc_stats_request\n"
+ outstr += prefix + "ofp header:\n"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_stats_request.show(self)
+ outstr += ofp_group_desc_stats_request.show(self)
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_stats_request.__eq__(self, other) and
+ ofp_group_desc_stats_request.__eq__(self, other))
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class group_desc_stats_reply(ofp_stats_reply):
+ """
+ Wrapper class for group_desc stats reply
+ """
+ def __init__(self):
+ self.header = ofp_header()
+ ofp_stats_reply.__init__(self)
+ self.header.type = OFPT_STATS_REPLY
+ self.type = OFPST_GROUP_DESC
+ # stats: Array of type group_desc_stats_entry
+ self.stats = []
+
+ def pack(self, assertstruct=True):
+ self.header.length = len(self)
+ packed = self.header.pack()
+ packed += ofp_stats_reply.pack(self)
+ for obj in self.stats:
+ packed += obj.pack()
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_stats_reply.unpack(self, binary_string)
+ dummy = group_desc_stats_entry()
+ while len(binary_string) >= len(dummy):
+ obj = group_desc_stats_entry()
+ binary_string = obj.unpack(binary_string)
+ self.stats.append(obj)
+ if len(binary_string) != 0:
+ print "ERROR unpacking group_desc stats string: extra bytes"
+ return binary_string
+
+ def __len__(self):
+ length = len(self.header) + OFP_STATS_REPLY_BYTES
+ for obj in self.stats:
+ length += len(obj)
+ return length
+
+ def show(self, prefix=''):
+ outstr = prefix + "group_desc_stats_reply\n"
+ outstr += prefix + "ofp header:\n"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_stats_reply.show(self)
+ outstr += prefix + "Stats array of length " + str(len(self.stats)) + '\n'
+ for obj in self.stats:
+ outstr += obj.show()
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_stats_reply.__eq__(self, other) and
+ self.stats == other.stats)
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class table_stats_request(ofp_stats_request, ofp_table_stats_request):
+ """
+ Wrapper class for table stats request message
+ """
+ def __init__(self):
+ self.header = ofp_header()
+ ofp_stats_request.__init__(self)
+ ofp_table_stats_request.__init__(self)
+ self.header.type = OFPT_STATS_REQUEST
+ self.type = OFPST_TABLE
+
+ def pack(self, assertstruct=True):
+ self.header.length = len(self)
+ packed = self.header.pack()
+ packed += ofp_stats_request.pack(self)
+ packed += ofp_table_stats_request.pack(self)
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_stats_request.unpack(self, binary_string)
+ binary_string = ofp_table_stats_request.unpack(self, binary_string)
+ if len(binary_string) != 0:
+ print "ERROR unpacking table: extra data"
+ return binary_string
+
+ def __len__(self):
+ return len(self.header) + OFP_STATS_REQUEST_BYTES + \
+ OFP_TABLE_STATS_REQUEST_BYTES
+
+ def show(self, prefix=''):
+ outstr = prefix + "table_stats_request\n"
+ outstr += prefix + "ofp header:\n"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_stats_request.show(self)
+ outstr += ofp_table_stats_request.show(self)
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_stats_request.__eq__(self, other) and
+ ofp_table_stats_request.__eq__(self, other))
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class table_stats_reply(ofp_stats_reply):
+ """
+ Wrapper class for table stats reply
+ """
+ def __init__(self):
+ self.header = ofp_header()
+ ofp_stats_reply.__init__(self)
+ self.header.type = OFPT_STATS_REPLY
+ self.type = OFPST_TABLE
+ # stats: Array of type table_stats_entry
+ self.stats = []
+
+ def pack(self, assertstruct=True):
+ self.header.length = len(self)
+ packed = self.header.pack()
+ packed += ofp_stats_reply.pack(self)
+ for obj in self.stats:
+ packed += obj.pack()
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_stats_reply.unpack(self, binary_string)
+ dummy = table_stats_entry()
+ while len(binary_string) >= len(dummy):
+ obj = table_stats_entry()
+ binary_string = obj.unpack(binary_string)
+ self.stats.append(obj)
+ if len(binary_string) != 0:
+ print "ERROR unpacking table stats string: extra bytes"
+ return binary_string
+
+ def __len__(self):
+ length = len(self.header) + OFP_STATS_REPLY_BYTES
+ for obj in self.stats:
+ length += len(obj)
+ return length
+
+ def show(self, prefix=''):
+ outstr = prefix + "table_stats_reply\n"
+ outstr += prefix + "ofp header:\n"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_stats_reply.show(self)
+ outstr += prefix + "Stats array of length " + str(len(self.stats)) + '\n'
+ for obj in self.stats:
+ outstr += obj.show()
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_stats_reply.__eq__(self, other) and
+ self.stats == other.stats)
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+# @todo Add buckets to group and group_desc stats obejcts"
+message_type_list = (
+ aggregate_stats_reply,
+ aggregate_stats_request,
+ bad_action_error_msg,
+ bad_request_error_msg,
+ barrier_reply,
+ barrier_request,
+ desc_stats_reply,
+ desc_stats_request,
+ echo_reply,
+ echo_request,
+ error,
+ experimenter,
+ features_reply,
+ features_request,
+ flow_mod,
+ flow_mod_failed_error_msg,
+ flow_removed,
+ flow_stats_reply,
+ flow_stats_request,
+ get_config_reply,
+ get_config_request,
+ group_desc_stats_request,
+ group_desc_stats_reply,
+ group_stats_request,
+ group_stats_reply,
+ group_mod,
+ group_mod_failed_error_msg,
+ hello,
+ hello_failed_error_msg,
+ packet_in,
+ packet_out,
+ port_mod,
+ port_mod_failed_error_msg,
+ port_stats_reply,
+ port_stats_request,
+ port_status,
+ queue_get_config_reply,
+ queue_get_config_request,
+ queue_op_failed_error_msg,
+ queue_stats_reply,
+ queue_stats_request,
+ set_config,
+ switch_config_failed_error_msg,
+ table_mod,
+ table_mod_failed_error_msg,
+ table_stats_reply,
+ table_stats_request,
+ )
+