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/__init__.py b/src/python/of12/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/python/of12/__init__.py
diff --git a/src/python/of12/action.py b/src/python/of12/action.py
new file mode 100644
index 0000000..d67a16c
--- /dev/null
+++ b/src/python/of12/action.py
@@ -0,0 +1,352 @@
+
+# Python OpenFlow action wrapper classes
+
+from cstruct import *
+from match import roundup
+from match_list import match_list
+
+class action_pop_mpls(ofp_action_pop_mpls):
+ """
+ Wrapper class for pop_mpls action object
+
+ Data members inherited from ofp_action_pop_mpls:
+ @arg type
+ @arg len
+ @arg ethertype
+
+ """
+ def __init__(self):
+ ofp_action_pop_mpls.__init__(self)
+ self.type = OFPAT_POP_MPLS
+ self.len = self.__len__()
+ def show(self, prefix=''):
+ outstr = prefix + "action_pop_mpls\n"
+ outstr += ofp_action_pop_mpls.show(self, prefix)
+ return outstr
+
+
+class action_push_vlan(ofp_action_push):
+ """
+ Wrapper class for push_vlan action object
+
+ Data members inherited from ofp_action_push:
+ @arg type
+ @arg len
+ @arg ethertype
+
+ """
+ def __init__(self):
+ ofp_action_push.__init__(self)
+ self.type = OFPAT_PUSH_VLAN
+ self.len = self.__len__()
+ def show(self, prefix=''):
+ outstr = prefix + "action_push_vlan\n"
+ outstr += ofp_action_push.show(self, prefix)
+ return outstr
+
+
+class action_experimenter(ofp_action_experimenter_header):
+ """
+ Wrapper class for experimenter action object
+
+ Data members inherited from ofp_action_experimenter_header:
+ @arg type
+ @arg len
+ @arg experimenter
+
+ """
+ def __init__(self):
+ ofp_action_experimenter_header.__init__(self)
+ self.type = OFPAT_EXPERIMENTER
+ self.len = self.__len__()
+ def show(self, prefix=''):
+ outstr = prefix + "action_experimenter\n"
+ outstr += ofp_action_experimenter_header.show(self, prefix)
+ return outstr
+
+
+class action_dec_mpls_ttl(ofp_action_header):
+ """
+ Wrapper class for dec_mpls_ttl action object
+
+ Data members inherited from ofp_action_header:
+ @arg type
+ @arg len
+
+ """
+ def __init__(self):
+ ofp_action_header.__init__(self)
+ self.type = OFPAT_DEC_MPLS_TTL
+ self.len = self.__len__()
+ def show(self, prefix=''):
+ outstr = prefix + "action_dec_mpls_ttl\n"
+ outstr += ofp_action_header.show(self, prefix)
+ return outstr
+
+
+class action_set_nw_ttl(ofp_action_nw_ttl):
+ """
+ Wrapper class for set_nw_ttl action object
+
+ Data members inherited from ofp_action_nw_ttl:
+ @arg type
+ @arg len
+ @arg nw_ttl
+
+ """
+ def __init__(self):
+ ofp_action_nw_ttl.__init__(self)
+ self.type = OFPAT_SET_NW_TTL
+ self.len = self.__len__()
+ def show(self, prefix=''):
+ outstr = prefix + "action_set_nw_ttl\n"
+ outstr += ofp_action_nw_ttl.show(self, prefix)
+ return outstr
+
+
+class action_copy_ttl_in(ofp_action_header):
+ """
+ Wrapper class for copy_ttl_in action object
+
+ Data members inherited from ofp_action_header:
+ @arg type
+ @arg len
+
+ """
+ def __init__(self):
+ ofp_action_header.__init__(self)
+ self.type = OFPAT_COPY_TTL_IN
+ self.len = self.__len__()
+ def show(self, prefix=''):
+ outstr = prefix + "action_copy_ttl_in\n"
+ outstr += ofp_action_header.show(self, prefix)
+ return outstr
+
+
+class action_group(ofp_action_group):
+ """
+ Wrapper class for group action object
+
+ Data members inherited from ofp_action_group:
+ @arg type
+ @arg len
+ @arg group_id
+
+ """
+ def __init__(self):
+ ofp_action_group.__init__(self)
+ self.type = OFPAT_GROUP
+ self.len = self.__len__()
+ def show(self, prefix=''):
+ outstr = prefix + "action_group\n"
+ outstr += ofp_action_group.show(self, prefix)
+ return outstr
+ def __len__(self):
+ return roundup(4 + 4,8)
+
+
+class action_set_queue(ofp_action_set_queue):
+ """
+ Wrapper class for set_queue action object
+
+ Data members inherited from ofp_action_set_queue:
+ @arg type
+ @arg len
+ @arg queue_id
+
+ """
+ def __init__(self):
+ ofp_action_set_queue.__init__(self)
+ self.type = OFPAT_SET_QUEUE
+ self.len = self.__len__()
+ def show(self, prefix=''):
+ outstr = prefix + "action_set_queue\n"
+ outstr += ofp_action_set_queue.show(self, prefix)
+ return outstr
+
+
+class action_push_mpls(ofp_action_push):
+ """
+ Wrapper class for push_mpls action object
+
+ Data members inherited from ofp_action_push:
+ @arg type
+ @arg len
+ @arg ethertype
+
+ """
+ def __init__(self):
+ ofp_action_push.__init__(self)
+ self.type = OFPAT_PUSH_MPLS
+ self.len = self.__len__()
+ def show(self, prefix=''):
+ outstr = prefix + "action_push_mpls\n"
+ outstr += ofp_action_push.show(self, prefix)
+ return outstr
+
+
+class action_copy_ttl_out(ofp_action_header):
+ """
+ Wrapper class for copy_ttl_out action object
+
+ Data members inherited from ofp_action_header:
+ @arg type
+ @arg len
+
+ """
+ def __init__(self):
+ ofp_action_header.__init__(self)
+ self.type = OFPAT_COPY_TTL_OUT
+ self.len = self.__len__()
+ def show(self, prefix=''):
+ outstr = prefix + "action_copy_ttl_out\n"
+ outstr += ofp_action_header.show(self, prefix)
+ return outstr
+
+
+class action_set_field(ofp_action_set_field):
+ """
+ Wrapper class for set_field action object
+
+ Data members inherited from ofp_action_set_field:
+ @arg type
+ @arg len
+ @arg field
+
+ """
+ def __init__(self):
+ ofp_action_set_field.__init__(self)
+ self.type = OFPAT_SET_FIELD
+ self.len = self.__len__()
+ self.field = match_list()
+
+ def pack(self):
+ packed = ""
+ if len(self.field) <= 4:
+ packed += ofp_action_set_field.pack()
+ else:
+ self.len = len(self)
+ packed += struct.pack("!HH", self.type, self.len)
+ packed += self.field.pack()
+ padding_size = roundup(len(self.field) -4,8) - (len(self.field) -4)
+ if padding_size:
+ padding = [0] * padding_size
+ packed += struct.pack("!" + str(padding_size) + "B", *padding)
+ return packed
+
+ def unpack(self, binary_string):
+ if len(binary_string) <= 8:
+ binary_string = ofp_action_set_field.unpack(self)
+ else:
+ (self.type, self.len) = struct.unpack("!HH", binary_string[0:4])
+ binary_string = binary_string[4:]
+ binary_string = self.field.unpack(binary_string, bytes = self.len - 4)
+ padding_size = roundup(len(self.field) -4,8) - (len(self.field) -4)
+ if padding_size:
+ binary_string = binary_string[padding_size:]
+ return binary_string
+
+ def show(self, prefix=''):
+ outstr = prefix + "action_set_field\n"
+ outstr += ofp_action_set_field.show(self, prefix)
+ return outstr
+
+ def __len__(self):
+ return roundup(4 + len(self.field),8)
+
+
+class action_set_mpls_ttl(ofp_action_mpls_ttl):
+ """
+ Wrapper class for set_mpls_ttl action object
+
+ Data members inherited from ofp_action_mpls_ttl:
+ @arg type
+ @arg len
+ @arg mpls_ttl
+
+ """
+ def __init__(self):
+ ofp_action_mpls_ttl.__init__(self)
+ self.type = OFPAT_SET_MPLS_TTL
+ self.len = self.__len__()
+ def show(self, prefix=''):
+ outstr = prefix + "action_set_mpls_ttl\n"
+ outstr += ofp_action_mpls_ttl.show(self, prefix)
+ return outstr
+
+
+class action_pop_vlan(ofp_action_header):
+ """
+ Wrapper class for pop_vlan action object
+
+ Data members inherited from ofp_action_header:
+ @arg type
+ @arg len
+
+ """
+ def __init__(self):
+ ofp_action_header.__init__(self)
+ self.type = OFPAT_POP_VLAN
+ self.len = self.__len__()
+ def show(self, prefix=''):
+ outstr = prefix + "action_pop_vlan\n"
+ outstr += ofp_action_header.show(self, prefix)
+ return outstr
+
+
+class action_dec_nw_ttl(ofp_action_header):
+ """
+ Wrapper class for dec_nw_ttl action object
+
+ Data members inherited from ofp_action_header:
+ @arg type
+ @arg len
+
+ """
+ def __init__(self):
+ ofp_action_header.__init__(self)
+ self.type = OFPAT_DEC_NW_TTL
+ self.len = self.__len__()
+ def show(self, prefix=''):
+ outstr = prefix + "action_dec_nw_ttl\n"
+ outstr += ofp_action_header.show(self, prefix)
+ return outstr
+
+
+class action_output(ofp_action_output):
+ """
+ Wrapper class for output action object
+
+ Data members inherited from ofp_action_output:
+ @arg type
+ @arg len
+ @arg port
+ @arg max_len
+
+ """
+ def __init__(self):
+ ofp_action_output.__init__(self)
+ self.type = OFPAT_OUTPUT
+ self.len = self.__len__()
+ def show(self, prefix=''):
+ outstr = prefix + "action_output\n"
+ outstr += ofp_action_output.show(self, prefix)
+ return outstr
+
+action_class_list = (
+ action_copy_ttl_in,
+ action_copy_ttl_out,
+ action_dec_mpls_ttl,
+ action_dec_nw_ttl,
+ action_experimenter,
+ action_group,
+ action_output,
+ action_pop_mpls,
+ action_pop_vlan,
+ action_push_mpls,
+ action_push_vlan,
+ action_set_field,
+ action_set_mpls_ttl,
+ action_set_nw_ttl,
+ action_set_queue)
+
diff --git a/src/python/of12/action_list.py b/src/python/of12/action_list.py
new file mode 100644
index 0000000..c34f6af
--- /dev/null
+++ b/src/python/of12/action_list.py
@@ -0,0 +1,86 @@
+"""
+OpenFlow action, instruction and bucket list classes
+"""
+
+from action import *
+from cstruct import ofp_header
+from base_list import ofp_base_list
+import copy
+
+action_object_map = {
+ OFPAT_OUTPUT : action_output,
+ OFPAT_SET_FIELD : action_set_field,
+ OFPAT_COPY_TTL_OUT : action_copy_ttl_out,
+ OFPAT_COPY_TTL_IN : action_copy_ttl_in,
+ OFPAT_SET_MPLS_TTL : action_set_mpls_ttl,
+ OFPAT_DEC_MPLS_TTL : action_dec_mpls_ttl,
+ OFPAT_PUSH_VLAN : action_push_vlan,
+ OFPAT_POP_VLAN : action_pop_vlan,
+ OFPAT_PUSH_MPLS : action_push_mpls,
+ OFPAT_POP_MPLS : action_pop_mpls,
+ OFPAT_SET_QUEUE : action_set_queue,
+ OFPAT_GROUP : action_group,
+ OFPAT_SET_NW_TTL : action_set_nw_ttl,
+ OFPAT_DEC_NW_TTL : action_dec_nw_ttl,
+ OFPAT_EXPERIMENTER : action_experimenter
+}
+
+class action_list(ofp_base_list):
+ """
+ Maintain a list of actions
+
+ Data members:
+ @arg actions: An array of action objects such as action_output, etc.
+
+ Methods:
+ @arg pack: Pack the structure into a string
+ @arg unpack: Unpack a string to objects, with proper typing
+ @arg add: Add an action to the list; you can directly access
+ the action member, but add will validate that the added object
+ is an action.
+
+ """
+
+ def __init__(self):
+ ofp_base_list.__init__(self)
+ self.actions = self.items
+ self.name = "action"
+ self.class_list = action_class_list
+
+ def unpack(self, binary_string, bytes=None):
+ """
+ Unpack a list of actions
+
+ Unpack actions from a binary string, creating an array
+ of objects of the appropriate type
+
+ @param binary_string The string to be unpacked
+
+ @param bytes The total length of the action list in bytes.
+ Ignored if decode is True. If None and decode is false, the
+ list is assumed to extend through the entire string.
+
+ @return The remainder of binary_string that was not parsed
+
+ """
+ if bytes == None:
+ bytes = len(binary_string)
+ bytes_done = 0
+ count = 0
+ cur_string = binary_string
+ while bytes_done < bytes:
+ hdr = ofp_action_header()
+ hdr.unpack(cur_string)
+ if hdr.len < OFP_ACTION_HEADER_BYTES:
+ print "ERROR: Action too short"
+ break
+ if not hdr.type in action_object_map.keys():
+ print "WARNING: Skipping unknown action ", hdr.type, hdr.len
+ else:
+ self.actions.append(action_object_map[hdr.type]())
+ self.actions[count].unpack(cur_string)
+ count += 1
+ cur_string = cur_string[hdr.len:]
+ bytes_done += hdr.len
+ return cur_string
+
diff --git a/src/python/of12/base_list.py b/src/python/of12/base_list.py
new file mode 100644
index 0000000..938c68e
--- /dev/null
+++ b/src/python/of12/base_list.py
@@ -0,0 +1,158 @@
+
+"""
+Base list class for inheritance.
+Most of the list stuff is common; unpacking is the only thing that
+is left pure virtual.
+"""
+
+import copy
+
+class ofp_base_list(object):
+ """
+ Container type to maintain a list of ofp objects
+
+ Data members:
+ @arg items An array of objects
+ @arg class_list A tuple of classes that may be added to the list;
+ If None, no checking is done
+ @arg name The name to use when displaying the list
+
+ Methods:
+ @arg pack Pack the structure into a string
+ @arg unpack Unpack a string to objects, with proper typing
+ @arg add Add an item to the list; you can directly access
+ the item member, but add will validate that the added object
+ is of the right type.
+ @arg extend Add the items for another list to this list
+
+ """
+
+ def __init__(self):
+ self.items = []
+ self.class_list = None
+ self.name = "unspecified"
+
+ def pack(self):
+ """
+ Pack a list of items
+
+ Returns the packed string
+ """
+ packed = ""
+ for obj in self.items:
+ packed += obj.pack()
+ return packed
+
+ def unpack(self, binary_string, bytes=None):
+ """
+ Pure virtual function for a list of items
+
+ Unpack items from a binary string, creating an array
+ of objects of the appropriate type
+
+ @param binary_string The string to be unpacked
+
+ @param bytes The total length of the list in bytes.
+ Ignored if decode is True. If None and decode is false, the
+ list is assumed to extend through the entire string.
+
+ @return The remainder of binary_string that was not parsed
+ """
+ pass
+
+ def add(self, item):
+ """
+ Add an item to a list
+
+ @param item The item to add
+ @return True if successful, False if not proper type object
+
+ """
+
+ # Note that the second arg of isinstance can be a list which
+ # checks that the type of item is in the list
+ if (self.class_list is not None) and \
+ not isinstance(item, tuple(self.class_list)):
+ return False
+
+ tmp = copy.deepcopy(item)
+ self.items.append(tmp)
+ return True
+
+ def remove_type(self, target):
+ """
+ Remove the first item on the list of the given type
+
+ @param target The type of item to search
+
+ @return The object removed, if any; otherwise None
+
+ """
+ for index in xrange(len(self.items)):
+ if self.items[index].type == target:
+ return self.items.pop(index)
+ return None
+
+ def find_type(self, target):
+ """
+ Find the first item on the list of the given type
+
+ @param target The type of item to search
+
+ @return The object with the matching type if any; otherwise None
+
+ """
+ for index in xrange(len(self.items)):
+ if self.items[index].type == target:
+ return self.items[index]
+ return None
+
+ def extend(self, other):
+ """
+ Add the items in other to this list
+
+ @param other An object of the same type of list whose
+ entries are to be merged into this list
+
+ @return True if successful. If not successful, the list
+ may have been modified.
+
+ @todo Check if this is proper deep copy or not
+
+ """
+ for act in other.items:
+ if not self.add(act):
+ return False
+ return True
+
+ def __len__(self):
+ """
+ Length of the list packed as a string
+ """
+ length = 0
+ for item in self.items:
+ length += item.__len__()
+ return length
+
+ def __eq__(self, other):
+ if type(self) != type(other):
+ return False
+ if self.items != other.items:
+ return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ # Methods to make class iterable
+ def __iter__(self):
+ return self.items.__iter__()
+
+ def show(self, prefix=''):
+ outstr = prefix + self.name + "list with " + str(len(self.items)) + \
+ " items\n"
+ count = 0
+ for obj in self.items:
+ count += 1
+ outstr += prefix + " " + self.name + " " + str(count) + ": \n"
+ outstr += obj.show(prefix + ' ')
+ return outstr
diff --git a/src/python/of12/bucket.py b/src/python/of12/bucket.py
new file mode 100644
index 0000000..64caed1
--- /dev/null
+++ b/src/python/of12/bucket.py
@@ -0,0 +1,42 @@
+
+# Python OpenFlow bucket wrapper class
+
+from cstruct import ofp_bucket
+from action_list import action_list
+
+
+
+class bucket(ofp_bucket):
+ """
+ Wrapper class for bucket object
+
+ Data members inherited from ofp_bucket:
+ @arg len
+ @arg weight
+ @arg watch_port
+ @arg watch_group
+
+ """
+ def __init__(self):
+ ofp_bucket.__init__(self)
+ self.actions = action_list()
+ self.type = None
+ self.len = self.__len__()
+ def show(self, prefix=''):
+ outstr = prefix + "bucket\n"
+ outstr += ofp_bucket.show(self, prefix)
+ outstr += self.actions.show()
+ return outstr
+ def unpack(self, binary_string):
+ binary_string = ofp_bucket.unpack(self, binary_string)
+ self.actions = action_list()
+ return self.actions.unpack(binary_string)
+ def pack(self):
+ self.len = len(self)
+ packed = ""
+ packed += ofp_bucket.pack(self)
+ packed += self.actions.pack()
+ return packed
+ def __len__(self):
+ return ofp_bucket.__len__(self) + self.actions.__len__()
+
diff --git a/src/python/of12/bucket_list.py b/src/python/of12/bucket_list.py
new file mode 100644
index 0000000..33d9472
--- /dev/null
+++ b/src/python/of12/bucket_list.py
@@ -0,0 +1,52 @@
+
+from base_list import ofp_base_list
+from bucket import bucket
+
+class bucket_list(ofp_base_list):
+ """
+ Maintain a list of instructions
+
+ Data members:
+ @arg instructions An array of instructions such as write_actions
+
+ Methods:
+ @arg pack: Pack the structure into a string
+ @arg unpack: Unpack a string to objects, with proper typing
+ @arg add: Add an action to the list; you can directly access
+ the action member, but add will validate that the added object
+ is an action.
+
+ """
+
+ def __init__(self):
+ ofp_base_list.__init__(self)
+ self.buckets = self.items
+ self.name = "buckets"
+ self.class_list = (bucket,)
+
+ def unpack(self, binary_string, bytes=None):
+ """
+ Unpack a list of buckets
+
+ Unpack buckets from a binary string, creating an array
+ of objects of the appropriate type
+
+ @param binary_string The string to be unpacked
+
+ @param bytes The total length of the instruction list in bytes.
+ Ignored if decode is True. If bytes is None and decode is false, the
+ list is assumed to extend through the entire string.
+
+ @return The remainder of binary_string that was not parsed
+
+ """
+ if bytes == None:
+ bytes = len(binary_string)
+ bytes_done = 0
+ cur_string = binary_string
+ while bytes_done < bytes:
+ b = bucket()
+ cur_string = b.unpack(cur_string)
+ self.buckets.append(b)
+ bytes_done += len(b)
+ return cur_string
diff --git a/src/python/of12/class_maps.py b/src/python/of12/class_maps.py
new file mode 100644
index 0000000..cd60deb
--- /dev/null
+++ b/src/python/of12/class_maps.py
@@ -0,0 +1,346 @@
+
+# Class to array member map
+class_to_members_map = {
+ 'ofp_aggregate_stats_reply' : [
+ 'packet_count',
+ 'byte_count',
+ 'flow_count'
+ ],
+ 'ofp_role_request' : [
+ 'role',
+ 'generation_id'
+ ],
+ 'ofp_table_stats' : [
+ 'table_id',
+ 'name',
+ 'match',
+ 'wildcards',
+ 'write_actions',
+ 'apply_actions',
+ 'write_setfields',
+ 'apply_setfields',
+ 'metadata_match',
+ 'metadata_write',
+ 'instructions',
+ 'config',
+ 'max_entries',
+ 'active_count',
+ 'lookup_count',
+ 'matched_count'
+ ],
+ 'ofp_table_mod' : [
+ 'table_id',
+ 'config'
+ ],
+ 'ofp_group_stats' : [
+ 'length',
+ 'group_id',
+ 'ref_count',
+ 'packet_count',
+ 'byte_count'
+ ],
+ 'ofp_instruction_actions' : [
+ 'type',
+ 'len'
+ ],
+ 'ofp_queue_stats' : [
+ 'port_no',
+ 'queue_id',
+ 'tx_bytes',
+ 'tx_packets',
+ 'tx_errors'
+ ],
+ 'ofp_packet_in' : [
+ 'buffer_id',
+ 'total_len',
+ 'reason',
+ 'table_id',
+ 'match'
+ ],
+ 'ofp_error_experimenter_msg' : [
+ 'type',
+ 'exp_type',
+ 'experimenter'
+ ],
+ 'ofp_bucket_counter' : [
+ 'packet_count',
+ 'byte_count'
+ ],
+ 'ofp_port_stats_request' : [
+ 'port_no'
+ ],
+ 'ofp_stats_request' : [
+ 'type',
+ 'flags'
+ ],
+ 'ofp_instruction' : [
+ 'type',
+ 'len'
+ ],
+ 'ofp_group_stats_request' : [
+ 'group_id'
+ ],
+ 'ofp_experimenter_header' : [
+ 'experimenter',
+ 'exp_type'
+ ],
+ 'ofp_aggregate_stats_request' : [
+ 'table_id',
+ 'out_port',
+ 'out_group',
+ 'cookie',
+ 'cookie_mask',
+ 'match'
+ ],
+ 'ofp_queue_get_config_request' : [
+ 'port'
+ ],
+ 'ofp_action_nw_ttl' : [
+ 'type',
+ 'len',
+ 'nw_ttl'
+ ],
+ 'ofp_port_status' : [
+ 'reason',
+ 'desc'
+ ],
+ 'ofp_action_header' : [
+ 'type',
+ 'len'
+ ],
+ 'ofp_port_mod' : [
+ 'port_no',
+ 'hw_addr',
+ 'config',
+ 'mask',
+ 'advertise'
+ ],
+ 'ofp_action_output' : [
+ 'type',
+ 'len',
+ 'port',
+ 'max_len'
+ ],
+ 'ofp_switch_config' : [
+ 'flags',
+ 'miss_send_len'
+ ],
+ 'ofp_queue_prop_experimenter' : [
+ 'prop_header',
+ 'experimenter'
+ ],
+ 'ofp_instruction_write_metadata' : [
+ 'type',
+ 'len',
+ 'metadata',
+ 'metadata_mask'
+ ],
+ 'ofp_action_experimenter_header' : [
+ 'type',
+ 'len',
+ 'experimenter'
+ ],
+ 'ofp_queue_get_config_reply' : [
+ 'port'
+ ],
+ 'ofp_oxm_experimenter_header' : [
+ 'oxm_header',
+ 'experimenter'
+ ],
+ 'ofp_action_set_queue' : [
+ 'type',
+ 'len',
+ 'queue_id'
+ ],
+ 'ofp_action_set_field' : [
+ 'type',
+ 'len',
+ 'field'
+ ],
+ 'ofp_flow_stats' : [
+ 'length',
+ 'table_id',
+ 'duration_sec',
+ 'duration_nsec',
+ 'priority',
+ 'idle_timeout',
+ 'hard_timeout',
+ 'cookie',
+ 'packet_count',
+ 'byte_count',
+ 'match'
+ ],
+ 'ofp_flow_removed' : [
+ 'cookie',
+ 'priority',
+ 'reason',
+ 'table_id',
+ 'duration_sec',
+ 'duration_nsec',
+ 'idle_timeout',
+ 'hard_timeout',
+ 'packet_count',
+ 'byte_count',
+ 'match'
+ ],
+ 'ofp_queue_prop_min_rate' : [
+ 'prop_header',
+ 'rate'
+ ],
+ 'ofp_header' : [
+ 'version',
+ 'type',
+ 'length',
+ 'xid'
+ ],
+ 'ofp_stats_reply' : [
+ 'type',
+ 'flags'
+ ],
+ 'ofp_queue_stats_request' : [
+ 'port_no',
+ 'queue_id'
+ ],
+ 'ofp_group_features_stats' : [
+ 'types',
+ 'capabilities',
+ 'max_groups',
+ 'actions'
+ ],
+ 'ofp_group_mod' : [
+ 'command',
+ 'type',
+ 'group_id'
+ ],
+ 'ofp_port_stats' : [
+ 'port_no',
+ 'rx_packets',
+ 'tx_packets',
+ 'rx_bytes',
+ 'tx_bytes',
+ 'rx_dropped',
+ 'tx_dropped',
+ 'rx_errors',
+ 'tx_errors',
+ 'rx_frame_err',
+ 'rx_over_err',
+ 'rx_crc_err',
+ 'collisions'
+ ],
+ 'ofp_packet_queue' : [
+ 'queue_id',
+ 'port',
+ 'len'
+ ],
+ 'ofp_port' : [
+ 'port_no',
+ 'hw_addr',
+ 'name',
+ 'config',
+ 'state',
+ 'curr',
+ 'advertised',
+ 'supported',
+ 'peer',
+ 'curr_speed',
+ 'max_speed'
+ ],
+ 'ofp_switch_features' : [
+ 'datapath_id',
+ 'n_buffers',
+ 'n_tables',
+ 'capabilities',
+ 'reserved'
+ ],
+ 'ofp_queue_prop_header' : [
+ 'property',
+ 'len'
+ ],
+ 'ofp_flow_stats_request' : [
+ 'table_id',
+ 'out_port',
+ 'out_group',
+ 'cookie',
+ 'cookie_mask',
+ 'match'
+ ],
+ 'ofp_bucket' : [
+ 'len',
+ 'weight',
+ 'watch_port',
+ 'watch_group'
+ ],
+ 'ofp_action_pop_mpls' : [
+ 'type',
+ 'len',
+ 'ethertype'
+ ],
+ 'ofp_match' : [
+ 'type',
+ 'length'
+ ],
+ 'ofp_flow_mod' : [
+ 'cookie',
+ 'cookie_mask',
+ 'table_id',
+ 'command',
+ 'idle_timeout',
+ 'hard_timeout',
+ 'priority',
+ 'buffer_id',
+ 'out_port',
+ 'out_group',
+ 'flags',
+ 'match'
+ ],
+ 'ofp_packet_out' : [
+ 'buffer_id',
+ 'in_port',
+ 'actions_len'
+ ],
+ 'ofp_instruction_goto_table' : [
+ 'type',
+ 'len',
+ 'table_id'
+ ],
+ 'ofp_queue_prop_max_rate' : [
+ 'prop_header',
+ 'rate'
+ ],
+ 'ofp_experimenter_stats_header' : [
+ 'experimenter',
+ 'exp_type'
+ ],
+ 'ofp_action_group' : [
+ 'type',
+ 'len',
+ 'group_id'
+ ],
+ 'ofp_desc_stats' : [
+ 'mfr_desc',
+ 'hw_desc',
+ 'sw_desc',
+ 'serial_num',
+ 'dp_desc'
+ ],
+ 'ofp_action_push' : [
+ 'type',
+ 'len',
+ 'ethertype'
+ ],
+ 'ofp_group_desc_stats' : [
+ 'length',
+ 'type',
+ 'group_id'
+ ],
+ 'ofp_error_msg' : [
+ 'type',
+ 'code'
+ ],
+ 'ofp_action_mpls_ttl' : [
+ 'type',
+ 'len',
+ 'mpls_ttl'
+ ],
+ '_ignore' : []
+}
diff --git a/src/python/of12/cstruct.py b/src/python/of12/cstruct.py
new file mode 100644
index 0000000..06f9ac9
--- /dev/null
+++ b/src/python/of12/cstruct.py
@@ -0,0 +1,5922 @@
+import struct
+
+# Structure definitions
+class ofp_hello(object):
+ """Automatically generated Python class for ofp_hello
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+
+ def __assert(self):
+ """Sanity check
+ """
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 0):
+ return binaryString
+ return binaryString[0:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 0
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ return outstr
+
+
+class ofp_aggregate_stats_reply(object):
+ """Automatically generated Python class for ofp_aggregate_stats_reply
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.packet_count = 0
+ self.byte_count = 0
+ self.flow_count = 0
+ self.pad= [0,0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 4):
+ return (False, "self.pad is not of size 4 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!QQL", self.packet_count, self.byte_count, self.flow_count)
+ packed += struct.pack("!BBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 24):
+ return binaryString
+ fmt = '!QQL'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.packet_count, self.byte_count, self.flow_count) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 20
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[24:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 24
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.packet_count != other.packet_count: return False
+ if self.byte_count != other.byte_count: return False
+ if self.flow_count != other.flow_count: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'packet_count: ' + str(self.packet_count) + '\n'
+ outstr += prefix + 'byte_count: ' + str(self.byte_count) + '\n'
+ outstr += prefix + 'flow_count: ' + str(self.flow_count) + '\n'
+ return outstr
+
+
+class ofp_role_request(object):
+ """Automatically generated Python class for ofp_role_request
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.role = 0
+ self.pad= [0,0,0,0]
+ self.generation_id = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 4):
+ return (False, "self.pad is not of size 4 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!L", self.role)
+ packed += struct.pack("!BBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3])
+ packed += struct.pack("!Q", self.generation_id)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 16):
+ return binaryString
+ fmt = '!L'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.role,) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 4
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3]) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!Q'
+ start = 8
+ end = start + struct.calcsize(fmt)
+ (self.generation_id,) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[16:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 16
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.role != other.role: return False
+ if self.pad != other.pad: return False
+ if self.generation_id != other.generation_id: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'role: ' + str(self.role) + '\n'
+ outstr += prefix + 'generation_id: ' + str(self.generation_id) + '\n'
+ return outstr
+
+
+class ofp_table_stats(object):
+ """Automatically generated Python class for ofp_table_stats
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.table_id = 0
+ self.pad= [0,0,0,0,0,0,0]
+ self.name= ""
+ self.match = 0
+ self.wildcards = 0
+ self.write_actions = 0
+ self.apply_actions = 0
+ self.write_setfields = 0
+ self.apply_setfields = 0
+ self.metadata_match = 0
+ self.metadata_write = 0
+ self.instructions = 0
+ self.config = 0
+ self.max_entries = 0
+ self.active_count = 0
+ self.lookup_count = 0
+ self.matched_count = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 7):
+ return (False, "self.pad is not of size 7 as expected.")
+ if(not isinstance(self.name, str)):
+ return (False, "self.name is not string as expected.")
+ if(len(self.name) > 32):
+ return (False, "self.name is not of size 32 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!B", self.table_id)
+ packed += struct.pack("!BBBBBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3], self.pad[4], self.pad[5], self.pad[6])
+ packed += self.name.ljust(32,'\0')
+ packed += struct.pack("!QQLLQQQQLLLLQQ", self.match, self.wildcards, self.write_actions, self.apply_actions, self.write_setfields, self.apply_setfields, self.metadata_match, self.metadata_write, self.instructions, self.config, self.max_entries, self.active_count, self.lookup_count, self.matched_count)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 128):
+ return binaryString
+ fmt = '!B'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.table_id,) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBBBBB'
+ start = 1
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3], self.pad[4], self.pad[5], self.pad[6]) = struct.unpack(fmt, binaryString[start:end])
+ self.name = binaryString[8:40].replace("\0","")
+ fmt = '!QQLLQQQQLLLLQQ'
+ start = 40
+ end = start + struct.calcsize(fmt)
+ (self.match, self.wildcards, self.write_actions, self.apply_actions, self.write_setfields, self.apply_setfields, self.metadata_match, self.metadata_write, self.instructions, self.config, self.max_entries, self.active_count, self.lookup_count, self.matched_count) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[128:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 128
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.table_id != other.table_id: return False
+ if self.pad != other.pad: return False
+ if self.name != other.name: return False
+ if self.match != other.match: return False
+ if self.wildcards != other.wildcards: return False
+ if self.write_actions != other.write_actions: return False
+ if self.apply_actions != other.apply_actions: return False
+ if self.write_setfields != other.write_setfields: return False
+ if self.apply_setfields != other.apply_setfields: return False
+ if self.metadata_write != other.metadata_match: return False
+ if self.metadata_write != other.metadata_write: return False
+ if self.instructions != other.instructions: return False
+ if self.config != other.config: return False
+ if self.max_entries != other.max_entries: return False
+ if self.active_count != other.active_count: return False
+ if self.lookup_count != other.lookup_count: return False
+ if self.matched_count != other.matched_count: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'table_id: ' + str(self.table_id) + '\n'
+ outstr += prefix + 'name: ' + str(self.name) + '\n'
+ outstr += prefix + 'match: ' + str(self.match) + '\n'
+ outstr += prefix + 'wildcards: ' + str(self.wildcards) + '\n'
+ outstr += prefix + 'write_actions: ' + str(self.write_actions) + '\n'
+ outstr += prefix + 'apply_actions: ' + str(self.apply_actions) + '\n'
+ outstr += prefix + 'write_setfields: ' + str(self.write_setfields) + '\n'
+ outstr += prefix + 'apply_setfields: ' + str(self.apply_setfields) + '\n'
+ outstr += prefix + 'metadata_match: ' + str(self.metadata_match) + '\n'
+ outstr += prefix + 'metadata_write: ' + str(self.metadata_write) + '\n'
+ outstr += prefix + 'instructions: ' + str(self.instructions) + '\n'
+ outstr += prefix + 'config: ' + str(self.config) + '\n'
+ outstr += prefix + 'max_entries: ' + str(self.max_entries) + '\n'
+ outstr += prefix + 'active_count: ' + str(self.active_count) + '\n'
+ outstr += prefix + 'lookup_count: ' + str(self.lookup_count) + '\n'
+ outstr += prefix + 'matched_count: ' + str(self.matched_count) + '\n'
+ return outstr
+
+
+class ofp_table_mod(object):
+ """Automatically generated Python class for ofp_table_mod
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.table_id = 0
+ self.pad= [0,0,0]
+ self.config = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 3):
+ return (False, "self.pad is not of size 3 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!B", self.table_id)
+ packed += struct.pack("!BBB", self.pad[0], self.pad[1], self.pad[2])
+ packed += struct.pack("!L", self.config)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!B'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.table_id,) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBB'
+ start = 1
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2]) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!L'
+ start = 4
+ end = start + struct.calcsize(fmt)
+ (self.config,) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.table_id != other.table_id: return False
+ if self.pad != other.pad: return False
+ if self.config != other.config: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'table_id: ' + str(self.table_id) + '\n'
+ outstr += prefix + 'config: ' + str(self.config) + '\n'
+ return outstr
+
+
+class ofp_group_stats(object):
+ """Automatically generated Python class for ofp_group_stats
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.length = 0
+ self.pad= [0,0]
+ self.group_id = 0
+ self.ref_count = 0
+ self.pad2= [0,0,0,0]
+ self.packet_count = 0
+ self.byte_count = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 2):
+ return (False, "self.pad is not of size 2 as expected.")
+ if(not isinstance(self.pad2, list)):
+ return (False, "self.pad2 is not list as expected.")
+ if(len(self.pad2) != 4):
+ return (False, "self.pad2 is not of size 4 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!H", self.length)
+ packed += struct.pack("!BB", self.pad[0], self.pad[1])
+ packed += struct.pack("!LL", self.group_id, self.ref_count)
+ packed += struct.pack("!BBBB", self.pad2[0], self.pad2[1], self.pad2[2], self.pad2[3])
+ packed += struct.pack("!QQ", self.packet_count, self.byte_count)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 32):
+ return binaryString
+ fmt = '!H'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.length,) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BB'
+ start = 2
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1]) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!LL'
+ start = 4
+ end = start + struct.calcsize(fmt)
+ (self.group_id, self.ref_count) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 12
+ end = start + struct.calcsize(fmt)
+ (self.pad2[0], self.pad2[1], self.pad2[2], self.pad2[3]) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!QQ'
+ start = 16
+ end = start + struct.calcsize(fmt)
+ (self.packet_count, self.byte_count) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[32:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 32
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.length != other.length: return False
+ if self.pad != other.pad: return False
+ if self.group_id != other.group_id: return False
+ if self.ref_count != other.ref_count: return False
+ if self.pad2 != other.pad2: return False
+ if self.packet_count != other.packet_count: return False
+ if self.byte_count != other.byte_count: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'length: ' + str(self.length) + '\n'
+ outstr += prefix + 'group_id: ' + str(self.group_id) + '\n'
+ outstr += prefix + 'ref_count: ' + str(self.ref_count) + '\n'
+ outstr += prefix + 'packet_count: ' + str(self.packet_count) + '\n'
+ outstr += prefix + 'byte_count: ' + str(self.byte_count) + '\n'
+ return outstr
+
+
+class ofp_instruction_actions(object):
+ """Automatically generated Python class for ofp_instruction_actions
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.type = 0
+ self.len = 0
+ self.pad= [0,0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 4):
+ return (False, "self.pad is not of size 4 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HH", self.type, self.len)
+ packed += struct.pack("!BBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!HH'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.type, self.len) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 4
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.type != other.type: return False
+ if self.len != other.len: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'len: ' + str(self.len) + '\n'
+ return outstr
+
+
+class ofp_queue_stats(object):
+ """Automatically generated Python class for ofp_queue_stats
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.port_no = 0
+ self.queue_id = 0
+ self.tx_bytes = 0
+ self.tx_packets = 0
+ self.tx_errors = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!LLQQQ", self.port_no, self.queue_id, self.tx_bytes, self.tx_packets, self.tx_errors)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 32):
+ return binaryString
+ fmt = '!LLQQQ'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.port_no, self.queue_id, self.tx_bytes, self.tx_packets, self.tx_errors) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[32:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 32
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.port_no != other.port_no: return False
+ if self.queue_id != other.queue_id: return False
+ if self.tx_bytes != other.tx_bytes: return False
+ if self.tx_packets != other.tx_packets: return False
+ if self.tx_errors != other.tx_errors: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'port_no: ' + str(self.port_no) + '\n'
+ outstr += prefix + 'queue_id: ' + str(self.queue_id) + '\n'
+ outstr += prefix + 'tx_bytes: ' + str(self.tx_bytes) + '\n'
+ outstr += prefix + 'tx_packets: ' + str(self.tx_packets) + '\n'
+ outstr += prefix + 'tx_errors: ' + str(self.tx_errors) + '\n'
+ return outstr
+
+
+class ofp_packet_in(object):
+ """Automatically generated Python class for ofp_packet_in
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.buffer_id = 0
+ self.total_len = 0
+ self.reason = 0
+ self.table_id = 0
+ self.match = ofp_match()
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.match, ofp_match)):
+ return (False, "self.match is not class ofp_match as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!LHBB", self.buffer_id, self.total_len, self.reason, self.table_id)
+ packed += self.match.pack()
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 12):
+ return binaryString
+ fmt = '!LHBB'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.buffer_id, self.total_len, self.reason, self.table_id) = struct.unpack(fmt, binaryString[start:end])
+ self.match.unpack(binaryString[8:])
+ return binaryString[12:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 12
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.buffer_id != other.buffer_id: return False
+ if self.total_len != other.total_len: return False
+ if self.reason != other.reason: return False
+ if self.table_id != other.table_id: return False
+ if self.match != other.match: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'buffer_id: ' + str(self.buffer_id) + '\n'
+ outstr += prefix + 'total_len: ' + str(self.total_len) + '\n'
+ outstr += prefix + 'reason: ' + str(self.reason) + '\n'
+ outstr += prefix + 'table_id: ' + str(self.table_id) + '\n'
+ outstr += prefix + 'match: \n'
+ outstr += self.match.show(prefix + ' ')
+ return outstr
+
+
+class ofp_error_experimenter_msg(object):
+ """Automatically generated Python class for ofp_error_experimenter_msg
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.type = 0
+ self.exp_type = 0
+ self.experimenter = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HHL", self.type, self.exp_type, self.experimenter)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!HHL'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.type, self.exp_type, self.experimenter) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.type != other.type: return False
+ if self.exp_type != other.exp_type: return False
+ if self.experimenter != other.experimenter: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'exp_type: ' + str(self.exp_type) + '\n'
+ outstr += prefix + 'experimenter: ' + str(self.experimenter) + '\n'
+ return outstr
+
+
+class ofp_bucket_counter(object):
+ """Automatically generated Python class for ofp_bucket_counter
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.packet_count = 0
+ self.byte_count = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!QQ", self.packet_count, self.byte_count)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 16):
+ return binaryString
+ fmt = '!QQ'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.packet_count, self.byte_count) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[16:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 16
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.packet_count != other.packet_count: return False
+ if self.byte_count != other.byte_count: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'packet_count: ' + str(self.packet_count) + '\n'
+ outstr += prefix + 'byte_count: ' + str(self.byte_count) + '\n'
+ return outstr
+
+
+class ofp_port_stats_request(object):
+ """Automatically generated Python class for ofp_port_stats_request
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.port_no = 0
+ self.pad= [0,0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 4):
+ return (False, "self.pad is not of size 4 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!L", self.port_no)
+ packed += struct.pack("!BBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!L'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.port_no,) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 4
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.port_no != other.port_no: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'port_no: ' + str(self.port_no) + '\n'
+ return outstr
+
+
+class ofp_stats_request(object):
+ """Automatically generated Python class for ofp_stats_request
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.type = 0
+ self.flags = 0
+ self.pad= [0,0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 4):
+ return (False, "self.pad is not of size 4 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HH", self.type, self.flags)
+ packed += struct.pack("!BBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!HH'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.type, self.flags) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 4
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.type != other.type: return False
+ if self.flags != other.flags: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'flags: ' + str(self.flags) + '\n'
+ return outstr
+
+
+class ofp_instruction(object):
+ """Automatically generated Python class for ofp_instruction
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.type = 0
+ self.len = 0
+ self.pad= [0,0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 4):
+ return (False, "self.pad is not of size 4 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HH", self.type, self.len)
+ packed += struct.pack("!BBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!HH'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.type, self.len) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 4
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.type != other.type: return False
+ if self.len != other.len: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'len: ' + str(self.len) + '\n'
+ return outstr
+
+
+class ofp_group_stats_request(object):
+ """Automatically generated Python class for ofp_group_stats_request
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.group_id = 0
+ self.pad= [0,0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 4):
+ return (False, "self.pad is not of size 4 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!L", self.group_id)
+ packed += struct.pack("!BBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!L'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.group_id,) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 4
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.group_id != other.group_id: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'group_id: ' + str(self.group_id) + '\n'
+ return outstr
+
+
+class ofp_experimenter_header(object):
+ """Automatically generated Python class for ofp_experimenter_header
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.experimenter = 0
+ self.exp_type = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!LL", self.experimenter, self.exp_type)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!LL'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.experimenter, self.exp_type) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.experimenter != other.experimenter: return False
+ if self.exp_type != other.exp_type: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'experimenter: ' + str(self.experimenter) + '\n'
+ outstr += prefix + 'exp_type: ' + str(self.exp_type) + '\n'
+ return outstr
+
+
+class ofp_aggregate_stats_request(object):
+ """Automatically generated Python class for ofp_aggregate_stats_request
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.table_id = 0
+ self.pad_asr= [0,0,0]
+ self.out_port = 0
+ self.out_group = 0
+ self.pad_asr2= [0,0,0,0]
+ self.cookie = 0
+ self.cookie_mask = 0
+ self.match = ofp_match()
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad_asr, list)):
+ return (False, "self.pad_asr is not list as expected.")
+ if(len(self.pad_asr) != 3):
+ return (False, "self.pad_asr is not of size 3 as expected.")
+ if(not isinstance(self.pad_asr2, list)):
+ return (False, "self.pad_asr2 is not list as expected.")
+ if(len(self.pad_asr2) != 4):
+ return (False, "self.pad_asr2 is not of size 4 as expected.")
+ if(not isinstance(self.match, ofp_match)):
+ return (False, "self.match is not class ofp_match as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!B", self.table_id)
+ packed += struct.pack("!BBB", self.pad_asr[0], self.pad_asr[1], self.pad_asr[2])
+ packed += struct.pack("!LL", self.out_port, self.out_group)
+ packed += struct.pack("!BBBB", self.pad_asr2[0], self.pad_asr2[1], self.pad_asr2[2], self.pad_asr2[3])
+ packed += struct.pack("!QQ", self.cookie, self.cookie_mask)
+ packed += self.match.pack()
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 36):
+ return binaryString
+ fmt = '!B'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.table_id,) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBB'
+ start = 1
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad_asr[1], self.pad_asr[2]) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!LL'
+ start = 4
+ end = start + struct.calcsize(fmt)
+ (self.out_port, self.out_group) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 12
+ end = start + struct.calcsize(fmt)
+ (self.pad2[0], self.pad_asr2[1], self.pad_asr2[2], self.pad_asr2[3]) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!QQ'
+ start = 16
+ end = start + struct.calcsize(fmt)
+ (self.cookie, self.cookie_mask) = struct.unpack(fmt, binaryString[start:end])
+ self.match.unpack(binaryString[32:])
+ return binaryString[36:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 36
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.table_id != other.table_id: return False
+ if self.pad != other.pad: return False
+ if self.out_port != other.out_port: return False
+ if self.out_group != other.out_group: return False
+ if self.pad2 != other.pad2: return False
+ if self.cookie != other.cookie: return False
+ if self.cookie_mask != other.cookie_mask: return False
+ if self.match != other.match: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'table_id: ' + str(self.table_id) + '\n'
+ outstr += prefix + 'out_port: ' + str(self.out_port) + '\n'
+ outstr += prefix + 'out_group: ' + str(self.out_group) + '\n'
+ outstr += prefix + 'cookie: ' + str(self.cookie) + '\n'
+ outstr += prefix + 'cookie_mask: ' + str(self.cookie_mask) + '\n'
+ outstr += prefix + 'match: \n'
+ outstr += self.match.show(prefix + ' ')
+ return outstr
+
+
+class ofp_queue_get_config_request(object):
+ """Automatically generated Python class for ofp_queue_get_config_request
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.port = 0
+ self.pad= [0,0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 4):
+ return (False, "self.pad is not of size 4 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!L", self.port)
+ packed += struct.pack("!BBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!L'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.port,) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 4
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.port != other.port: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'port: ' + str(self.port) + '\n'
+ return outstr
+
+
+class ofp_action_nw_ttl(object):
+ """Automatically generated Python class for ofp_action_nw_ttl
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.type = 0
+ self.len = 0
+ self.nw_ttl = 0
+ self.pad= [0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 3):
+ return (False, "self.pad is not of size 3 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HHB", self.type, self.len, self.nw_ttl)
+ packed += struct.pack("!BBB", self.pad[0], self.pad[1], self.pad[2])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!HHB'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.type, self.len, self.nw_ttl) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBB'
+ start = 5
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.type != other.type: return False
+ if self.len != other.len: return False
+ if self.nw_ttl != other.nw_ttl: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'len: ' + str(self.len) + '\n'
+ outstr += prefix + 'nw_ttl: ' + str(self.nw_ttl) + '\n'
+ return outstr
+
+
+class ofp_port_status(object):
+ """Automatically generated Python class for ofp_port_status
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.reason = 0
+ self.pad= [0,0,0,0,0,0,0]
+ self.desc = ofp_port()
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 7):
+ return (False, "self.pad is not of size 7 as expected.")
+ if(not isinstance(self.desc, ofp_port)):
+ return (False, "self.desc is not class ofp_port as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!B", self.reason)
+ packed += struct.pack("!BBBBBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3], self.pad[4], self.pad[5], self.pad[6])
+ packed += self.desc.pack()
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 72):
+ return binaryString
+ fmt = '!B'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.reason,) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBBBBB'
+ start = 1
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3], self.pad[4], self.pad[5], self.pad[6]) = struct.unpack(fmt, binaryString[start:end])
+ self.desc.unpack(binaryString[8:])
+ return binaryString[72:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 72
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.reason != other.reason: return False
+ if self.pad != other.pad: return False
+ if self.desc != other.desc: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'reason: ' + str(self.reason) + '\n'
+ outstr += prefix + 'desc: \n'
+ outstr += self.desc.show(prefix + ' ')
+ return outstr
+
+
+class ofp_action_header(object):
+ """Automatically generated Python class for ofp_action_header
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.type = 0
+ self.len = 0
+ self.pad= [0,0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 4):
+ return (False, "self.pad is not of size 4 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HH", self.type, self.len)
+ packed += struct.pack("!BBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!HH'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.type, self.len) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 4
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.type != other.type: return False
+ if self.len != other.len: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'len: ' + str(self.len) + '\n'
+ return outstr
+
+
+class ofp_port_mod(object):
+ """Automatically generated Python class for ofp_port_mod
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.port_no = 0
+ self.pad= [0,0,0,0]
+ self.hw_addr= [0,0,0,0,0,0]
+ self.pad2= [0,0]
+ self.config = 0
+ self.mask = 0
+ self.advertise = 0
+ self.pad3= [0,0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 4):
+ return (False, "self.pad is not of size 4 as expected.")
+ if(not isinstance(self.hw_addr, list)):
+ return (False, "self.hw_addr is not list as expected.")
+ if(len(self.hw_addr) != 6):
+ return (False, "self.hw_addr is not of size 6 as expected.")
+ if(not isinstance(self.pad2, list)):
+ return (False, "self.pad2 is not list as expected.")
+ if(len(self.pad2) != 2):
+ return (False, "self.pad2 is not of size 2 as expected.")
+ if(not isinstance(self.pad3, list)):
+ return (False, "self.pad3 is not list as expected.")
+ if(len(self.pad3) != 4):
+ return (False, "self.pad3 is not of size 4 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!L", self.port_no)
+ packed += struct.pack("!BBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3])
+ packed += struct.pack("!BBBBBB", self.hw_addr[0], self.hw_addr[1], self.hw_addr[2], self.hw_addr[3], self.hw_addr[4], self.hw_addr[5])
+ packed += struct.pack("!BB", self.pad2[0], self.pad2[1])
+ packed += struct.pack("!LLL", self.config, self.mask, self.advertise)
+ packed += struct.pack("!BBBB", self.pad3[0], self.pad3[1], self.pad3[2], self.pad3[3])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 32):
+ return binaryString
+ fmt = '!L'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.port_no,) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 4
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3]) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBBBB'
+ start = 8
+ end = start + struct.calcsize(fmt)
+ (self.hw_addr[0], self.hw_addr[1], self.hw_addr[2], self.hw_addr[3], self.hw_addr[4], self.hw_addr[5]) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BB'
+ start = 14
+ end = start + struct.calcsize(fmt)
+ (self.pad2[0], self.pad2[1]) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!LLL'
+ start = 16
+ end = start + struct.calcsize(fmt)
+ (self.config, self.mask, self.advertise) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 28
+ end = start + struct.calcsize(fmt)
+ (self.pad3[0], self.pad3[1], self.pad3[2], self.pad3[3]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[32:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 32
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.port_no != other.port_no: return False
+ if self.pad != other.pad: return False
+ if self.hw_addr != other.hw_addr: return False
+ if self.pad2 != other.pad2: return False
+ if self.config != other.config: return False
+ if self.mask != other.mask: return False
+ if self.advertise != other.advertise: return False
+ if self.pad3 != other.pad3: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'port_no: ' + str(self.port_no) + '\n'
+ outstr += prefix + 'hw_addr: ' + str(self.hw_addr) + '\n'
+ outstr += prefix + 'config: ' + str(self.config) + '\n'
+ outstr += prefix + 'mask: ' + str(self.mask) + '\n'
+ outstr += prefix + 'advertise: ' + str(self.advertise) + '\n'
+ return outstr
+
+
+class ofp_action_output(object):
+ """Automatically generated Python class for ofp_action_output
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.type = 0
+ self.len = 0
+ self.port = 0
+ self.max_len = 0
+ self.pad= [0,0,0,0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 6):
+ return (False, "self.pad is not of size 6 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HHLH", self.type, self.len, self.port, self.max_len)
+ packed += struct.pack("!BBBBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3], self.pad[4], self.pad[5])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 16):
+ return binaryString
+ fmt = '!HHLH'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.type, self.len, self.port, self.max_len) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBBBB'
+ start = 10
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3], self.pad[4], self.pad[5]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[16:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 16
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.type != other.type: return False
+ if self.len != other.len: return False
+ if self.port != other.port: return False
+ if self.max_len != other.max_len: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'len: ' + str(self.len) + '\n'
+ outstr += prefix + 'port: ' + str(self.port) + '\n'
+ outstr += prefix + 'max_len: ' + str(self.max_len) + '\n'
+ return outstr
+
+
+class ofp_switch_config(object):
+ """Automatically generated Python class for ofp_switch_config
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.flags = 0
+ self.miss_send_len = 128
+
+ def __assert(self):
+ """Sanity check
+ """
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HH", self.flags, self.miss_send_len)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 4):
+ return binaryString
+ fmt = '!HH'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.flags, self.miss_send_len) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[4:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 4
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.flags != other.flags: return False
+ if self.miss_send_len != other.miss_send_len: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'flags: ' + str(self.flags) + '\n'
+ outstr += prefix + 'miss_send_len: ' + str(self.miss_send_len) + '\n'
+ return outstr
+
+
+class ofp_queue_prop_experimenter(object):
+ """Automatically generated Python class for ofp_queue_prop_experimenter
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.prop_header = ofp_queue_prop_header()
+ self.experimenter = 0
+ self.pad= [0,0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.prop_header, ofp_queue_prop_header)):
+ return (False, "self.prop_header is not class ofp_queue_prop_header as expected.")
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 4):
+ return (False, "self.pad is not of size 4 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += self.prop_header.pack()
+ packed += struct.pack("!L", self.experimenter)
+ packed += struct.pack("!BBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 16):
+ return binaryString
+ self.prop_header.unpack(binaryString[0:])
+ fmt = '!L'
+ start = 8
+ end = start + struct.calcsize(fmt)
+ (self.experimenter,) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 12
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[16:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 16
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.prop_header != other.prop_header: return False
+ if self.experimenter != other.experimenter: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'prop_header: \n'
+ outstr += self.prop_header.show(prefix + ' ')
+ outstr += prefix + 'experimenter: ' + str(self.experimenter) + '\n'
+ return outstr
+
+
+class ofp_instruction_write_metadata(object):
+ """Automatically generated Python class for ofp_instruction_write_metadata
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.type = 0
+ self.len = 0
+ self.pad= [0,0,0,0]
+ self.metadata = 0
+ self.metadata_mask = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 4):
+ return (False, "self.pad is not of size 4 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HH", self.type, self.len)
+ packed += struct.pack("!BBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3])
+ packed += struct.pack("!QQ", self.metadata, self.metadata_mask)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 24):
+ return binaryString
+ fmt = '!HH'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.type, self.len) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 4
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3]) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!QQ'
+ start = 8
+ end = start + struct.calcsize(fmt)
+ (self.metadata, self.metadata_mask) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[24:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 24
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.type != other.type: return False
+ if self.len != other.len: return False
+ if self.pad != other.pad: return False
+ if self.metadata != other.metadata: return False
+ if self.metadata_mask != other.metadata_mask: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'len: ' + str(self.len) + '\n'
+ outstr += prefix + 'metadata: ' + str(self.metadata) + '\n'
+ outstr += prefix + 'metadata_mask: ' + str(self.metadata_mask) + '\n'
+ return outstr
+
+
+class ofp_action_experimenter_header(object):
+ """Automatically generated Python class for ofp_action_experimenter_header
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.type = 0
+ self.len = 0
+ self.experimenter = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HHL", self.type, self.len, self.experimenter)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!HHL'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.type, self.len, self.experimenter) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.type != other.type: return False
+ if self.len != other.len: return False
+ if self.experimenter != other.experimenter: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'len: ' + str(self.len) + '\n'
+ outstr += prefix + 'experimenter: ' + str(self.experimenter) + '\n'
+ return outstr
+
+
+class ofp_queue_get_config_reply(object):
+ """Automatically generated Python class for ofp_queue_get_config_reply
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.port = 0
+ self.pad= [0,0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 4):
+ return (False, "self.pad is not of size 4 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!L", self.port)
+ packed += struct.pack("!BBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!L'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.port,) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 4
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.port != other.port: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'port: ' + str(self.port) + '\n'
+ return outstr
+
+
+class ofp_oxm_experimenter_header(object):
+ """Automatically generated Python class for ofp_oxm_experimenter_header
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.oxm_header = 0
+ self.experimenter = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!LL", self.oxm_header, self.experimenter)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!LL'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.oxm_header, self.experimenter) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.oxm_header != other.oxm_header: return False
+ if self.experimenter != other.experimenter: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'oxm_header: ' + str(self.oxm_header) + '\n'
+ outstr += prefix + 'experimenter: ' + str(self.experimenter) + '\n'
+ return outstr
+
+
+class ofp_action_set_queue(object):
+ """Automatically generated Python class for ofp_action_set_queue
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.type = 0
+ self.len = 0
+ self.queue_id = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HHL", self.type, self.len, self.queue_id)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!HHL'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.type, self.len, self.queue_id) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.type != other.type: return False
+ if self.len != other.len: return False
+ if self.queue_id != other.queue_id: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'len: ' + str(self.len) + '\n'
+ outstr += prefix + 'queue_id: ' + str(self.queue_id) + '\n'
+ return outstr
+
+
+class ofp_action_set_field(object):
+ """Automatically generated Python class for ofp_action_set_field
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.type = 0
+ self.len = 0
+ self.field= [0,0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.field, list)):
+ return (False, "self.field is not list as expected.")
+ if(len(self.field) != 4):
+ return (False, "self.field is not of size 4 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HH", self.type, self.len)
+ packed += struct.pack("!BBBB", self.field[0], self.field[1], self.field[2], self.field[3])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!HH'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.type, self.len) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 4
+ end = start + struct.calcsize(fmt)
+ (self.field[0], self.field[1], self.field[2], self.field[3]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.type != other.type: return False
+ if self.len != other.len: return False
+ if self.field != other.field: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'len: ' + str(self.len) + '\n'
+ outstr += prefix + 'field: ' + str(self.field) + '\n'
+ return outstr
+
+
+class ofp_flow_stats(object):
+ """Automatically generated Python class for ofp_flow_stats
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.length = 0
+ self.table_id = 0
+ self.pad = 0
+ self.duration_sec = 0
+ self.duration_nsec = 0
+ self.priority = 0x8000
+ self.idle_timeout = 0
+ self.hard_timeout = 0
+ self.pad2= [0,0,0,0,0,0]
+ self.cookie = 0
+ self.packet_count = 0
+ self.byte_count = 0
+ self.match = ofp_match()
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad2, list)):
+ return (False, "self.pad2 is not list as expected.")
+ if(len(self.pad2) != 6):
+ return (False, "self.pad2 is not of size 6 as expected.")
+ if(not isinstance(self.match, ofp_match)):
+ return (False, "self.match is not class ofp_match as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HBBLLHHH", self.length, self.table_id, self.pad, self.duration_sec, self.duration_nsec, self.priority, self.idle_timeout, self.hard_timeout)
+ packed += struct.pack("!BBBBBB", self.pad2[0], self.pad2[1], self.pad2[2], self.pad2[3], self.pad2[4], self.pad2[5])
+ packed += struct.pack("!QQQ", self.cookie, self.packet_count, self.byte_count)
+ packed += self.match.pack()
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 52):
+ return binaryString
+ fmt = '!HBBLLHHH'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.length, self.table_id, self.pad, self.duration_sec, self.duration_nsec, self.priority, self.idle_timeout, self.hard_timeout) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBBBB'
+ start = 18
+ end = start + struct.calcsize(fmt)
+ (self.pad2[0], self.pad2[1], self.pad2[2], self.pad2[3], self.pad2[4], self.pad2[5]) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!QQQ'
+ start = 24
+ end = start + struct.calcsize(fmt)
+ (self.cookie, self.packet_count, self.byte_count) = struct.unpack(fmt, binaryString[start:end])
+ self.match.unpack(binaryString[48:])
+ return binaryString[52:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 52
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.length != other.length: return False
+ if self.table_id != other.table_id: return False
+ if self.pad != other.pad: return False
+ if self.duration_sec != other.duration_sec: return False
+ if self.duration_nsec != other.duration_nsec: return False
+ if self.priority != other.priority: return False
+ if self.idle_timeout != other.idle_timeout: return False
+ if self.hard_timeout != other.hard_timeout: return False
+ if self.pad2 != other.pad2: return False
+ if self.cookie != other.cookie: return False
+ if self.packet_count != other.packet_count: return False
+ if self.byte_count != other.byte_count: return False
+ if self.match != other.match: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'length: ' + str(self.length) + '\n'
+ outstr += prefix + 'table_id: ' + str(self.table_id) + '\n'
+ outstr += prefix + 'duration_sec: ' + str(self.duration_sec) + '\n'
+ outstr += prefix + 'duration_nsec: ' + str(self.duration_nsec) + '\n'
+ outstr += prefix + 'priority: ' + str(self.priority) + '\n'
+ outstr += prefix + 'idle_timeout: ' + str(self.idle_timeout) + '\n'
+ outstr += prefix + 'hard_timeout: ' + str(self.hard_timeout) + '\n'
+ outstr += prefix + 'cookie: ' + str(self.cookie) + '\n'
+ outstr += prefix + 'packet_count: ' + str(self.packet_count) + '\n'
+ outstr += prefix + 'byte_count: ' + str(self.byte_count) + '\n'
+ outstr += prefix + 'match: \n'
+ outstr += self.match.show(prefix + ' ')
+ return outstr
+
+
+class ofp_flow_removed(object):
+ """Automatically generated Python class for ofp_flow_removed
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.cookie = 0
+ self.priority = 0
+ self.reason = 0
+ self.table_id = 0
+ self.duration_sec = 0
+ self.duration_nsec = 0
+ self.idle_timeout = 0
+ self.hard_timeout = 0
+ self.packet_count = 0
+ self.byte_count = 0
+ self.match = ofp_match()
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.match, ofp_match)):
+ return (False, "self.match is not class ofp_match as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!QHBBLLHHQQ", self.cookie, self.priority, self.reason, self.table_id, self.duration_sec, self.duration_nsec, self.idle_timeout, self.hard_timeout, self.packet_count, self.byte_count)
+ packed += self.match.pack()
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 44):
+ return binaryString
+ fmt = '!QHBBLLHHQQ'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.cookie, self.priority, self.reason, self.table_id, self.duration_sec, self.duration_nsec, self.idle_timeout, self.hard_timeout, self.packet_count, self.byte_count) = struct.unpack(fmt, binaryString[start:end])
+ self.match.unpack(binaryString[40:])
+ return binaryString[44:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 44
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.cookie != other.cookie: return False
+ if self.priority != other.priority: return False
+ if self.reason != other.reason: return False
+ if self.table_id != other.table_id: return False
+ if self.duration_sec != other.duration_sec: return False
+ if self.duration_nsec != other.duration_nsec: return False
+ if self.idle_timeout != other.idle_timeout: return False
+ if self.hard_timeout != other.hard_timeout: return False
+ if self.packet_count != other.packet_count: return False
+ if self.byte_count != other.byte_count: return False
+ if self.match != other.match: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'cookie: ' + str(self.cookie) + '\n'
+ outstr += prefix + 'priority: ' + str(self.priority) + '\n'
+ outstr += prefix + 'reason: ' + str(self.reason) + '\n'
+ outstr += prefix + 'table_id: ' + str(self.table_id) + '\n'
+ outstr += prefix + 'duration_sec: ' + str(self.duration_sec) + '\n'
+ outstr += prefix + 'duration_nsec: ' + str(self.duration_nsec) + '\n'
+ outstr += prefix + 'idle_timeout: ' + str(self.idle_timeout) + '\n'
+ outstr += prefix + 'hard_timeout: ' + str(self.hard_timeout) + '\n'
+ outstr += prefix + 'packet_count: ' + str(self.packet_count) + '\n'
+ outstr += prefix + 'byte_count: ' + str(self.byte_count) + '\n'
+ outstr += prefix + 'match: \n'
+ outstr += self.match.show(prefix + ' ')
+ return outstr
+
+
+class ofp_queue_prop_min_rate(object):
+ """Automatically generated Python class for ofp_queue_prop_min_rate
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.prop_header = ofp_queue_prop_header()
+ self.rate = 0
+ self.pad= [0,0,0,0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.prop_header, ofp_queue_prop_header)):
+ return (False, "self.prop_header is not class ofp_queue_prop_header as expected.")
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 6):
+ return (False, "self.pad is not of size 6 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += self.prop_header.pack()
+ packed += struct.pack("!H", self.rate)
+ packed += struct.pack("!BBBBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3], self.pad[4], self.pad[5])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 16):
+ return binaryString
+ self.prop_header.unpack(binaryString[0:])
+ fmt = '!H'
+ start = 8
+ end = start + struct.calcsize(fmt)
+ (self.rate,) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBBBB'
+ start = 10
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3], self.pad[4], self.pad[5]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[16:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 16
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.prop_header != other.prop_header: return False
+ if self.rate != other.rate: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'prop_header: \n'
+ outstr += self.prop_header.show(prefix + ' ')
+ outstr += prefix + 'rate: ' + str(self.rate) + '\n'
+ return outstr
+
+
+class ofp_header(object):
+ """Automatically generated Python class for ofp_header
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.version = 0x03
+ self.type = 0
+ self.length = 0
+ self.xid = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ if (not (self.type in ofp_type_map.keys())):
+ return (False, "type must have values from ofp_type_map.keys()")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!BBHL", self.version, self.type, self.length, self.xid)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!BBHL'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.version, self.type, self.length, self.xid) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.version != other.version: return False
+ if self.type != other.type: return False
+ if self.length != other.length: return False
+ if self.xid != other.xid: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'version: ' + str(self.version) + '\n'
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'length: ' + str(self.length) + '\n'
+ outstr += prefix + 'xid: ' + str(self.xid) + '\n'
+ return outstr
+
+
+class ofp_stats_reply(object):
+ """Automatically generated Python class for ofp_stats_reply
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.type = 0
+ self.flags = 0
+ self.pad= [0,0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 4):
+ return (False, "self.pad is not of size 4 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HH", self.type, self.flags)
+ packed += struct.pack("!BBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!HH'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.type, self.flags) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 4
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.type != other.type: return False
+ if self.flags != other.flags: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'flags: ' + str(self.flags) + '\n'
+ return outstr
+
+
+class ofp_queue_stats_request(object):
+ """Automatically generated Python class for ofp_queue_stats_request
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.port_no = 0
+ self.queue_id = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!LL", self.port_no, self.queue_id)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!LL'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.port_no, self.queue_id) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.port_no != other.port_no: return False
+ if self.queue_id != other.queue_id: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'port_no: ' + str(self.port_no) + '\n'
+ outstr += prefix + 'queue_id: ' + str(self.queue_id) + '\n'
+ return outstr
+
+
+class ofp_group_features_stats(object):
+ """Automatically generated Python class for ofp_group_features_stats
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.types = 0
+ self.capabilities = 0
+ self.max_groups= [0,0,0,0]
+ self.actions= [0,0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.max_groups, list)):
+ return (False, "self.max_groups is not list as expected.")
+ if(len(self.max_groups) != 4):
+ return (False, "self.max_groups is not of size 4 as expected.")
+ if(not isinstance(self.actions, list)):
+ return (False, "self.actions is not list as expected.")
+ if(len(self.actions) != 4):
+ return (False, "self.actions is not of size 4 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!LL", self.types, self.capabilities)
+ packed += struct.pack("!LLLL", self.max_groups[0], self.max_groups[1], self.max_groups[2], self.max_groups[3])
+ packed += struct.pack("!LLLL", self.actions[0], self.actions[1], self.actions[2], self.actions[3])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 40):
+ return binaryString
+ fmt = '!LL'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.types, self.capabilities) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!LLLL'
+ start = 8
+ end = start + struct.calcsize(fmt)
+ (self.max_groups[0], self.max_groups[1], self.max_groups[2], self.max_groups[3]) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!LLLL'
+ start = 24
+ end = start + struct.calcsize(fmt)
+ (self.actions[0], self.actions[1], self.actions[2], self.actions[3]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[40:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 40
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.types != other.types: return False
+ if self.capabilities != other.capabilities: return False
+ if self.max_groups != other.max_groups: return False
+ if self.actions != other.actions: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'types: ' + str(self.types) + '\n'
+ outstr += prefix + 'capabilities: ' + str(self.capabilities) + '\n'
+ outstr += prefix + 'max_groups: ' + str(self.max_groups) + '\n'
+ outstr += prefix + 'actions: ' + str(self.actions) + '\n'
+ return outstr
+
+
+class ofp_group_mod(object):
+ """Automatically generated Python class for ofp_group_mod
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.command = 0
+ self.type = 0
+ self.pad = 0
+ self.group_id = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HBBL", self.command, self.type, self.pad, self.group_id)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!HBBL'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.command, self.type, self.pad, self.group_id) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.command != other.command: return False
+ if self.type != other.type: return False
+ if self.pad != other.pad: return False
+ if self.group_id != other.group_id: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'command: ' + str(self.command) + '\n'
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'group_id: ' + str(self.group_id) + '\n'
+ return outstr
+
+
+class ofp_port_stats(object):
+ """Automatically generated Python class for ofp_port_stats
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.port_no = 0
+ self.pad= [0,0,0,0]
+ self.rx_packets = 0
+ self.tx_packets = 0
+ self.rx_bytes = 0
+ self.tx_bytes = 0
+ self.rx_dropped = 0
+ self.tx_dropped = 0
+ self.rx_errors = 0
+ self.tx_errors = 0
+ self.rx_frame_err = 0
+ self.rx_over_err = 0
+ self.rx_crc_err = 0
+ self.collisions = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 4):
+ return (False, "self.pad is not of size 4 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!L", self.port_no)
+ packed += struct.pack("!BBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3])
+ packed += struct.pack("!QQQQQQQQQQQQ", self.rx_packets, self.tx_packets, self.rx_bytes, self.tx_bytes, self.rx_dropped, self.tx_dropped, self.rx_errors, self.tx_errors, self.rx_frame_err, self.rx_over_err, self.rx_crc_err, self.collisions)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 104):
+ return binaryString
+ fmt = '!L'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.port_no,) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 4
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3]) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!QQQQQQQQQQQQ'
+ start = 8
+ end = start + struct.calcsize(fmt)
+ (self.rx_packets, self.tx_packets, self.rx_bytes, self.tx_bytes, self.rx_dropped, self.tx_dropped, self.rx_errors, self.tx_errors, self.rx_frame_err, self.rx_over_err, self.rx_crc_err, self.collisions) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[104:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 104
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.port_no != other.port_no: return False
+ if self.pad != other.pad: return False
+ if self.rx_packets != other.rx_packets: return False
+ if self.tx_packets != other.tx_packets: return False
+ if self.rx_bytes != other.rx_bytes: return False
+ if self.tx_bytes != other.tx_bytes: return False
+ if self.rx_dropped != other.rx_dropped: return False
+ if self.tx_dropped != other.tx_dropped: return False
+ if self.rx_errors != other.rx_errors: return False
+ if self.tx_errors != other.tx_errors: return False
+ if self.rx_frame_err != other.rx_frame_err: return False
+ if self.rx_over_err != other.rx_over_err: return False
+ if self.rx_crc_err != other.rx_crc_err: return False
+ if self.collisions != other.collisions: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'port_no: ' + str(self.port_no) + '\n'
+ outstr += prefix + 'rx_packets: ' + str(self.rx_packets) + '\n'
+ outstr += prefix + 'tx_packets: ' + str(self.tx_packets) + '\n'
+ outstr += prefix + 'rx_bytes: ' + str(self.rx_bytes) + '\n'
+ outstr += prefix + 'tx_bytes: ' + str(self.tx_bytes) + '\n'
+ outstr += prefix + 'rx_dropped: ' + str(self.rx_dropped) + '\n'
+ outstr += prefix + 'tx_dropped: ' + str(self.tx_dropped) + '\n'
+ outstr += prefix + 'rx_errors: ' + str(self.rx_errors) + '\n'
+ outstr += prefix + 'tx_errors: ' + str(self.tx_errors) + '\n'
+ outstr += prefix + 'rx_frame_err: ' + str(self.rx_frame_err) + '\n'
+ outstr += prefix + 'rx_over_err: ' + str(self.rx_over_err) + '\n'
+ outstr += prefix + 'rx_crc_err: ' + str(self.rx_crc_err) + '\n'
+ outstr += prefix + 'collisions: ' + str(self.collisions) + '\n'
+ return outstr
+
+
+class ofp_packet_queue(object):
+ """Automatically generated Python class for ofp_packet_queue
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.queue_id = 0
+ self.port = 0
+ self.len = 0
+ self.pad= [0,0,0,0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 6):
+ return (False, "self.pad is not of size 6 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!LLH", self.queue_id, self.port, self.len)
+ packed += struct.pack("!BBBBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3], self.pad[4], self.pad[5])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 16):
+ return binaryString
+ fmt = '!LLH'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.queue_id, self.port, self.len) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBBBB'
+ start = 10
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3], self.pad[4], self.pad[5]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[16:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 16
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.queue_id != other.queue_id: return False
+ if self.port != other.port: return False
+ if self.len != other.len: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'queue_id: ' + str(self.queue_id) + '\n'
+ outstr += prefix + 'port: ' + str(self.port) + '\n'
+ outstr += prefix + 'len: ' + str(self.len) + '\n'
+ return outstr
+
+
+class ofp_port(object):
+ """Automatically generated Python class for ofp_port
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.port_no = 0
+ self.pad= [0,0,0,0]
+ self.hw_addr= [0,0,0,0,0,0]
+ self.pad2= [0,0]
+ self.name= ""
+ self.config = 0
+ self.state = 0
+ self.curr = 0
+ self.advertised = 0
+ self.supported = 0
+ self.peer = 0
+ self.curr_speed = 0
+ self.max_speed = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 4):
+ return (False, "self.pad is not of size 4 as expected.")
+ if(not isinstance(self.hw_addr, list)):
+ return (False, "self.hw_addr is not list as expected.")
+ if(len(self.hw_addr) != 6):
+ return (False, "self.hw_addr is not of size 6 as expected.")
+ if(not isinstance(self.pad2, list)):
+ return (False, "self.pad2 is not list as expected.")
+ if(len(self.pad2) != 2):
+ return (False, "self.pad2 is not of size 2 as expected.")
+ if(not isinstance(self.name, str)):
+ return (False, "self.name is not string as expected.")
+ if(len(self.name) > 16):
+ return (False, "self.name is not of size 16 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!L", self.port_no)
+ packed += struct.pack("!BBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3])
+ packed += struct.pack("!BBBBBB", self.hw_addr[0], self.hw_addr[1], self.hw_addr[2], self.hw_addr[3], self.hw_addr[4], self.hw_addr[5])
+ packed += struct.pack("!BB", self.pad2[0], self.pad2[1])
+ packed += self.name.ljust(16,'\0')
+ packed += struct.pack("!LLLLLLLL", self.config, self.state, self.curr, self.advertised, self.supported, self.peer, self.curr_speed, self.max_speed)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 64):
+ return binaryString
+ fmt = '!L'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.port_no,) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 4
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3]) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBBBB'
+ start = 8
+ end = start + struct.calcsize(fmt)
+ (self.hw_addr[0], self.hw_addr[1], self.hw_addr[2], self.hw_addr[3], self.hw_addr[4], self.hw_addr[5]) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BB'
+ start = 14
+ end = start + struct.calcsize(fmt)
+ (self.pad2[0], self.pad2[1]) = struct.unpack(fmt, binaryString[start:end])
+ self.name = binaryString[16:32].replace("\0","")
+ fmt = '!LLLLLLLL'
+ start = 32
+ end = start + struct.calcsize(fmt)
+ (self.config, self.state, self.curr, self.advertised, self.supported, self.peer, self.curr_speed, self.max_speed) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[64:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 64
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.port_no != other.port_no: return False
+ if self.pad != other.pad: return False
+ if self.hw_addr != other.hw_addr: return False
+ if self.pad2 != other.pad2: return False
+ if self.name != other.name: return False
+ if self.config != other.config: return False
+ if self.state != other.state: return False
+ if self.curr != other.curr: return False
+ if self.advertised != other.advertised: return False
+ if self.supported != other.supported: return False
+ if self.peer != other.peer: return False
+ if self.curr_speed != other.curr_speed: return False
+ if self.max_speed != other.max_speed: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'port_no: ' + str(self.port_no) + '\n'
+ outstr += prefix + 'hw_addr: ' + str(self.hw_addr) + '\n'
+ outstr += prefix + 'name: ' + str(self.name) + '\n'
+ outstr += prefix + 'config: ' + str(self.config) + '\n'
+ outstr += prefix + 'state: ' + str(self.state) + '\n'
+ outstr += prefix + 'curr: ' + str(self.curr) + '\n'
+ outstr += prefix + 'advertised: ' + str(self.advertised) + '\n'
+ outstr += prefix + 'supported: ' + str(self.supported) + '\n'
+ outstr += prefix + 'peer: ' + str(self.peer) + '\n'
+ outstr += prefix + 'curr_speed: ' + str(self.curr_speed) + '\n'
+ outstr += prefix + 'max_speed: ' + str(self.max_speed) + '\n'
+ return outstr
+
+
+class ofp_switch_features(object):
+ """Automatically generated Python class for ofp_switch_features
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.datapath_id = 0
+ self.n_buffers = 0
+ self.n_tables = 0
+ self.pad= [0,0,0]
+ self.capabilities = 0
+ self.reserved = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 3):
+ return (False, "self.pad is not of size 3 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!QLB", self.datapath_id, self.n_buffers, self.n_tables)
+ packed += struct.pack("!BBB", self.pad[0], self.pad[1], self.pad[2])
+ packed += struct.pack("!LL", self.capabilities, self.reserved)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 24):
+ return binaryString
+ fmt = '!QLB'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.datapath_id, self.n_buffers, self.n_tables) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBB'
+ start = 13
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2]) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!LL'
+ start = 16
+ end = start + struct.calcsize(fmt)
+ (self.capabilities, self.reserved) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[24:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 24
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.datapath_id != other.datapath_id: return False
+ if self.n_buffers != other.n_buffers: return False
+ if self.n_tables != other.n_tables: return False
+ if self.pad != other.pad: return False
+ if self.capabilities != other.capabilities: return False
+ if self.reserved != other.reserved: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'datapath_id: ' + str(self.datapath_id) + '\n'
+ outstr += prefix + 'n_buffers: ' + str(self.n_buffers) + '\n'
+ outstr += prefix + 'n_tables: ' + str(self.n_tables) + '\n'
+ outstr += prefix + 'capabilities: ' + str(self.capabilities) + '\n'
+ outstr += prefix + 'reserved: ' + str(self.reserved) + '\n'
+ return outstr
+
+
+class ofp_queue_prop_header(object):
+ """Automatically generated Python class for ofp_queue_prop_header
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.property = 0
+ self.len = 0
+ self.pad= [0,0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 4):
+ return (False, "self.pad is not of size 4 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HH", self.property, self.len)
+ packed += struct.pack("!BBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!HH'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.property, self.len) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 4
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.property != other.property: return False
+ if self.len != other.len: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'property: ' + str(self.property) + '\n'
+ outstr += prefix + 'len: ' + str(self.len) + '\n'
+ return outstr
+
+
+class ofp_flow_stats_request(object):
+ """Automatically generated Python class for ofp_flow_stats_request
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.table_id = 0
+ self.pad_fstat= [0,0,0]
+ self.out_port = 0
+ self.out_group = 0
+ self.pad_fstat2= [0,0,0,0]
+ self.cookie = 0
+ self.cookie_mask = 0
+ self.match = ofp_match()
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad_fstat is not list as expected.")
+ if(len(self.pad_fstat) != 3):
+ return (False, "self.pad_fstat is not of size 3 as expected.")
+ if(not isinstance(self.pad_fstat2, list)):
+ return (False, "self.pad_fstat2 is not list as expected.")
+ if(len(self.pad_fstat2) != 4):
+ return (False, "self.pad_ftsat2 is not of size 4 as expected.")
+ if(not isinstance(self.match, ofp_match)):
+ return (False, "self.match is not class ofp_match as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!B", self.table_id)
+ packed += struct.pack("!BBB", self.pad_fstat[0], self.pad_fstat[1], self.pad_fstat[2])
+ packed += struct.pack("!LL", self.out_port, self.out_group)
+ packed += struct.pack("!BBBB", self.pad_fstat2[0], self.pad_fstat2[1], self.pad_fstat2[2], self.pad_fstat2[3])
+ packed += struct.pack("!QQ", self.cookie, self.cookie_mask)
+ packed += self.match.pack()
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 36):
+ return binaryString
+ fmt = '!B'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.table_id,) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBB'
+ start = 1
+ end = start + struct.calcsize(fmt)
+ (self.pad_fstat[0], self.pad_fstat[1], self.pad_fstat[2]) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!LL'
+ start = 4
+ end = start + struct.calcsize(fmt)
+ (self.out_port, self.out_group) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 12
+ end = start + struct.calcsize(fmt)
+ (self.pad_fstat2[0], self.pad_fstat2[1], self.pad_fstat2[2], self.pad_fstat2[3]) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!QQ'
+ start = 16
+ end = start + struct.calcsize(fmt)
+ (self.cookie, self.cookie_mask) = struct.unpack(fmt, binaryString[start:end])
+ self.match.unpack(binaryString[32:])
+ return binaryString[36:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 36
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.table_id != other.table_id: return False
+ if self.pad_fstat != other.pad_fstat: return False
+ if self.out_port != other.out_port: return False
+ if self.out_group != other.out_group: return False
+ if self.pad_fstat2 != other.pad_fstat2: return False
+ if self.cookie != other.cookie: return False
+ if self.cookie_mask != other.cookie_mask: return False
+ if self.match != other.match: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'table_id: ' + str(self.table_id) + '\n'
+ outstr += prefix + 'out_port: ' + str(self.out_port) + '\n'
+ outstr += prefix + 'out_group: ' + str(self.out_group) + '\n'
+ outstr += prefix + 'cookie: ' + str(self.cookie) + '\n'
+ outstr += prefix + 'cookie_mask: ' + str(self.cookie_mask) + '\n'
+ outstr += prefix + 'match: \n'
+ outstr += self.match.show(prefix + ' ')
+ return outstr
+
+
+class ofp_bucket(object):
+ """Automatically generated Python class for ofp_bucket
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.len = 0
+ self.weight = 0
+ self.watch_port = 0
+ self.watch_group = 0
+ self.pad= [0,0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 4):
+ return (False, "self.pad is not of size 4 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HHLL", self.len, self.weight, self.watch_port, self.watch_group)
+ packed += struct.pack("!BBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 16):
+ return binaryString
+ fmt = '!HHLL'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.len, self.weight, self.watch_port, self.watch_group) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBB'
+ start = 12
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[16:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 16
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.len != other.len: return False
+ if self.weight != other.weight: return False
+ if self.watch_port != other.watch_port: return False
+ if self.watch_group != other.watch_group: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'len: ' + str(self.len) + '\n'
+ outstr += prefix + 'weight: ' + str(self.weight) + '\n'
+ outstr += prefix + 'watch_port: ' + str(self.watch_port) + '\n'
+ outstr += prefix + 'watch_group: ' + str(self.watch_group) + '\n'
+ return outstr
+
+
+class ofp_action_pop_mpls(object):
+ """Automatically generated Python class for ofp_action_pop_mpls
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.type = 0
+ self.len = 0
+ self.ethertype = 0
+ self.pad= [0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 2):
+ return (False, "self.pad is not of size 2 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HHH", self.type, self.len, self.ethertype)
+ packed += struct.pack("!BB", self.pad[0], self.pad[1])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!HHH'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.type, self.len, self.ethertype) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BB'
+ start = 6
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.type != other.type: return False
+ if self.len != other.len: return False
+ if self.ethertype != other.ethertype: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'len: ' + str(self.len) + '\n'
+ outstr += prefix + 'ethertype: ' + str(self.ethertype) + '\n'
+ return outstr
+
+
+class ofp_match(object):
+ """Automatically generated Python class for ofp_match
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.type = OFPMT_OXM
+ #exclude padding bytes
+ self.length = OFP_MATCH_BYTES
+
+ def __assert(self):
+ """Sanity check
+ """
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HH", self.type, self.length)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 4):
+ return binaryString
+ fmt = '!HH'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.type, self.length) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[4:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 4
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.type != other.type: return False
+ if self.length != other.length: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'length: ' + str(self.length) + '\n'
+ return outstr
+
+
+class ofp_flow_mod(object):
+ """Automatically generated Python class for ofp_flow_mod
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.cookie = 0
+ self.cookie_mask = 0
+ self.table_id = 0
+ self.command = 0
+ self.idle_timeout = 0
+ self.hard_timeout = 0
+ self.priority = 0x8000
+ self.buffer_id = 0
+ self.out_port = 0
+ self.out_group = 0
+ self.flags = 0
+ self.pad= [0,0]
+ self.match = ofp_match()
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 2):
+ return (False, "self.pad is not of size 2 as expected.")
+ if(not isinstance(self.match, ofp_match)):
+ return (False, "self.match is not class ofp_match as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!QQBBHHHLLLH", self.cookie, self.cookie_mask, self.table_id, self.command, self.idle_timeout, self.hard_timeout, self.priority, self.buffer_id, self.out_port, self.out_group, self.flags)
+ packed += struct.pack("!BB", self.pad[0], self.pad[1])
+ packed += self.match.pack()
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 44):
+ return binaryString
+ fmt = '!QQBBHHHLLLH'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.cookie, self.cookie_mask, self.table_id, self.command, self.idle_timeout, self.hard_timeout, self.priority, self.buffer_id, self.out_port, self.out_group, self.flags) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BB'
+ start = 38
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1]) = struct.unpack(fmt, binaryString[start:end])
+ self.match.unpack(binaryString[40:])
+ return binaryString[44:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 44
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.cookie != other.cookie: return False
+ if self.cookie_mask != other.cookie_mask: return False
+ if self.table_id != other.table_id: return False
+ if self.command != other.command: return False
+ if self.idle_timeout != other.idle_timeout: return False
+ if self.hard_timeout != other.hard_timeout: return False
+ if self.priority != other.priority: return False
+ if self.buffer_id != other.buffer_id: return False
+ if self.out_port != other.out_port: return False
+ if self.out_group != other.out_group: return False
+ if self.flags != other.flags: return False
+ if self.pad != other.pad: return False
+ if self.match != other.match: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'cookie: ' + str(self.cookie) + '\n'
+ outstr += prefix + 'cookie_mask: ' + str(self.cookie_mask) + '\n'
+ outstr += prefix + 'table_id: ' + str(self.table_id) + '\n'
+ outstr += prefix + 'command: ' + str(self.command) + '\n'
+ outstr += prefix + 'idle_timeout: ' + str(self.idle_timeout) + '\n'
+ outstr += prefix + 'hard_timeout: ' + str(self.hard_timeout) + '\n'
+ outstr += prefix + 'priority: ' + str(self.priority) + '\n'
+ outstr += prefix + 'buffer_id: ' + str(self.buffer_id) + '\n'
+ outstr += prefix + 'out_port: ' + str(self.out_port) + '\n'
+ outstr += prefix + 'out_group: ' + str(self.out_group) + '\n'
+ outstr += prefix + 'flags: ' + str(self.flags) + '\n'
+ outstr += prefix + 'match: \n'
+ outstr += self.match.show(prefix + ' ')
+ return outstr
+
+
+class ofp_packet_out(object):
+ """Automatically generated Python class for ofp_packet_out
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.buffer_id = 4294967295
+ self.in_port = 0
+ self.actions_len = 0
+ self.pad= [0,0,0,0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 6):
+ return (False, "self.pad is not of size 6 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!LLH", self.buffer_id, self.in_port, self.actions_len)
+ packed += struct.pack("!BBBBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3], self.pad[4], self.pad[5])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 16):
+ return binaryString
+ fmt = '!LLH'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.buffer_id, self.in_port, self.actions_len) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBBBB'
+ start = 10
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3], self.pad[4], self.pad[5]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[16:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 16
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.buffer_id != other.buffer_id: return False
+ if self.in_port != other.in_port: return False
+ if self.actions_len != other.actions_len: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'buffer_id: ' + str(self.buffer_id) + '\n'
+ outstr += prefix + 'in_port: ' + str(self.in_port) + '\n'
+ outstr += prefix + 'actions_len: ' + str(self.actions_len) + '\n'
+ return outstr
+
+
+class ofp_instruction_goto_table(object):
+ """Automatically generated Python class for ofp_instruction_goto_table
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.type = 0
+ self.len = 0
+ self.table_id = 0
+ self.pad= [0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 3):
+ return (False, "self.pad is not of size 3 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HHB", self.type, self.len, self.table_id)
+ packed += struct.pack("!BBB", self.pad[0], self.pad[1], self.pad[2])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!HHB'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.type, self.len, self.table_id) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBB'
+ start = 5
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.type != other.type: return False
+ if self.len != other.len: return False
+ if self.table_id != other.table_id: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'len: ' + str(self.len) + '\n'
+ outstr += prefix + 'table_id: ' + str(self.table_id) + '\n'
+ return outstr
+
+
+class ofp_queue_prop_max_rate(object):
+ """Automatically generated Python class for ofp_queue_prop_max_rate
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.prop_header = ofp_queue_prop_header()
+ self.rate = 0
+ self.pad= [0,0,0,0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.prop_header, ofp_queue_prop_header)):
+ return (False, "self.prop_header is not class ofp_queue_prop_header as expected.")
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 6):
+ return (False, "self.pad is not of size 6 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += self.prop_header.pack()
+ packed += struct.pack("!H", self.rate)
+ packed += struct.pack("!BBBBBB", self.pad[0], self.pad[1], self.pad[2], self.pad[3], self.pad[4], self.pad[5])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 16):
+ return binaryString
+ self.prop_header.unpack(binaryString[0:])
+ fmt = '!H'
+ start = 8
+ end = start + struct.calcsize(fmt)
+ (self.rate,) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBBBBB'
+ start = 10
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2], self.pad[3], self.pad[4], self.pad[5]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[16:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 16
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.prop_header != other.prop_header: return False
+ if self.rate != other.rate: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'prop_header: \n'
+ outstr += self.prop_header.show(prefix + ' ')
+ outstr += prefix + 'rate: ' + str(self.rate) + '\n'
+ return outstr
+
+
+class ofp_experimenter_stats_header(object):
+ """Automatically generated Python class for ofp_experimenter_stats_header
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.experimenter = 0
+ self.exp_type = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!LL", self.experimenter, self.exp_type)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!LL'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.experimenter, self.exp_type) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.experimenter != other.experimenter: return False
+ if self.exp_type != other.exp_type: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'experimenter: ' + str(self.experimenter) + '\n'
+ outstr += prefix + 'exp_type: ' + str(self.exp_type) + '\n'
+ return outstr
+
+
+class ofp_action_group(object):
+ """Automatically generated Python class for ofp_action_group
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.type = 0
+ self.len = 0
+ self.group_id = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HHL", self.type, self.len, self.group_id)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!HHL'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.type, self.len, self.group_id) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.type != other.type: return False
+ if self.len != other.len: return False
+ if self.group_id != other.group_id: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'len: ' + str(self.len) + '\n'
+ outstr += prefix + 'group_id: ' + str(self.group_id) + '\n'
+ return outstr
+
+
+class ofp_desc_stats(object):
+ """Automatically generated Python class for ofp_desc_stats
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.mfr_desc= ""
+ self.hw_desc= ""
+ self.sw_desc= ""
+ self.serial_num= ""
+ self.dp_desc= ""
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.mfr_desc, str)):
+ return (False, "self.mfr_desc is not string as expected.")
+ if(len(self.mfr_desc) > 256):
+ return (False, "self.mfr_desc is not of size 256 as expected.")
+ if(not isinstance(self.hw_desc, str)):
+ return (False, "self.hw_desc is not string as expected.")
+ if(len(self.hw_desc) > 256):
+ return (False, "self.hw_desc is not of size 256 as expected.")
+ if(not isinstance(self.sw_desc, str)):
+ return (False, "self.sw_desc is not string as expected.")
+ if(len(self.sw_desc) > 256):
+ return (False, "self.sw_desc is not of size 256 as expected.")
+ if(not isinstance(self.serial_num, str)):
+ return (False, "self.serial_num is not string as expected.")
+ if(len(self.serial_num) > 32):
+ return (False, "self.serial_num is not of size 32 as expected.")
+ if(not isinstance(self.dp_desc, str)):
+ return (False, "self.dp_desc is not string as expected.")
+ if(len(self.dp_desc) > 256):
+ return (False, "self.dp_desc is not of size 256 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += self.mfr_desc.ljust(256,'\0')
+ packed += self.hw_desc.ljust(256,'\0')
+ packed += self.sw_desc.ljust(256,'\0')
+ packed += self.serial_num.ljust(32,'\0')
+ packed += self.dp_desc.ljust(256,'\0')
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 1056):
+ return binaryString
+ self.mfr_desc = binaryString[0:256].replace("\0","")
+ self.hw_desc = binaryString[256:512].replace("\0","")
+ self.sw_desc = binaryString[512:768].replace("\0","")
+ self.serial_num = binaryString[768:800].replace("\0","")
+ self.dp_desc = binaryString[800:1056].replace("\0","")
+ return binaryString[1056:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 1056
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.mfr_desc != other.mfr_desc: return False
+ if self.hw_desc != other.hw_desc: return False
+ if self.sw_desc != other.sw_desc: return False
+ if self.serial_num != other.serial_num: return False
+ if self.dp_desc != other.dp_desc: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'mfr_desc: ' + str(self.mfr_desc) + '\n'
+ outstr += prefix + 'hw_desc: ' + str(self.hw_desc) + '\n'
+ outstr += prefix + 'sw_desc: ' + str(self.sw_desc) + '\n'
+ outstr += prefix + 'serial_num: ' + str(self.serial_num) + '\n'
+ outstr += prefix + 'dp_desc: ' + str(self.dp_desc) + '\n'
+ return outstr
+
+
+class ofp_action_push(object):
+ """Automatically generated Python class for ofp_action_push
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.type = 0
+ self.len = 0
+ self.ethertype = 0
+ self.pad= [0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 2):
+ return (False, "self.pad is not of size 2 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HHH", self.type, self.len, self.ethertype)
+ packed += struct.pack("!BB", self.pad[0], self.pad[1])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!HHH'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.type, self.len, self.ethertype) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BB'
+ start = 6
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.type != other.type: return False
+ if self.len != other.len: return False
+ if self.ethertype != other.ethertype: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'len: ' + str(self.len) + '\n'
+ outstr += prefix + 'ethertype: ' + str(self.ethertype) + '\n'
+ return outstr
+
+
+class ofp_group_desc_stats(object):
+ """Automatically generated Python class for ofp_group_desc_stats
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.length = 0
+ self.type = 0
+ self.pad = 0
+ self.group_id = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HBBL", self.length, self.type, self.pad, self.group_id)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!HBBL'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.length, self.type, self.pad, self.group_id) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.length != other.length: return False
+ if self.type != other.type: return False
+ if self.pad != other.pad: return False
+ if self.group_id != other.group_id: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'length: ' + str(self.length) + '\n'
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'group_id: ' + str(self.group_id) + '\n'
+ return outstr
+
+
+class ofp_error_msg(object):
+ """Automatically generated Python class for ofp_error_msg
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.type = 0
+ self.code = 0
+
+ def __assert(self):
+ """Sanity check
+ """
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HH", self.type, self.code)
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 4):
+ return binaryString
+ fmt = '!HH'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.type, self.code) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[4:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 4
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.type != other.type: return False
+ if self.code != other.code: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'code: ' + str(self.code) + '\n'
+ return outstr
+
+
+class ofp_action_mpls_ttl(object):
+ """Automatically generated Python class for ofp_action_mpls_ttl
+
+ Date 2012-06-25
+ Created by of.pythonize.pythonizer
+ Core structure: Messages do not include ofp_header
+ Does not include var-length arrays
+ """
+ def __init__(self):
+ """Initialize
+ Declare members and default values
+ """
+ self.type = 0
+ self.len = 0
+ self.mpls_ttl = 0
+ self.pad= [0,0,0]
+
+ def __assert(self):
+ """Sanity check
+ """
+ if(not isinstance(self.pad, list)):
+ return (False, "self.pad is not list as expected.")
+ if(len(self.pad) != 3):
+ return (False, "self.pad is not of size 3 as expected.")
+ return (True, None)
+
+ def pack(self, assertstruct=True):
+ """Pack message
+ Packs empty array used as placeholder
+ """
+ if(assertstruct):
+ if(not self.__assert()[0]):
+ return None
+ packed = ""
+ packed += struct.pack("!HHB", self.type, self.len, self.mpls_ttl)
+ packed += struct.pack("!BBB", self.pad[0], self.pad[1], self.pad[2])
+ return packed
+
+ def unpack(self, binaryString):
+ """Unpack message
+ Do not unpack empty array used as placeholder
+ since they can contain heterogeneous type
+ """
+ if (len(binaryString) < 8):
+ return binaryString
+ fmt = '!HHB'
+ start = 0
+ end = start + struct.calcsize(fmt)
+ (self.type, self.len, self.mpls_ttl) = struct.unpack(fmt, binaryString[start:end])
+ fmt = '!BBB'
+ start = 5
+ end = start + struct.calcsize(fmt)
+ (self.pad[0], self.pad[1], self.pad[2]) = struct.unpack(fmt, binaryString[start:end])
+ return binaryString[8:]
+
+ def __len__(self):
+ """Return length of message
+ """
+ l = 8
+ return l
+
+ def __eq__(self, other):
+ """Return True if self and other have same values
+ """
+ if type(self) != type(other): return False
+ if self.type != other.type: return False
+ if self.len != other.len: return False
+ if self.mpls_ttl != other.mpls_ttl: return False
+ if self.pad != other.pad: return False
+ return True
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+ def show(self, prefix=''):
+ """Generate string showing basic members of structure
+ """
+ outstr = ''
+ outstr += prefix + 'type: ' + str(self.type) + '\n'
+ outstr += prefix + 'len: ' + str(self.len) + '\n'
+ outstr += prefix + 'mpls_ttl: ' + str(self.mpls_ttl) + '\n'
+ return outstr
+
+
+# Enumerated type definitions
+ofp_error_type = ['OFPET_HELLO_FAILED', 'OFPET_BAD_REQUEST', 'OFPET_BAD_ACTION', 'OFPET_BAD_INSTRUCTION', 'OFPET_BAD_MATCH', 'OFPET_FLOW_MOD_FAILED', 'OFPET_GROUP_MOD_FAILED', 'OFPET_PORT_MOD_FAILED', 'OFPET_TABLE_MOD_FAILED', 'OFPET_QUEUE_OP_FAILED', 'OFPET_SWITCH_CONFIG_FAILED', 'OFPET_ROLE_REQUEST_FAILED', 'OFPET_EXPERIMENTER']
+OFPET_HELLO_FAILED = 0
+OFPET_BAD_REQUEST = 1
+OFPET_BAD_ACTION = 2
+OFPET_BAD_INSTRUCTION = 3
+OFPET_BAD_MATCH = 4
+OFPET_FLOW_MOD_FAILED = 5
+OFPET_GROUP_MOD_FAILED = 6
+OFPET_PORT_MOD_FAILED = 7
+OFPET_TABLE_MOD_FAILED = 8
+OFPET_QUEUE_OP_FAILED = 9
+OFPET_SWITCH_CONFIG_FAILED = 10
+OFPET_ROLE_REQUEST_FAILED = 11
+OFPET_EXPERIMENTER = 65535
+ofp_error_type_map = {
+ 0 : 'OFPET_HELLO_FAILED',
+ 1 : 'OFPET_BAD_REQUEST',
+ 2 : 'OFPET_BAD_ACTION',
+ 3 : 'OFPET_BAD_INSTRUCTION',
+ 4 : 'OFPET_BAD_MATCH',
+ 5 : 'OFPET_FLOW_MOD_FAILED',
+ 6 : 'OFPET_GROUP_MOD_FAILED',
+ 7 : 'OFPET_PORT_MOD_FAILED',
+ 8 : 'OFPET_TABLE_MOD_FAILED',
+ 9 : 'OFPET_QUEUE_OP_FAILED',
+ 10 : 'OFPET_SWITCH_CONFIG_FAILED',
+ 11 : 'OFPET_ROLE_REQUEST_FAILED',
+ 65535 : 'OFPET_EXPERIMENTER'
+}
+
+ofp_flow_mod_flags = ['OFPFF_SEND_FLOW_REM', 'OFPFF_CHECK_OVERLAP', 'OFPFF_RESET_COUNTS']
+OFPFF_SEND_FLOW_REM = 1
+OFPFF_CHECK_OVERLAP = 2
+OFPFF_RESET_COUNTS = 4
+ofp_flow_mod_flags_map = {
+ 1 : 'OFPFF_SEND_FLOW_REM',
+ 2 : 'OFPFF_CHECK_OVERLAP',
+ 4 : 'OFPFF_RESET_COUNTS'
+}
+
+ofp_controller_role = ['OFPCR_ROLE_NOCHANGE', 'OFPCR_ROLE_EQUAL', 'OFPCR_ROLE_MASTER', 'OFPCR_ROLE_SLAVE']
+OFPCR_ROLE_NOCHANGE = 0
+OFPCR_ROLE_EQUAL = 1
+OFPCR_ROLE_MASTER = 2
+OFPCR_ROLE_SLAVE = 3
+ofp_controller_role_map = {
+ 0 : 'OFPCR_ROLE_NOCHANGE',
+ 1 : 'OFPCR_ROLE_EQUAL',
+ 2 : 'OFPCR_ROLE_MASTER',
+ 3 : 'OFPCR_ROLE_SLAVE'
+}
+
+ofp_stats_reply_flags = ['OFPSF_REPLY_MORE']
+OFPSF_REPLY_MORE = 1
+ofp_stats_reply_flags_map = {
+ 1 : 'OFPSF_REPLY_MORE'
+}
+
+ofp_port_no = ['OFPP_MAX', 'OFPP_IN_PORT', 'OFPP_TABLE', 'OFPP_NORMAL', 'OFPP_FLOOD', 'OFPP_ALL', 'OFPP_CONTROLLER', 'OFPP_LOCAL', 'OFPP_ANY']
+OFPP_MAX = 4294967040
+OFPP_IN_PORT = 4294967288
+OFPP_TABLE = 4294967289
+OFPP_NORMAL = 4294967290
+OFPP_FLOOD = 4294967291
+OFPP_ALL = 4294967292
+OFPP_CONTROLLER = 4294967293
+OFPP_LOCAL = 4294967294
+OFPP_ANY = 4294967295
+ofp_port_no_map = {
+ 4294967040 : 'OFPP_MAX',
+ 4294967288 : 'OFPP_IN_PORT',
+ 4294967289 : 'OFPP_TABLE',
+ 4294967290 : 'OFPP_NORMAL',
+ 4294967291 : 'OFPP_FLOOD',
+ 4294967292 : 'OFPP_ALL',
+ 4294967293 : 'OFPP_CONTROLLER',
+ 4294967294 : 'OFPP_LOCAL',
+ 4294967295 : 'OFPP_ANY'
+}
+
+ofp_bad_request_code = ['OFPBRC_BAD_VERSION', 'OFPBRC_BAD_TYPE', 'OFPBRC_BAD_STAT', 'OFPBRC_BAD_EXPERIMENTER', 'OFPBRC_BAD_EXP_TYPE', 'OFPBRC_EPERM', 'OFPBRC_BAD_LEN', 'OFPBRC_BUFFER_EMPTY', 'OFPBRC_BUFFER_UNKNOWN', 'OFPBRC_BAD_TABLE_ID', 'OFPBRC_IS_SLAVE', 'OFPBRC_BAD_PORT', 'OFPBRC_BAD_PACKET']
+OFPBRC_BAD_VERSION = 0
+OFPBRC_BAD_TYPE = 1
+OFPBRC_BAD_STAT = 2
+OFPBRC_BAD_EXPERIMENTER = 3
+OFPBRC_BAD_EXP_TYPE = 4
+OFPBRC_EPERM = 5
+OFPBRC_BAD_LEN = 6
+OFPBRC_BUFFER_EMPTY = 7
+OFPBRC_BUFFER_UNKNOWN = 8
+OFPBRC_BAD_TABLE_ID = 9
+OFPBRC_IS_SLAVE = 10
+OFPBRC_BAD_PORT = 11
+OFPBRC_BAD_PACKET = 12
+ofp_bad_request_code_map = {
+ 0 : 'OFPBRC_BAD_VERSION',
+ 1 : 'OFPBRC_BAD_TYPE',
+ 2 : 'OFPBRC_BAD_STAT',
+ 3 : 'OFPBRC_BAD_EXPERIMENTER',
+ 4 : 'OFPBRC_BAD_EXP_TYPE',
+ 5 : 'OFPBRC_EPERM',
+ 6 : 'OFPBRC_BAD_LEN',
+ 7 : 'OFPBRC_BUFFER_EMPTY',
+ 8 : 'OFPBRC_BUFFER_UNKNOWN',
+ 9 : 'OFPBRC_BAD_TABLE_ID',
+ 10 : 'OFPBRC_IS_SLAVE',
+ 11 : 'OFPBRC_BAD_PORT',
+ 12 : 'OFPBRC_BAD_PACKET'
+}
+
+ofp_bad_instruction_code = ['OFPBIC_UNKNOWN_INST', 'OFPBIC_UNSUP_INST', 'OFPBIC_BAD_TABLE_ID', 'OFPBIC_UNSUP_METADATA', 'OFPBIC_UNSUP_METADATA_MASK', 'OFPBIC_BAD_EXPERIMENTER', 'OFPBIC_BAD_EXP_TYPE', 'OFPBIC_BAD_LEN', 'OFPBIC_EPERM']
+OFPBIC_UNKNOWN_INST = 0
+OFPBIC_UNSUP_INST = 1
+OFPBIC_BAD_TABLE_ID = 2
+OFPBIC_UNSUP_METADATA = 3
+OFPBIC_UNSUP_METADATA_MASK = 4
+OFPBIC_BAD_EXPERIMENTER = 5
+OFPBIC_BAD_EXP_TYPE = 6
+OFPBIC_BAD_LEN = 7
+OFPBIC_EPERM = 8
+ofp_bad_instruction_code_map = {
+ 0 : 'OFPBIC_UNKNOWN_INST',
+ 1 : 'OFPBIC_UNSUP_INST',
+ 2 : 'OFPBIC_BAD_TABLE_ID',
+ 3 : 'OFPBIC_UNSUP_METADATA',
+ 4 : 'OFPBIC_UNSUP_METADATA_MASK',
+ 5 : 'OFPBIC_BAD_EXPERIMENTER',
+ 6 : 'OFPBIC_BAD_EXP_TYPE',
+ 7 : 'OFPBIC_BAD_LEN',
+ 8 : 'OFPBIC_EPERM'
+}
+
+ofp_port_config = ['OFPPC_PORT_DOWN', 'OFPPC_NO_RECV', 'OFPPC_NO_FWD', 'OFPPC_NO_PACKET_IN']
+OFPPC_PORT_DOWN = 1
+OFPPC_NO_RECV = 4
+OFPPC_NO_FWD = 32
+OFPPC_NO_PACKET_IN = 64
+ofp_port_config_map = {
+ 1 : 'OFPPC_PORT_DOWN',
+ 4 : 'OFPPC_NO_RECV',
+ 32 : 'OFPPC_NO_FWD',
+ 64 : 'OFPPC_NO_PACKET_IN'
+}
+
+ofp_port_state = ['OFPPS_LINK_DOWN', 'OFPPS_BLOCKED', 'OFPPS_LIVE']
+OFPPS_LINK_DOWN = 1
+OFPPS_BLOCKED = 2
+OFPPS_LIVE = 4
+ofp_port_state_map = {
+ 1 : 'OFPPS_LINK_DOWN',
+ 2 : 'OFPPS_BLOCKED',
+ 4 : 'OFPPS_LIVE'
+}
+
+ofp_config_flags = ['OFPC_FRAG_NORMAL', 'OFPC_FRAG_DROP', 'OFPC_FRAG_REASM', 'OFPC_FRAG_MASK', 'OFPC_INVALID_TTL_TO_CONTROLLER']
+OFPC_FRAG_NORMAL = 0
+OFPC_FRAG_DROP = 1
+OFPC_FRAG_REASM = 2
+OFPC_FRAG_MASK = 3
+OFPC_INVALID_TTL_TO_CONTROLLER = 4
+ofp_config_flags_map = {
+ 0 : 'OFPC_FRAG_NORMAL',
+ 1 : 'OFPC_FRAG_DROP',
+ 2 : 'OFPC_FRAG_REASM',
+ 3 : 'OFPC_FRAG_MASK',
+ 4 : 'OFPC_INVALID_TTL_TO_CONTROLLER'
+}
+
+ofp_switch_config_failed_code = ['OFPSCFC_BAD_FLAGS', 'OFPSCFC_BAD_LEN', 'OFPQCFC_EPERM']
+OFPSCFC_BAD_FLAGS = 0
+OFPSCFC_BAD_LEN = 1
+OFPQCFC_EPERM = 2
+ofp_switch_config_failed_code_map = {
+ 0 : 'OFPSCFC_BAD_FLAGS',
+ 1 : 'OFPSCFC_BAD_LEN',
+ 2 : 'OFPQCFC_EPERM'
+}
+
+ofp_controller_max_len = ['OFPCML_MAX', 'OFPCML_NO_BUFFER']
+OFPCML_MAX = 65509
+OFPCML_NO_BUFFER = 65535
+ofp_controller_max_len_map = {
+ 65509 : 'OFPCML_MAX',
+ 65535 : 'OFPCML_NO_BUFFER'
+}
+
+ofp_role_request_failed_code = ['OFPRRFC_STALE', 'OFPRRFC_UNSUP', 'OFPRRFC_BAD_ROLE']
+OFPRRFC_STALE = 0
+OFPRRFC_UNSUP = 1
+OFPRRFC_BAD_ROLE = 2
+ofp_role_request_failed_code_map = {
+ 0 : 'OFPRRFC_STALE',
+ 1 : 'OFPRRFC_UNSUP',
+ 2 : 'OFPRRFC_BAD_ROLE'
+}
+
+ofp_capabilities = ['OFPC_FLOW_STATS', 'OFPC_TABLE_STATS', 'OFPC_PORT_STATS', 'OFPC_GROUP_STATS', 'OFPC_IP_REASM', 'OFPC_QUEUE_STATS', 'OFPC_PORT_BLOCKED']
+OFPC_FLOW_STATS = 1
+OFPC_TABLE_STATS = 2
+OFPC_PORT_STATS = 4
+OFPC_GROUP_STATS = 8
+OFPC_IP_REASM = 32
+OFPC_QUEUE_STATS = 64
+OFPC_PORT_BLOCKED = 256
+ofp_capabilities_map = {
+ 1 : 'OFPC_FLOW_STATS',
+ 2 : 'OFPC_TABLE_STATS',
+ 4 : 'OFPC_PORT_STATS',
+ 8 : 'OFPC_GROUP_STATS',
+ 32 : 'OFPC_IP_REASM',
+ 64 : 'OFPC_QUEUE_STATS',
+ 256 : 'OFPC_PORT_BLOCKED'
+}
+
+ofp_bad_match_code = ['OFPBMC_BAD_TYPE', 'OFPBMC_BAD_LEN', 'OFPBMC_BAD_TAG', 'OFPBMC_BAD_DL_ADDR_MASK', 'OFPBMC_BAD_NW_ADDR_MASK', 'OFPBMC_BAD_WILDCARDS', 'OFPBMC_BAD_FIELD', 'OFPBMC_BAD_VALUE', 'OFPBMC_BAD_MASK', 'OFPBMC_BAD_PREREQ', 'OFPBMC_DUP_FIELD', 'OFPBMC_EPERM']
+OFPBMC_BAD_TYPE = 0
+OFPBMC_BAD_LEN = 1
+OFPBMC_BAD_TAG = 2
+OFPBMC_BAD_DL_ADDR_MASK = 3
+OFPBMC_BAD_NW_ADDR_MASK = 4
+OFPBMC_BAD_WILDCARDS = 5
+OFPBMC_BAD_FIELD = 6
+OFPBMC_BAD_VALUE = 7
+OFPBMC_BAD_MASK = 8
+OFPBMC_BAD_PREREQ = 9
+OFPBMC_DUP_FIELD = 10
+OFPBMC_EPERM = 11
+ofp_bad_match_code_map = {
+ 0 : 'OFPBMC_BAD_TYPE',
+ 1 : 'OFPBMC_BAD_LEN',
+ 2 : 'OFPBMC_BAD_TAG',
+ 3 : 'OFPBMC_BAD_DL_ADDR_MASK',
+ 4 : 'OFPBMC_BAD_NW_ADDR_MASK',
+ 5 : 'OFPBMC_BAD_WILDCARDS',
+ 6 : 'OFPBMC_BAD_FIELD',
+ 7 : 'OFPBMC_BAD_VALUE',
+ 8 : 'OFPBMC_BAD_MASK',
+ 9 : 'OFPBMC_BAD_PREREQ',
+ 10 : 'OFPBMC_DUP_FIELD',
+ 11 : 'OFPBMC_EPERM'
+}
+
+ofp_flow_removed_reason = ['OFPRR_IDLE_TIMEOUT', 'OFPRR_HARD_TIMEOUT', 'OFPRR_DELETE', 'OFPRR_GROUP_DELETE']
+OFPRR_IDLE_TIMEOUT = 0
+OFPRR_HARD_TIMEOUT = 1
+OFPRR_DELETE = 2
+OFPRR_GROUP_DELETE = 3
+ofp_flow_removed_reason_map = {
+ 0 : 'OFPRR_IDLE_TIMEOUT',
+ 1 : 'OFPRR_HARD_TIMEOUT',
+ 2 : 'OFPRR_DELETE',
+ 3 : 'OFPRR_GROUP_DELETE'
+}
+
+ofp_table_mod_failed_code = ['OFPTMFC_BAD_TABLE', 'OFPTMFC_BAD_CONFIG', 'OFPTMFC_EPERM']
+OFPTMFC_BAD_TABLE = 0
+OFPTMFC_BAD_CONFIG = 1
+OFPTMFC_EPERM = 2
+ofp_table_mod_failed_code_map = {
+ 0 : 'OFPTMFC_BAD_TABLE',
+ 1 : 'OFPTMFC_BAD_CONFIG',
+ 2 : 'OFPTMFC_EPERM'
+}
+
+ofp_queue_properties = ['OFPQT_MIN_RATE', 'OFPQT_MAX_RATE', 'OFPQT_EXPERIMENTER']
+OFPQT_MIN_RATE = 1
+OFPQT_MAX_RATE = 2
+OFPQT_EXPERIMENTER = 65535
+ofp_queue_properties_map = {
+ 1 : 'OFPQT_MIN_RATE',
+ 2 : 'OFPQT_MAX_RATE',
+ 65535 : 'OFPQT_EXPERIMENTER'
+}
+
+ofp_table = ['OFPTT_MAX', 'OFPTT_ALL']
+OFPTT_MAX = 254
+OFPTT_ALL = 255
+ofp_table_map = {
+ 254 : 'OFPTT_MAX',
+ 255 : 'OFPTT_ALL'
+}
+
+ofp_group = ['OFPG_MAX', 'OFPG_ALL', 'OFPG_ANY']
+OFPG_MAX = 4294967040
+OFPG_ALL = 4294967292
+OFPG_ANY = 4294967295
+ofp_group_map = {
+ 4294967040 : 'OFPG_MAX',
+ 4294967292 : 'OFPG_ALL',
+ 4294967295 : 'OFPG_ANY'
+}
+
+ofp_port_reason = ['OFPPR_ADD', 'OFPPR_DELETE', 'OFPPR_MODIFY']
+OFPPR_ADD = 0
+OFPPR_DELETE = 1
+OFPPR_MODIFY = 2
+ofp_port_reason_map = {
+ 0 : 'OFPPR_ADD',
+ 1 : 'OFPPR_DELETE',
+ 2 : 'OFPPR_MODIFY'
+}
+
+ofp_group_capabilities = ['OFPGFC_SELECT_WEIGHT', 'OFPGFC_SELECT_LIVENESS', 'OFPGFC_CHAINING', 'OFPGFC_CHAINING_CHECKS']
+OFPGFC_SELECT_WEIGHT = 1
+OFPGFC_SELECT_LIVENESS = 2
+OFPGFC_CHAINING = 4
+OFPGFC_CHAINING_CHECKS = 8
+ofp_group_capabilities_map = {
+ 1 : 'OFPGFC_SELECT_WEIGHT',
+ 2 : 'OFPGFC_SELECT_LIVENESS',
+ 4 : 'OFPGFC_CHAINING',
+ 8 : 'OFPGFC_CHAINING_CHECKS'
+}
+
+ofp_table_config = ['OFPTC_TABLE_MISS_CONTROLLER', 'OFPTC_TABLE_MISS_CONTINUE', 'OFPTC_TABLE_MISS_DROP', 'OFPTC_TABLE_MISS_MASK']
+OFPTC_TABLE_MISS_CONTROLLER = 0
+OFPTC_TABLE_MISS_CONTINUE = 1
+OFPTC_TABLE_MISS_DROP = 2
+OFPTC_TABLE_MISS_MASK = 3
+ofp_table_config_map = {
+ 0 : 'OFPTC_TABLE_MISS_CONTROLLER',
+ 1 : 'OFPTC_TABLE_MISS_CONTINUE',
+ 2 : 'OFPTC_TABLE_MISS_DROP',
+ 3 : 'OFPTC_TABLE_MISS_MASK'
+}
+
+ofp_action_type = ['OFPAT_OUTPUT', 'OFPAT_COPY_TTL_OUT', 'OFPAT_COPY_TTL_IN', 'OFPAT_SET_MPLS_TTL', 'OFPAT_DEC_MPLS_TTL', 'OFPAT_PUSH_VLAN', 'OFPAT_POP_VLAN', 'OFPAT_PUSH_MPLS', 'OFPAT_POP_MPLS', 'OFPAT_SET_QUEUE', 'OFPAT_GROUP', 'OFPAT_SET_NW_TTL', 'OFPAT_DEC_NW_TTL', 'OFPAT_SET_FIELD', 'OFPAT_EXPERIMENTER']
+OFPAT_OUTPUT = 0
+OFPAT_COPY_TTL_OUT = 11
+OFPAT_COPY_TTL_IN = 12
+OFPAT_SET_MPLS_TTL = 15
+OFPAT_DEC_MPLS_TTL = 16
+OFPAT_PUSH_VLAN = 17
+OFPAT_POP_VLAN = 18
+OFPAT_PUSH_MPLS = 19
+OFPAT_POP_MPLS = 20
+OFPAT_SET_QUEUE = 21
+OFPAT_GROUP = 22
+OFPAT_SET_NW_TTL = 23
+OFPAT_DEC_NW_TTL = 24
+OFPAT_SET_FIELD = 25
+OFPAT_EXPERIMENTER = 65535
+ofp_action_type_map = {
+ 0 : 'OFPAT_OUTPUT',
+ 11 : 'OFPAT_COPY_TTL_OUT',
+ 12 : 'OFPAT_COPY_TTL_IN',
+ 15 : 'OFPAT_SET_MPLS_TTL',
+ 16 : 'OFPAT_DEC_MPLS_TTL',
+ 17 : 'OFPAT_PUSH_VLAN',
+ 18 : 'OFPAT_POP_VLAN',
+ 19 : 'OFPAT_PUSH_MPLS',
+ 20 : 'OFPAT_POP_MPLS',
+ 21 : 'OFPAT_SET_QUEUE',
+ 22 : 'OFPAT_GROUP',
+ 23 : 'OFPAT_SET_NW_TTL',
+ 24 : 'OFPAT_DEC_NW_TTL',
+ 25 : 'OFPAT_SET_FIELD',
+ 65535 : 'OFPAT_EXPERIMENTER'
+}
+
+ofp_flow_mod_command = ['OFPFC_ADD', 'OFPFC_MODIFY', 'OFPFC_MODIFY_STRICT', 'OFPFC_DELETE', 'OFPFC_DELETE_STRICT']
+OFPFC_ADD = 0
+OFPFC_MODIFY = 1
+OFPFC_MODIFY_STRICT = 2
+OFPFC_DELETE = 3
+OFPFC_DELETE_STRICT = 4
+ofp_flow_mod_command_map = {
+ 0 : 'OFPFC_ADD',
+ 1 : 'OFPFC_MODIFY',
+ 2 : 'OFPFC_MODIFY_STRICT',
+ 3 : 'OFPFC_DELETE',
+ 4 : 'OFPFC_DELETE_STRICT'
+}
+
+ofp_queue_op_failed_code = ['OFPQOFC_BAD_PORT', 'OFPQOFC_BAD_QUEUE', 'OFPQOFC_EPERM']
+OFPQOFC_BAD_PORT = 0
+OFPQOFC_BAD_QUEUE = 1
+OFPQOFC_EPERM = 2
+ofp_queue_op_failed_code_map = {
+ 0 : 'OFPQOFC_BAD_PORT',
+ 1 : 'OFPQOFC_BAD_QUEUE',
+ 2 : 'OFPQOFC_EPERM'
+}
+
+ofp_hello_failed_code = ['OFPHFC_INCOMPATIBLE', 'OFPHFC_EPERM']
+OFPHFC_INCOMPATIBLE = 0
+OFPHFC_EPERM = 1
+ofp_hello_failed_code_map = {
+ 0 : 'OFPHFC_INCOMPATIBLE',
+ 1 : 'OFPHFC_EPERM'
+}
+
+ofp_match_type = ['OFPMT_STANDARD', 'OFPMT_OXM']
+OFPMT_STANDARD = 0
+OFPMT_OXM = 1
+ofp_match_type_map = {
+ 0 : 'OFPMT_STANDARD',
+ 1 : 'OFPMT_OXM'
+}
+
+ofp_vlan_id = ['OFPVID_PRESENT', 'OFPVID_NONE']
+OFPVID_PRESENT = 4096
+OFPVID_NONE = 0
+ofp_vlan_id_map = {
+ 4096 : 'OFPVID_PRESENT',
+ 0 : 'OFPVID_NONE'
+}
+
+ofp_oxm_class = ['OFPXMC_NXM_0', 'OFPXMC_NXM_1', 'OFPXMC_OPENFLOW_BASIC', 'OFPXMC_EXPERIMENTER']
+OFPXMC_NXM_0 = 0
+OFPXMC_NXM_1 = 1
+OFPXMC_OPENFLOW_BASIC = 32768
+OFPXMC_EXPERIMENTER = 65535
+ofp_oxm_class_map = {
+ 0 : 'OFPXMC_NXM_0',
+ 1 : 'OFPXMC_NXM_1',
+ 32768 : 'OFPXMC_OPENFLOW_BASIC',
+ 65535 : 'OFPXMC_EXPERIMENTER'
+}
+
+ofp_group_type = ['OFPGT_ALL', 'OFPGT_SELECT', 'OFPGT_INDIRECT', 'OFPGT_FF']
+OFPGT_ALL = 0
+OFPGT_SELECT = 1
+OFPGT_INDIRECT = 2
+OFPGT_FF = 3
+ofp_group_type_map = {
+ 0 : 'OFPGT_ALL',
+ 1 : 'OFPGT_SELECT',
+ 2 : 'OFPGT_INDIRECT',
+ 3 : 'OFPGT_FF'
+}
+
+ofp_instruction_type = ['OFPIT_GOTO_TABLE', 'OFPIT_WRITE_METADATA', 'OFPIT_WRITE_ACTIONS', 'OFPIT_APPLY_ACTIONS', 'OFPIT_CLEAR_ACTIONS', 'OFPIT_EXPERIMENTER']
+OFPIT_GOTO_TABLE = 1
+OFPIT_WRITE_METADATA = 2
+OFPIT_WRITE_ACTIONS = 3
+OFPIT_APPLY_ACTIONS = 4
+OFPIT_CLEAR_ACTIONS = 5
+OFPIT_EXPERIMENTER = 65535
+ofp_instruction_type_map = {
+ 1 : 'OFPIT_GOTO_TABLE',
+ 2 : 'OFPIT_WRITE_METADATA',
+ 3 : 'OFPIT_WRITE_ACTIONS',
+ 4 : 'OFPIT_APPLY_ACTIONS',
+ 5 : 'OFPIT_CLEAR_ACTIONS',
+ 65535 : 'OFPIT_EXPERIMENTER'
+}
+
+ofp_bad_action_code = ['OFPBAC_BAD_TYPE', 'OFPBAC_BAD_LEN', 'OFPBAC_BAD_EXPERIMENTER', 'OFPBAC_BAD_EXP_TYPE', 'OFPBAC_BAD_OUT_PORT', 'OFPBAC_BAD_ARGUMENT', 'OFPBAC_EPERM', 'OFPBAC_TOO_MANY', 'OFPBAC_BAD_QUEUE', 'OFPBAC_BAD_OUT_GROUP', 'OFPBAC_MATCH_INCONSISTENT', 'OFPBAC_UNSUPPORTED_ORDER', 'OFPBAC_BAD_TAG', 'OFPBAC_BAD_SET_TYPE', 'OFPBAC_BAD_SET_LEN', 'OFPBAC_BAD_SET_ARGUMENT']
+OFPBAC_BAD_TYPE = 0
+OFPBAC_BAD_LEN = 1
+OFPBAC_BAD_EXPERIMENTER = 2
+OFPBAC_BAD_EXP_TYPE = 3
+OFPBAC_BAD_OUT_PORT = 4
+OFPBAC_BAD_ARGUMENT = 5
+OFPBAC_EPERM = 6
+OFPBAC_TOO_MANY = 7
+OFPBAC_BAD_QUEUE = 8
+OFPBAC_BAD_OUT_GROUP = 9
+OFPBAC_MATCH_INCONSISTENT = 10
+OFPBAC_UNSUPPORTED_ORDER = 11
+OFPBAC_BAD_TAG = 12
+OFPBAC_BAD_SET_TYPE = 13
+OFPBAC_BAD_SET_LEN = 14
+OFPBAC_BAD_SET_ARGUMENT = 15
+ofp_bad_action_code_map = {
+ 0 : 'OFPBAC_BAD_TYPE',
+ 1 : 'OFPBAC_BAD_LEN',
+ 2 : 'OFPBAC_BAD_EXPERIMENTER',
+ 3 : 'OFPBAC_BAD_EXP_TYPE',
+ 4 : 'OFPBAC_BAD_OUT_PORT',
+ 5 : 'OFPBAC_BAD_ARGUMENT',
+ 6 : 'OFPBAC_EPERM',
+ 7 : 'OFPBAC_TOO_MANY',
+ 8 : 'OFPBAC_BAD_QUEUE',
+ 9 : 'OFPBAC_BAD_OUT_GROUP',
+ 10 : 'OFPBAC_MATCH_INCONSISTENT',
+ 11 : 'OFPBAC_UNSUPPORTED_ORDER',
+ 12 : 'OFPBAC_BAD_TAG',
+ 13 : 'OFPBAC_BAD_SET_TYPE',
+ 14 : 'OFPBAC_BAD_SET_LEN',
+ 15 : 'OFPBAC_BAD_SET_ARGUMENT'
+}
+
+oxm_ofb_match_fields = ['OFPXMT_OFB_IN_PORT', 'OFPXMT_OFB_IN_PHY_PORT', 'OFPXMT_OFB_METADATA', 'OFPXMT_OFB_ETH_DST', 'OFPXMT_OFB_ETH_SRC', 'OFPXMT_OFB_ETH_TYPE', 'OFPXMT_OFB_VLAN_VID', 'OFPXMT_OFB_VLAN_PCP', 'OFPXMT_OFB_IP_DSCP', 'OFPXMT_OFB_IP_ECN', 'OFPXMT_OFB_IP_PROTO', 'OFPXMT_OFB_IPV4_SRC', 'OFPXMT_OFB_IPV4_DST', 'OFPXMT_OFB_TCP_SRC', 'OFPXMT_OFB_TCP_DST', 'OFPXMT_OFB_UDP_SRC', 'OFPXMT_OFB_UDP_DST', 'OFPXMT_OFB_SCTP_SRC', 'OFPXMT_OFB_SCTP_DST', 'OFPXMT_OFB_ICMPV4_TYPE', 'OFPXMT_OFB_ICMPV4_CODE', 'OFPXMT_OFB_ARP_OP', 'OFPXMT_OFB_ARP_SPA', 'OFPXMT_OFB_ARP_TPA', 'OFPXMT_OFB_ARP_SHA', 'OFPXMT_OFB_ARP_THA', 'OFPXMT_OFB_IPV6_SRC', 'OFPXMT_OFB_IPV6_DST', 'OFPXMT_OFB_IPV6_FLABEL', 'OFPXMT_OFB_ICMPV6_TYPE', 'OFPXMT_OFB_ICMPV6_CODE', 'OFPXMT_OFB_IPV6_ND_TARGET', 'OFPXMT_OFB_IPV6_ND_SLL', 'OFPXMT_OFB_IPV6_ND_TLL', 'OFPXMT_OFB_MPLS_LABEL', 'OFPXMT_OFB_MPLS_TC']
+OFPXMT_OFB_IN_PORT = 0
+OFPXMT_OFB_IN_PHY_PORT = 1
+OFPXMT_OFB_METADATA = 2
+OFPXMT_OFB_ETH_DST = 3
+OFPXMT_OFB_ETH_SRC = 4
+OFPXMT_OFB_ETH_TYPE = 5
+OFPXMT_OFB_VLAN_VID = 6
+OFPXMT_OFB_VLAN_PCP = 7
+OFPXMT_OFB_IP_DSCP = 8
+OFPXMT_OFB_IP_ECN = 9
+OFPXMT_OFB_IP_PROTO = 10
+OFPXMT_OFB_IPV4_SRC = 11
+OFPXMT_OFB_IPV4_DST = 12
+OFPXMT_OFB_TCP_SRC = 13
+OFPXMT_OFB_TCP_DST = 14
+OFPXMT_OFB_UDP_SRC = 15
+OFPXMT_OFB_UDP_DST = 16
+OFPXMT_OFB_SCTP_SRC = 17
+OFPXMT_OFB_SCTP_DST = 18
+OFPXMT_OFB_ICMPV4_TYPE = 19
+OFPXMT_OFB_ICMPV4_CODE = 20
+OFPXMT_OFB_ARP_OP = 21
+OFPXMT_OFB_ARP_SPA = 22
+OFPXMT_OFB_ARP_TPA = 23
+OFPXMT_OFB_ARP_SHA = 24
+OFPXMT_OFB_ARP_THA = 25
+OFPXMT_OFB_IPV6_SRC = 26
+OFPXMT_OFB_IPV6_DST = 27
+OFPXMT_OFB_IPV6_FLABEL = 28
+OFPXMT_OFB_ICMPV6_TYPE = 29
+OFPXMT_OFB_ICMPV6_CODE = 30
+OFPXMT_OFB_IPV6_ND_TARGET = 31
+OFPXMT_OFB_IPV6_ND_SLL = 32
+OFPXMT_OFB_IPV6_ND_TLL = 33
+OFPXMT_OFB_MPLS_LABEL = 34
+OFPXMT_OFB_MPLS_TC = 35
+oxm_ofb_match_fields_map = {
+ 0 : 'OFPXMT_OFB_IN_PORT',
+ 1 : 'OFPXMT_OFB_IN_PHY_PORT',
+ 2 : 'OFPXMT_OFB_METADATA',
+ 3 : 'OFPXMT_OFB_ETH_DST',
+ 4 : 'OFPXMT_OFB_ETH_SRC',
+ 5 : 'OFPXMT_OFB_ETH_TYPE',
+ 6 : 'OFPXMT_OFB_VLAN_VID',
+ 7 : 'OFPXMT_OFB_VLAN_PCP',
+ 8 : 'OFPXMT_OFB_IP_DSCP',
+ 9 : 'OFPXMT_OFB_IP_ECN',
+ 10 : 'OFPXMT_OFB_IP_PROTO',
+ 11 : 'OFPXMT_OFB_IPV4_SRC',
+ 12 : 'OFPXMT_OFB_IPV4_DST',
+ 13 : 'OFPXMT_OFB_TCP_SRC',
+ 14 : 'OFPXMT_OFB_TCP_DST',
+ 15 : 'OFPXMT_OFB_UDP_SRC',
+ 16 : 'OFPXMT_OFB_UDP_DST',
+ 17 : 'OFPXMT_OFB_SCTP_SRC',
+ 18 : 'OFPXMT_OFB_SCTP_DST',
+ 19 : 'OFPXMT_OFB_ICMPV4_TYPE',
+ 20 : 'OFPXMT_OFB_ICMPV4_CODE',
+ 21 : 'OFPXMT_OFB_ARP_OP',
+ 22 : 'OFPXMT_OFB_ARP_SPA',
+ 23 : 'OFPXMT_OFB_ARP_TPA',
+ 24 : 'OFPXMT_OFB_ARP_SHA',
+ 25 : 'OFPXMT_OFB_ARP_THA',
+ 26 : 'OFPXMT_OFB_IPV6_SRC',
+ 27 : 'OFPXMT_OFB_IPV6_DST',
+ 28 : 'OFPXMT_OFB_IPV6_FLABEL',
+ 29 : 'OFPXMT_OFB_ICMPV6_TYPE',
+ 30 : 'OFPXMT_OFB_ICMPV6_CODE',
+ 31 : 'OFPXMT_OFB_IPV6_ND_TARGET',
+ 32 : 'OFPXMT_OFB_IPV6_ND_SLL',
+ 33 : 'OFPXMT_OFB_IPV6_ND_TLL',
+ 34 : 'OFPXMT_OFB_MPLS_LABEL',
+ 35 : 'OFPXMT_OFB_MPLS_TC'
+}
+
+ofp_flow_mod_failed_code = ['OFPFMFC_UNKNOWN', 'OFPFMFC_TABLE_FULL', 'OFPFMFC_BAD_TABLE_ID', 'OFPFMFC_OVERLAP', 'OFPFMFC_EPERM', 'OFPFMFC_BAD_TIMEOUT', 'OFPFMFC_BAD_COMMAND', 'OFPFMFC_BAD_FLAGS']
+OFPFMFC_UNKNOWN = 0
+OFPFMFC_TABLE_FULL = 1
+OFPFMFC_BAD_TABLE_ID = 2
+OFPFMFC_OVERLAP = 3
+OFPFMFC_EPERM = 4
+OFPFMFC_BAD_TIMEOUT = 5
+OFPFMFC_BAD_COMMAND = 6
+OFPFMFC_BAD_FLAGS = 7
+ofp_flow_mod_failed_code_map = {
+ 0 : 'OFPFMFC_UNKNOWN',
+ 1 : 'OFPFMFC_TABLE_FULL',
+ 2 : 'OFPFMFC_BAD_TABLE_ID',
+ 3 : 'OFPFMFC_OVERLAP',
+ 4 : 'OFPFMFC_EPERM',
+ 5 : 'OFPFMFC_BAD_TIMEOUT',
+ 6 : 'OFPFMFC_BAD_COMMAND',
+ 7 : 'OFPFMFC_BAD_FLAGS'
+}
+
+ofp_port_mod_failed_code = ['OFPPMFC_BAD_PORT', 'OFPPMFC_BAD_HW_ADDR', 'OFPPMFC_BAD_CONFIG', 'OFPPMFC_BAD_ADVERTISE', 'OFPPMFC_EPERM']
+OFPPMFC_BAD_PORT = 0
+OFPPMFC_BAD_HW_ADDR = 1
+OFPPMFC_BAD_CONFIG = 2
+OFPPMFC_BAD_ADVERTISE = 3
+OFPPMFC_EPERM = 4
+ofp_port_mod_failed_code_map = {
+ 0 : 'OFPPMFC_BAD_PORT',
+ 1 : 'OFPPMFC_BAD_HW_ADDR',
+ 2 : 'OFPPMFC_BAD_CONFIG',
+ 3 : 'OFPPMFC_BAD_ADVERTISE',
+ 4 : 'OFPPMFC_EPERM'
+}
+
+ofp_type = ['OFPT_HELLO', 'OFPT_ERROR', 'OFPT_ECHO_REQUEST', 'OFPT_ECHO_REPLY', 'OFPT_EXPERIMENTER', 'OFPT_FEATURES_REQUEST', 'OFPT_FEATURES_REPLY', 'OFPT_GET_CONFIG_REQUEST', 'OFPT_GET_CONFIG_REPLY', 'OFPT_SET_CONFIG', 'OFPT_PACKET_IN', 'OFPT_FLOW_REMOVED', 'OFPT_PORT_STATUS', 'OFPT_PACKET_OUT', 'OFPT_FLOW_MOD', 'OFPT_GROUP_MOD', 'OFPT_PORT_MOD', 'OFPT_TABLE_MOD', 'OFPT_STATS_REQUEST', 'OFPT_STATS_REPLY', 'OFPT_BARRIER_REQUEST', 'OFPT_BARRIER_REPLY', 'OFPT_QUEUE_GET_CONFIG_REQUEST', 'OFPT_QUEUE_GET_CONFIG_REPLY', 'OFPT_ROLE_REQUEST', 'OFPT_ROLE_REPLY']
+OFPT_HELLO = 0
+OFPT_ERROR = 1
+OFPT_ECHO_REQUEST = 2
+OFPT_ECHO_REPLY = 3
+OFPT_EXPERIMENTER = 4
+OFPT_FEATURES_REQUEST = 5
+OFPT_FEATURES_REPLY = 6
+OFPT_GET_CONFIG_REQUEST = 7
+OFPT_GET_CONFIG_REPLY = 8
+OFPT_SET_CONFIG = 9
+OFPT_PACKET_IN = 10
+OFPT_FLOW_REMOVED = 11
+OFPT_PORT_STATUS = 12
+OFPT_PACKET_OUT = 13
+OFPT_FLOW_MOD = 14
+OFPT_GROUP_MOD = 15
+OFPT_PORT_MOD = 16
+OFPT_TABLE_MOD = 17
+OFPT_STATS_REQUEST = 18
+OFPT_STATS_REPLY = 19
+OFPT_BARRIER_REQUEST = 20
+OFPT_BARRIER_REPLY = 21
+OFPT_QUEUE_GET_CONFIG_REQUEST = 22
+OFPT_QUEUE_GET_CONFIG_REPLY = 23
+OFPT_ROLE_REQUEST = 24
+OFPT_ROLE_REPLY = 25
+ofp_type_map = {
+ 0 : 'OFPT_HELLO',
+ 1 : 'OFPT_ERROR',
+ 2 : 'OFPT_ECHO_REQUEST',
+ 3 : 'OFPT_ECHO_REPLY',
+ 4 : 'OFPT_EXPERIMENTER',
+ 5 : 'OFPT_FEATURES_REQUEST',
+ 6 : 'OFPT_FEATURES_REPLY',
+ 7 : 'OFPT_GET_CONFIG_REQUEST',
+ 8 : 'OFPT_GET_CONFIG_REPLY',
+ 9 : 'OFPT_SET_CONFIG',
+ 10 : 'OFPT_PACKET_IN',
+ 11 : 'OFPT_FLOW_REMOVED',
+ 12 : 'OFPT_PORT_STATUS',
+ 13 : 'OFPT_PACKET_OUT',
+ 14 : 'OFPT_FLOW_MOD',
+ 15 : 'OFPT_GROUP_MOD',
+ 16 : 'OFPT_PORT_MOD',
+ 17 : 'OFPT_TABLE_MOD',
+ 18 : 'OFPT_STATS_REQUEST',
+ 19 : 'OFPT_STATS_REPLY',
+ 20 : 'OFPT_BARRIER_REQUEST',
+ 21 : 'OFPT_BARRIER_REPLY',
+ 22 : 'OFPT_QUEUE_GET_CONFIG_REQUEST',
+ 23 : 'OFPT_QUEUE_GET_CONFIG_REPLY',
+ 24 : 'OFPT_ROLE_REQUEST',
+ 25 : 'OFPT_ROLE_REPLY'
+}
+
+ofp_packet_in_reason = ['OFPR_NO_MATCH', 'OFPR_ACTION', 'OFPR_INVALID_TTL']
+OFPR_NO_MATCH = 0
+OFPR_ACTION = 1
+OFPR_INVALID_TTL = 2
+ofp_packet_in_reason_map = {
+ 0 : 'OFPR_NO_MATCH',
+ 1 : 'OFPR_ACTION',
+ 2 : 'OFPR_INVALID_TTL'
+}
+
+ofp_stats_types = ['OFPST_DESC', 'OFPST_FLOW', 'OFPST_AGGREGATE', 'OFPST_TABLE', 'OFPST_PORT', 'OFPST_QUEUE', 'OFPST_GROUP', 'OFPST_GROUP_DESC', 'OFPST_GROUP_FEATURES', 'OFPST_EXPERIMENTER']
+OFPST_DESC = 0
+OFPST_FLOW = 1
+OFPST_AGGREGATE = 2
+OFPST_TABLE = 3
+OFPST_PORT = 4
+OFPST_QUEUE = 5
+OFPST_GROUP = 6
+OFPST_GROUP_DESC = 7
+OFPST_GROUP_FEATURES = 8
+OFPST_EXPERIMENTER = 65535
+ofp_stats_types_map = {
+ 0 : 'OFPST_DESC',
+ 1 : 'OFPST_FLOW',
+ 2 : 'OFPST_AGGREGATE',
+ 3 : 'OFPST_TABLE',
+ 4 : 'OFPST_PORT',
+ 5 : 'OFPST_QUEUE',
+ 6 : 'OFPST_GROUP',
+ 7 : 'OFPST_GROUP_DESC',
+ 8 : 'OFPST_GROUP_FEATURES',
+ 65535 : 'OFPST_EXPERIMENTER'
+}
+
+ofp_group_mod_command = ['OFPGC_ADD', 'OFPGC_MODIFY', 'OFPGC_DELETE']
+OFPGC_ADD = 0
+OFPGC_MODIFY = 1
+OFPGC_DELETE = 2
+ofp_group_mod_command_map = {
+ 0 : 'OFPGC_ADD',
+ 1 : 'OFPGC_MODIFY',
+ 2 : 'OFPGC_DELETE'
+}
+
+ofp_port_features = ['OFPPF_10MB_HD', 'OFPPF_10MB_FD', 'OFPPF_100MB_HD', 'OFPPF_100MB_FD', 'OFPPF_1GB_HD', 'OFPPF_1GB_FD', 'OFPPF_10GB_FD', 'OFPPF_40GB_FD', 'OFPPF_100GB_FD', 'OFPPF_1TB_FD', 'OFPPF_OTHER', 'OFPPF_COPPER', 'OFPPF_FIBER', 'OFPPF_AUTONEG', 'OFPPF_PAUSE', 'OFPPF_PAUSE_ASYM']
+OFPPF_10MB_HD = 1
+OFPPF_10MB_FD = 2
+OFPPF_100MB_HD = 4
+OFPPF_100MB_FD = 8
+OFPPF_1GB_HD = 16
+OFPPF_1GB_FD = 32
+OFPPF_10GB_FD = 64
+OFPPF_40GB_FD = 128
+OFPPF_100GB_FD = 256
+OFPPF_1TB_FD = 512
+OFPPF_OTHER = 1024
+OFPPF_COPPER = 2048
+OFPPF_FIBER = 4096
+OFPPF_AUTONEG = 8192
+OFPPF_PAUSE = 16384
+OFPPF_PAUSE_ASYM = 32768
+ofp_port_features_map = {
+ 1 : 'OFPPF_10MB_HD',
+ 2 : 'OFPPF_10MB_FD',
+ 4 : 'OFPPF_100MB_HD',
+ 8 : 'OFPPF_100MB_FD',
+ 16 : 'OFPPF_1GB_HD',
+ 32 : 'OFPPF_1GB_FD',
+ 64 : 'OFPPF_10GB_FD',
+ 128 : 'OFPPF_40GB_FD',
+ 256 : 'OFPPF_100GB_FD',
+ 512 : 'OFPPF_1TB_FD',
+ 1024 : 'OFPPF_OTHER',
+ 2048 : 'OFPPF_COPPER',
+ 4096 : 'OFPPF_FIBER',
+ 8192 : 'OFPPF_AUTONEG',
+ 16384 : 'OFPPF_PAUSE',
+ 32768 : 'OFPPF_PAUSE_ASYM'
+}
+
+ofp_group_mod_failed_code = ['OFPGMFC_GROUP_EXISTS', 'OFPGMFC_INVALID_GROUP', 'OFPGMFC_OUT_OF_GROUPS', 'OFPGMFC_OUT_OF_BUCKETS', 'OFPGMFC_CHAINING_UNSUPPORTED', 'OFPGMFC_WATCH_UNSUPPORTED', 'OFPGMFC_LOOP', 'OFPGMFC_UNKNOWN_GROUP', 'OFPGMFC_CHAINED_GROUP', 'OFPGMFC_BAD_TYPE', 'OFPGMFC_BAD_COMMAND', 'OFPGMFC_BAD_BUCKET', 'OFPGMFC_BAD_WATCH', 'OFPGMFC_EPERM']
+OFPGMFC_GROUP_EXISTS = 0
+OFPGMFC_INVALID_GROUP = 1
+OFPGMFC_OUT_OF_GROUPS = 3
+OFPGMFC_OUT_OF_BUCKETS = 4
+OFPGMFC_CHAINING_UNSUPPORTED = 5
+OFPGMFC_WATCH_UNSUPPORTED = 6
+OFPGMFC_LOOP = 7
+OFPGMFC_UNKNOWN_GROUP = 8
+OFPGMFC_CHAINED_GROUP = 9
+OFPGMFC_BAD_TYPE = 10
+OFPGMFC_BAD_COMMAND = 11
+OFPGMFC_BAD_BUCKET = 12
+OFPGMFC_BAD_WATCH = 13
+OFPGMFC_EPERM = 14
+ofp_group_mod_failed_code_map = {
+ 0 : 'OFPGMFC_GROUP_EXISTS',
+ 1 : 'OFPGMFC_INVALID_GROUP',
+ 3 : 'OFPGMFC_OUT_OF_GROUPS',
+ 4 : 'OFPGMFC_OUT_OF_BUCKETS',
+ 5 : 'OFPGMFC_CHAINING_UNSUPPORTED',
+ 6 : 'OFPGMFC_WATCH_UNSUPPORTED',
+ 7 : 'OFPGMFC_LOOP',
+ 8 : 'OFPGMFC_UNKNOWN_GROUP',
+ 9 : 'OFPGMFC_CHAINED_GROUP',
+ 10 : 'OFPGMFC_BAD_TYPE',
+ 11 : 'OFPGMFC_BAD_COMMAND',
+ 12 : 'OFPGMFC_BAD_BUCKET',
+ 13 : 'OFPGMFC_BAD_WATCH',
+ 14 : 'OFPGMFC_EPERM'
+}
+
+# Values from macro definitions
+OFP_ETH_ALEN = 6
+OFP_MAX_PORT_NAME_LEN = 16
+OFP_TCP_PORT = 6633
+OFP_FLOW_PERMANENT = 0
+OFPQ_MIN_RATE_UNCFG = 0xffff
+OFPQ_ALL = 0xffffffff
+OFP_VERSION = 0x03
+OFP_MAX_TABLE_NAME_LEN = 32
+OFP_DEFAULT_PRIORITY = 0x8000
+OFP_NO_BUFFER = 0xffffffff
+OFP_SSL_PORT = 6633
+OFP_DEFAULT_MISS_SEND_LEN = 128
+DESC_STR_LEN = 256
+SERIAL_NUM_LEN = 32
+
+# Basic structure size definitions.
+# Does not include ofp_header members.
+# Does not include variable length arrays.
+OFP_ACTION_EXPERIMENTER_HEADER_BYTES = 8
+OFP_ACTION_GROUP_BYTES = 8
+OFP_ACTION_HEADER_BYTES = 8
+OFP_ACTION_MPLS_TTL_BYTES = 8
+OFP_ACTION_NW_TTL_BYTES = 8
+OFP_ACTION_OUTPUT_BYTES = 16
+OFP_ACTION_POP_MPLS_BYTES = 8
+OFP_ACTION_PUSH_BYTES = 8
+OFP_ACTION_SET_FIELD_BYTES = 8
+OFP_ACTION_SET_QUEUE_BYTES = 8
+OFP_AGGREGATE_STATS_REPLY_BYTES = 24
+OFP_AGGREGATE_STATS_REQUEST_BYTES = 36
+OFP_BUCKET_BYTES = 16
+OFP_BUCKET_COUNTER_BYTES = 16
+OFP_DESC_STATS_BYTES = 1056
+OFP_ERROR_EXPERIMENTER_MSG_BYTES = 8
+OFP_ERROR_MSG_BYTES = 4
+OFP_EXPERIMENTER_HEADER_BYTES = 8
+OFP_EXPERIMENTER_STATS_HEADER_BYTES = 8
+OFP_FLOW_MOD_BYTES = 44
+OFP_FLOW_REMOVED_BYTES = 44
+OFP_FLOW_STATS_BYTES = 52
+OFP_FLOW_STATS_REQUEST_BYTES = 36
+OFP_GROUP_DESC_STATS_BYTES = 8
+OFP_GROUP_FEATURES_STATS_BYTES = 40
+OFP_GROUP_MOD_BYTES = 8
+OFP_GROUP_STATS_BYTES = 32
+OFP_GROUP_STATS_REQUEST_BYTES = 8
+OFP_HEADER_BYTES = 8
+OFP_HELLO_BYTES = 0
+OFP_INSTRUCTION_BYTES = 8
+OFP_INSTRUCTION_ACTIONS_BYTES = 8
+OFP_INSTRUCTION_GOTO_TABLE_BYTES = 8
+OFP_INSTRUCTION_WRITE_METADATA_BYTES = 24
+OFP_MATCH_BYTES = 4
+OFP_OXM_EXPERIMENTER_HEADER_BYTES = 8
+OFP_PACKET_IN_BYTES = 12
+OFP_PACKET_OUT_BYTES = 16
+OFP_PACKET_QUEUE_BYTES = 16
+OFP_PORT_BYTES = 64
+OFP_PORT_MOD_BYTES = 32
+OFP_PORT_STATS_BYTES = 104
+OFP_PORT_STATS_REQUEST_BYTES = 8
+OFP_PORT_STATUS_BYTES = 72
+OFP_QUEUE_GET_CONFIG_REPLY_BYTES = 8
+OFP_QUEUE_GET_CONFIG_REQUEST_BYTES = 8
+OFP_QUEUE_PROP_EXPERIMENTER_BYTES = 16
+OFP_QUEUE_PROP_HEADER_BYTES = 8
+OFP_QUEUE_PROP_MAX_RATE_BYTES = 16
+OFP_QUEUE_PROP_MIN_RATE_BYTES = 16
+OFP_QUEUE_STATS_BYTES = 32
+OFP_QUEUE_STATS_REQUEST_BYTES = 8
+OFP_ROLE_REQUEST_BYTES = 16
+OFP_STATS_REPLY_BYTES = 8
+OFP_STATS_REQUEST_BYTES = 8
+OFP_SWITCH_CONFIG_BYTES = 4
+OFP_SWITCH_FEATURES_BYTES = 24
+OFP_TABLE_MOD_BYTES = 8
+OFP_TABLE_STATS_BYTES = 128
+
diff --git a/src/python/of12/error.py b/src/python/of12/error.py
new file mode 100644
index 0000000..0a1244a
--- /dev/null
+++ b/src/python/of12/error.py
@@ -0,0 +1,556 @@
+
+# Python OpenFlow error wrapper classes
+
+from cstruct import *
+
+
+
+class hello_failed_error_msg(ofp_error_msg):
+ """
+ Wrapper class for hello_failed error message class
+
+ 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.type = OFPET_HELLO_FAILED
+ self.data = ""
+
+ def pack(self, assertstruct=True):
+ self.header.length = self.__len__()
+ packed = self.header.pack()
+ packed += ofp_error_msg.pack(self)
+ packed += self.data
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_error_msg.unpack(self, binary_string)
+ self.data = binary_string
+ return ""
+
+ def __len__(self):
+ return OFP_HEADER_BYTES + OFP_ERROR_MSG_BYTES + len(self.data)
+
+ def show(self, prefix=''):
+ outstr = prefix + "hello_failed_error_msg\m"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_error_msg.show(self, prefix + ' ')
+ outstr += prefix + "data is of length " + str(len(self.data)) + '\n'
+ ##@todo Consider trying to parse the string
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_error_msg.__eq__(self, other) and
+ self.data == other.data)
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class bad_request_error_msg(ofp_error_msg):
+ """
+ Wrapper class for bad_request error message class
+
+ 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.type = OFPET_BAD_REQUEST
+ self.data = ""
+
+ def pack(self, assertstruct=True):
+ self.header.length = self.__len__()
+ packed = self.header.pack()
+ packed += ofp_error_msg.pack(self)
+ packed += self.data
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_error_msg.unpack(self, binary_string)
+ self.data = binary_string
+ return ""
+
+ def __len__(self):
+ return OFP_HEADER_BYTES + OFP_ERROR_MSG_BYTES + len(self.data)
+
+ def show(self, prefix=''):
+ outstr = prefix + "bad_request_error_msg\m"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_error_msg.show(self, prefix + ' ')
+ outstr += prefix + "data is of length " + str(len(self.data)) + '\n'
+ ##@todo Consider trying to parse the string
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_error_msg.__eq__(self, other) and
+ self.data == other.data)
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class bad_action_error_msg(ofp_error_msg):
+ """
+ Wrapper class for bad_action error message class
+
+ 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.type = OFPET_BAD_ACTION
+ self.data = ""
+
+ def pack(self, assertstruct=True):
+ self.header.length = self.__len__()
+ packed = self.header.pack()
+ packed += ofp_error_msg.pack(self)
+ packed += self.data
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_error_msg.unpack(self, binary_string)
+ self.data = binary_string
+ return ""
+
+ def __len__(self):
+ return OFP_HEADER_BYTES + OFP_ERROR_MSG_BYTES + len(self.data)
+
+ def show(self, prefix=''):
+ outstr = prefix + "bad_action_error_msg\m"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_error_msg.show(self, prefix + ' ')
+ outstr += prefix + "data is of length " + str(len(self.data)) + '\n'
+ ##@todo Consider trying to parse the string
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_error_msg.__eq__(self, other) and
+ self.data == other.data)
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class bad_instruction_error_msg(ofp_error_msg):
+ """
+ Wrapper class for bad_instruction error message class
+
+ 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.type = OFPET_BAD_INSTRUCTION
+ self.data = ""
+
+ def pack(self, assertstruct=True):
+ self.header.length = self.__len__()
+ packed = self.header.pack()
+ packed += ofp_error_msg.pack(self)
+ packed += self.data
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_error_msg.unpack(self, binary_string)
+ self.data = binary_string
+ return ""
+
+ def __len__(self):
+ return OFP_HEADER_BYTES + OFP_ERROR_MSG_BYTES + len(self.data)
+
+ def show(self, prefix=''):
+ outstr = prefix + "bad_instruction_error_msg\m"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_error_msg.show(self, prefix + ' ')
+ outstr += prefix + "data is of length " + str(len(self.data)) + '\n'
+ ##@todo Consider trying to parse the string
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_error_msg.__eq__(self, other) and
+ self.data == other.data)
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class bad_match_error_msg(ofp_error_msg):
+ """
+ Wrapper class for bad_match error message class
+
+ 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.type = OFPET_BAD_MATCH
+ self.data = ""
+
+ def pack(self, assertstruct=True):
+ self.header.length = self.__len__()
+ packed = self.header.pack()
+ packed += ofp_error_msg.pack(self)
+ packed += self.data
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_error_msg.unpack(self, binary_string)
+ self.data = binary_string
+ return ""
+
+ def __len__(self):
+ return OFP_HEADER_BYTES + OFP_ERROR_MSG_BYTES + len(self.data)
+
+ def show(self, prefix=''):
+ outstr = prefix + "bad_match_error_msg\m"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_error_msg.show(self, prefix + ' ')
+ outstr += prefix + "data is of length " + str(len(self.data)) + '\n'
+ ##@todo Consider trying to parse the string
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_error_msg.__eq__(self, other) and
+ self.data == other.data)
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class flow_mod_failed_error_msg(ofp_error_msg):
+ """
+ Wrapper class for flow_mod_failed error message class
+
+ 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.type = OFPET_FLOW_MOD_FAILED
+ self.data = ""
+
+ def pack(self, assertstruct=True):
+ self.header.length = self.__len__()
+ packed = self.header.pack()
+ packed += ofp_error_msg.pack(self)
+ packed += self.data
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_error_msg.unpack(self, binary_string)
+ self.data = binary_string
+ return ""
+
+ def __len__(self):
+ return OFP_HEADER_BYTES + OFP_ERROR_MSG_BYTES + len(self.data)
+
+ def show(self, prefix=''):
+ outstr = prefix + "flow_mod_failed_error_msg\m"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_error_msg.show(self, prefix + ' ')
+ outstr += prefix + "data is of length " + str(len(self.data)) + '\n'
+ ##@todo Consider trying to parse the string
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_error_msg.__eq__(self, other) and
+ self.data == other.data)
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class group_mod_failed_error_msg(ofp_error_msg):
+ """
+ Wrapper class for group_mod_failed error message class
+
+ 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.type = OFPET_GROUP_MOD_FAILED
+ self.data = ""
+
+ def pack(self, assertstruct=True):
+ self.header.length = self.__len__()
+ packed = self.header.pack()
+ packed += ofp_error_msg.pack(self)
+ packed += self.data
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_error_msg.unpack(self, binary_string)
+ self.data = binary_string
+ return ""
+
+ def __len__(self):
+ return OFP_HEADER_BYTES + OFP_ERROR_MSG_BYTES + len(self.data)
+
+ def show(self, prefix=''):
+ outstr = prefix + "group_mod_failed_error_msg\m"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_error_msg.show(self, prefix + ' ')
+ outstr += prefix + "data is of length " + str(len(self.data)) + '\n'
+ ##@todo Consider trying to parse the string
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_error_msg.__eq__(self, other) and
+ self.data == other.data)
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class port_mod_failed_error_msg(ofp_error_msg):
+ """
+ Wrapper class for port_mod_failed error message class
+
+ 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.type = OFPET_PORT_MOD_FAILED
+ self.data = ""
+
+ def pack(self, assertstruct=True):
+ self.header.length = self.__len__()
+ packed = self.header.pack()
+ packed += ofp_error_msg.pack(self)
+ packed += self.data
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_error_msg.unpack(self, binary_string)
+ self.data = binary_string
+ return ""
+
+ def __len__(self):
+ return OFP_HEADER_BYTES + OFP_ERROR_MSG_BYTES + len(self.data)
+
+ def show(self, prefix=''):
+ outstr = prefix + "port_mod_failed_error_msg\m"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_error_msg.show(self, prefix + ' ')
+ outstr += prefix + "data is of length " + str(len(self.data)) + '\n'
+ ##@todo Consider trying to parse the string
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_error_msg.__eq__(self, other) and
+ self.data == other.data)
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class table_mod_failed_error_msg(ofp_error_msg):
+ """
+ Wrapper class for table_mod_failed error message class
+
+ 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.type = OFPET_TABLE_MOD_FAILED
+ self.data = ""
+
+ def pack(self, assertstruct=True):
+ self.header.length = self.__len__()
+ packed = self.header.pack()
+ packed += ofp_error_msg.pack(self)
+ packed += self.data
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_error_msg.unpack(self, binary_string)
+ self.data = binary_string
+ return ""
+
+ def __len__(self):
+ return OFP_HEADER_BYTES + OFP_ERROR_MSG_BYTES + len(self.data)
+
+ def show(self, prefix=''):
+ outstr = prefix + "table_mod_failed_error_msg\m"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_error_msg.show(self, prefix + ' ')
+ outstr += prefix + "data is of length " + str(len(self.data)) + '\n'
+ ##@todo Consider trying to parse the string
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_error_msg.__eq__(self, other) and
+ self.data == other.data)
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class queue_op_failed_error_msg(ofp_error_msg):
+ """
+ Wrapper class for queue_op_failed error message class
+
+ 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.type = OFPET_QUEUE_OP_FAILED
+ self.data = ""
+
+ def pack(self, assertstruct=True):
+ self.header.length = self.__len__()
+ packed = self.header.pack()
+ packed += ofp_error_msg.pack(self)
+ packed += self.data
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_error_msg.unpack(self, binary_string)
+ self.data = binary_string
+ return ""
+
+ def __len__(self):
+ return OFP_HEADER_BYTES + OFP_ERROR_MSG_BYTES + len(self.data)
+
+ def show(self, prefix=''):
+ outstr = prefix + "queue_op_failed_error_msg\m"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_error_msg.show(self, prefix + ' ')
+ outstr += prefix + "data is of length " + str(len(self.data)) + '\n'
+ ##@todo Consider trying to parse the string
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_error_msg.__eq__(self, other) and
+ self.data == other.data)
+
+ def __ne__(self, other): return not self.__eq__(other)
+
+
+class switch_config_failed_error_msg(ofp_error_msg):
+ """
+ Wrapper class for switch_config_failed error message class
+
+ 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.type = OFPET_SWITCH_CONFIG_FAILED
+ self.data = ""
+
+ def pack(self, assertstruct=True):
+ self.header.length = self.__len__()
+ packed = self.header.pack()
+ packed += ofp_error_msg.pack(self)
+ packed += self.data
+ return packed
+
+ def unpack(self, binary_string):
+ binary_string = self.header.unpack(binary_string)
+ binary_string = ofp_error_msg.unpack(self, binary_string)
+ self.data = binary_string
+ return ""
+
+ def __len__(self):
+ return OFP_HEADER_BYTES + OFP_ERROR_MSG_BYTES + len(self.data)
+
+ def show(self, prefix=''):
+ outstr = prefix + "switch_config_failed_error_msg\m"
+ outstr += self.header.show(prefix + ' ')
+ outstr += ofp_error_msg.show(self, prefix + ' ')
+ outstr += prefix + "data is of length " + str(len(self.data)) + '\n'
+ ##@todo Consider trying to parse the string
+ return outstr
+
+ def __eq__(self, other):
+ if type(self) != type(other): return False
+ return (self.header == other.header and
+ ofp_error_msg.__eq__(self, other) and
+ self.data == other.data)
+
+ def __ne__(self, other): return not self.__eq__(other)
+
diff --git a/src/python/of12/instruction.py b/src/python/of12/instruction.py
new file mode 100644
index 0000000..a945525
--- /dev/null
+++ b/src/python/of12/instruction.py
@@ -0,0 +1,143 @@
+
+# Python OpenFlow instruction wrapper classes
+
+from cstruct import *
+from action_list import action_list
+
+
+
+class instruction_write_metadata(ofp_instruction_write_metadata):
+ """
+ Wrapper class for write_metadata instruction object
+
+ Data members inherited from ofp_instruction_write_metadata:
+ @arg type
+ @arg len
+ @arg metadata
+ @arg metadata_mask
+
+ """
+ def __init__(self):
+ ofp_instruction_write_metadata.__init__(self)
+ self.type = OFPIT_WRITE_METADATA
+ self.len = self.__len__()
+ def show(self, prefix=''):
+ outstr = prefix + "instruction_write_metadata\n"
+ outstr += ofp_instruction_write_metadata.show(self, prefix)
+ return outstr
+
+
+class instruction_goto_table(ofp_instruction_goto_table):
+ """
+ Wrapper class for goto_table instruction object
+
+ Data members inherited from ofp_instruction_goto_table:
+ @arg type
+ @arg len
+ @arg table_id
+
+ """
+ def __init__(self):
+ ofp_instruction_goto_table.__init__(self)
+ self.type = OFPIT_GOTO_TABLE
+ self.len = self.__len__()
+ def show(self, prefix=''):
+ outstr = prefix + "instruction_goto_table\n"
+ outstr += ofp_instruction_goto_table.show(self, prefix)
+ return outstr
+
+
+class instruction_write_actions(ofp_instruction_actions):
+ """
+ Wrapper class for write_actions instruction object
+
+ Data members inherited from ofp_instruction_actions:
+ @arg type
+ @arg len
+
+ """
+ def __init__(self):
+ ofp_instruction_actions.__init__(self)
+ self.type = OFPIT_WRITE_ACTIONS
+ self.actions = action_list()
+ self.len = self.__len__()
+ def show(self, prefix=''):
+ outstr = prefix + "instruction_write_actions\n"
+ outstr += ofp_instruction_actions.show(self, prefix)
+ outstr += self.actions.show(prefix)
+ return outstr
+ def unpack(self, binary_string):
+ binary_string = ofp_instruction_actions.unpack(self, binary_string)
+ bytes = self.len - OFP_INSTRUCTION_ACTIONS_BYTES
+ self.actions = action_list()
+ binary_string = self.actions.unpack(binary_string, bytes=bytes)
+ return binary_string
+ def pack(self):
+ self.len = self.__len__()
+ packed = ""
+ packed += ofp_instruction_actions.pack(self)
+ packed += self.actions.pack()
+ return packed
+ def __len__(self):
+ return ofp_instruction_actions.__len__(self) + self.actions.__len__()
+
+
+class instruction_apply_actions(ofp_instruction_actions):
+ """
+ Wrapper class for apply_actions instruction object
+
+ Data members inherited from ofp_instruction_actions:
+ @arg type
+ @arg len
+
+ """
+ def __init__(self):
+ ofp_instruction_actions.__init__(self)
+ self.type = OFPIT_APPLY_ACTIONS
+ self.actions = action_list()
+ self.len = self.__len__()
+ def show(self, prefix=''):
+ outstr = prefix + "instruction_apply_actions\n"
+ outstr += ofp_instruction_actions.show(self, prefix)
+ outstr += self.actions.show(prefix)
+ return outstr
+ def unpack(self, binary_string):
+ binary_string = ofp_instruction_actions.unpack(self, binary_string)
+ bytes = self.len - OFP_INSTRUCTION_ACTIONS_BYTES
+ self.actions = action_list()
+ binary_string = self.actions.unpack(binary_string, bytes=bytes)
+ return binary_string
+ def pack(self):
+ self.len = self.__len__()
+ packed = ""
+ packed += ofp_instruction_actions.pack(self)
+ packed += self.actions.pack()
+ return packed
+ def __len__(self):
+ return ofp_instruction_actions.__len__(self) + self.actions.__len__()
+
+
+class instruction_clear_actions(ofp_instruction):
+ """
+ Wrapper class for clear_actions instruction object
+
+ Data members inherited from ofp_instruction:
+ @arg type
+ @arg len
+
+ """
+ def __init__(self):
+ ofp_instruction.__init__(self)
+ self.type = OFPIT_CLEAR_ACTIONS
+ self.len = self.__len__()
+ def show(self, prefix=''):
+ outstr = prefix + "instruction_clear_actions\n"
+ outstr += ofp_instruction.show(self, prefix)
+ return outstr
+
+instruction_class_list = (
+ instruction_apply_actions,
+ instruction_clear_actions,
+ instruction_goto_table,
+ instruction_write_actions,
+ instruction_write_metadata)
diff --git a/src/python/of12/instruction_list.py b/src/python/of12/instruction_list.py
new file mode 100644
index 0000000..7b03fbf
--- /dev/null
+++ b/src/python/of12/instruction_list.py
@@ -0,0 +1,96 @@
+"""
+OpenFlow instruction list class
+"""
+
+import action as action
+import instruction as instruction
+from action_list import action_list
+from base_list import ofp_base_list
+from cstruct import ofp_header
+import unittest
+
+# Instruction list
+
+instruction_object_map = {
+ action.OFPIT_GOTO_TABLE : instruction.instruction_goto_table,
+ action.OFPIT_WRITE_METADATA : instruction.instruction_write_metadata,
+ action.OFPIT_WRITE_ACTIONS : instruction.instruction_write_actions,
+ action.OFPIT_APPLY_ACTIONS : instruction.instruction_apply_actions,
+ action.OFPIT_CLEAR_ACTIONS : instruction.instruction_clear_actions,
+}
+
+class instruction_list(ofp_base_list):
+ """
+ Maintain a list of instructions
+
+ Data members:
+ @arg instructions An array of instructions such as write_actions
+
+ Methods:
+ @arg pack: Pack the structure into a string
+ @arg unpack: Unpack a string to objects, with proper typing
+ @arg add: Add an action to the list; you can directly access
+ the action member, but add will validate that the added object
+ is an action.
+
+ """
+
+ def __init__(self):
+ ofp_base_list.__init__(self)
+ self.instructions = self.items
+ self.name = "instruction"
+ self.class_list = instruction.instruction_class_list
+
+ def unpack(self, binary_string, bytes=None):
+ """
+ Unpack a list of instructions
+
+ Unpack instructions from a binary string, creating an array
+ of objects of the appropriate type
+
+ @param binary_string The string to be unpacked
+
+ @param bytes The total length of the instruction list in bytes.
+ Ignored if decode is True. If bytes is None and decode is false, the
+ list is assumed to extend through the entire string.
+
+ @return The remainder of binary_string that was not parsed
+
+ """
+ if bytes == None:
+ bytes = len(binary_string)
+ bytes_done = 0
+ count = 0
+ cur_string = binary_string
+ while bytes_done < bytes:
+ hdr = instruction.ofp_instruction()
+ hdr.unpack(cur_string)
+ if hdr.len < action.OFP_ACTION_HEADER_BYTES:
+ print "ERROR: Action too short"
+ break
+ if not hdr.type in instruction_object_map.keys():
+ print "WARNING: Skipping unknown action ", hdr.type, hdr.len
+ else:
+ self.instructions.append(instruction_object_map[hdr.type]())
+ self.instructions[count].unpack(cur_string)
+ count += 1
+ cur_string = cur_string[hdr.len:]
+ bytes_done += hdr.len
+ return cur_string
+
+class Instruction_List_Test(unittest.TestCase):
+ def runTest(self):
+ # instructions header is 8 bytes
+ l = instruction_list()
+ act = action.action_output()
+ act.port = 7
+ inst = instruction.instruction_apply_actions()
+ self.assertTrue(inst.actions.add(act))
+ self.assertTrue(l.add(inst))
+ pkt = l.pack()
+ # 24 == 8 (list header) + (apply header) 8 + (output action) 8
+ self.assertEqual(len(pkt),24)
+
+ l = instruction_list()
+ self.assertTrue(l.add(instruction.instruction_goto_table()))
+
diff --git a/src/python/of12/match.py b/src/python/of12/match.py
new file mode 100644
index 0000000..de285a2
--- /dev/null
+++ b/src/python/of12/match.py
@@ -0,0 +1,787 @@
+
+# Python OpenFlow instruction wrapper classes
+
+import ipaddr
+from cstruct import *
+
+
+class oxm_tlv:
+ def __init__(self, field, hasmask, length, value, mask=None, class_ = 0x8000):
+ self.class_ = class_
+ self.field = field
+ self.hasmask = hasmask
+ self.length = length
+ self.value = value
+ self.mask = mask
+
+ def pack(self, assertstruct=True):
+
+ packed = ""
+ packed += struct.pack("!I", ((self.class_ << 16) | (self.field << 9) | (self.hasmask << 8) | self.length))
+ if self.length == 1:
+ packed += struct.pack("B", self.value)
+ if self.hasmask:
+ packed += struct.pack("B", self.mask)
+ elif self.length == 2 or (self.length == 4 and self.hasmask == True):
+ packed += struct.pack("!H", self.value)
+ if self.hasmask:
+ packed += struct.pack("!H", self.mask)
+ elif self.length == 4 or (self.length == 8 and self.hasmask == True):
+ packed += struct.pack("!I", self.value)
+ if self.hasmask:
+ packed += struct.pack("!I", self.mask)
+ elif self.length == 6 or self.length == 12:
+ packed += struct.pack("!BBBBBB", self.value[0],self.value[1],self.value[2],self.value[3],self.value[4],self.value[5])
+ if self.hasmask:
+ packed += struct.pack("!BBBBBB", self.mask[0],self.mask[1],self.mask[2],self.mask[3],self.mask[4],self.mask[5])
+ elif self.length == 8 or (self.length == 16 and self.hasmask == True):
+ packed += struct.pack("!Q", self.value)
+ if self.hasmask:
+ packed += struct.pack("!Q", self.mask)
+ elif self.length == 16 or self.length == 32:
+ packed += self.value.packed
+ if self.hasmask:
+ packed += self.mask.packed
+ return packed
+
+ def __len__(self):
+ return self.length + 4
+
+ def show(self, prefix=''):
+ return "\n".join(
+# ("oxm_tlv_class=" + hex(self.class_),
+ ("oxm_tlv_class=" + str(self.class_),
+ "oxm_tlv_field=" + hex(self.field),
+ "oxm_tlv_hasmask=" + str(bool(self.hasmask)),
+ "oxm_tlv_length: " + hex(self.length),
+ "value: " + str(self.value),))
+
+
+def roundup (x,y):
+ return (((x) + ((y) - 1)) / (y) * (y))
+
+class in_port(oxm_tlv):
+ """
+ Wrapper class for in_port match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_IN_PORT , hasmask, 4, value)
+ def show(self, prefix=''):
+ outstr = prefix + "in_port\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+
+class in_phy_port(oxm_tlv):
+ """
+ Wrapper class for in_phy_port match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self,OFPXMT_OFB_IN_PHY_PORT, hasmask, 4, value)
+ def show(self, prefix=''):
+ outstr = prefix + "in_phy_port\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+
+class metadata(oxm_tlv):
+ """
+ Wrapper class for metadata match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, mask = None):
+ if mask == None:
+ oxm_tlv.__init__(self, OFPXMT_OFB_METADATA, False, 8, value)
+ else:
+ oxm_tlv.__init__(self, OFPXMT_OFB_METADATA, True, 16, value, mask)
+ def show(self, prefix=''):
+ outstr = prefix + "metadata\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class eth_dst(oxm_tlv):
+ """
+ Wrapper class for eth_dst match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, mask = None):
+ if mask == None:
+ oxm_tlv.__init__(self, OFPXMT_OFB_ETH_DST, False, 6, value)
+ else:
+ oxm_tlv.__init__(self, OFPXMT_OFB_ETH_DST, True, 12, value, mask)
+ def show(self, prefix=''):
+ outstr = prefix + "eth_dst\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class eth_src(oxm_tlv):
+ """
+ Wrapper class for eth_src match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ if not hasmask:
+ oxm_tlv.__init__(self, OFPXMT_OFB_ETH_SRC, hasmask, 6, value)
+ else:
+ oxm_tlv.__init__(self, OFPXMT_OFB_ETH_SRC, hasmask, 12, value, mask)
+ def show(self, prefix=''):
+ outstr = prefix + "eth_src\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class eth_type(oxm_tlv):
+ """
+ Wrapper class for eth_type match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_ETH_TYPE, hasmask, 2, value)
+ def show(self, prefix=''):
+ outstr = prefix + "eth_type\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class vlan_vid(oxm_tlv):
+ """
+ Wrapper class for vlan_vid match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_VLAN_VID, hasmask, 2, value)
+ def show(self, prefix=''):
+ outstr = prefix + "vlan_vid\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class vlan_pcp(oxm_tlv):
+ """
+ Wrapper class for vlan_pcp match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_VLAN_PCP, hasmask, 1, value)
+ def show(self, prefix=''):
+ outstr = prefix + "vlan_pcp\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class ip_dscp(oxm_tlv):
+ """
+ Wrapper class for ip_dscp match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_IP_DSCP, hasmask, 1, value)
+ def show(self, prefix=''):
+ outstr = prefix + "ip_dscp\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class ip_ecn(oxm_tlv):
+ """
+ Wrapper class for ip_dscp match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_IP_ECN, hasmask, 1, value)
+ def show(self, prefix=''):
+ outstr = prefix + "ip_ecn\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class ip_proto(oxm_tlv):
+ """
+ Wrapper class for ip_proto match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_IP_PROTO, hasmask, 1, value)
+ def show(self, prefix=''):
+ outstr = prefix + "ip_proto\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class ipv4_src(oxm_tlv):
+ """
+ Wrapper class for ipv4_src match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ if not hasmask:
+ oxm_tlv.__init__(self, OFPXMT_OFB_IPV4_SRC, hasmask, 4, value)
+ else:
+ oxm_tlv.__init__(self, OFPXMT_OFB_IPV4_SRC, hasmask, 4, value, mask)
+ def show(self, prefix=''):
+ outstr = prefix + "ipv4_src\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class ipv4_dst(oxm_tlv):
+ """
+ Wrapper class for ipv4_dst match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ if not hasmask:
+ oxm_tlv.__init__(self, OFPXMT_OFB_IPV4_DST, hasmask, 4, value)
+ else:
+ oxm_tlv.__init__(self, OFPXMT_OFB_IPV4_DST, hasmask, 4, value, mask)
+ def show(self, prefix=''):
+ outstr = prefix + "ipv4_dst\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class tcp_src(oxm_tlv):
+ """
+ Wrapper class for tcp_src match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_TCP_SRC, hasmask, 2, value)
+ def show(self, prefix=''):
+ outstr = prefix + "tcp_src\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class tcp_dst(oxm_tlv):
+ """
+ Wrapper class for tcp_src match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_TCP_DST, hasmask, 2, value)
+ def show(self, prefix=''):
+ outstr = prefix + "tcp_dst\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class udp_src(oxm_tlv):
+ """
+ Wrapper class for udp_src match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_UDP_SRC, hasmask, 2, value)
+ def show(self, prefix=''):
+ outstr = prefix + "udp_src\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class udp_dst(oxm_tlv):
+ """
+ Wrapper class for udp_dst match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_UDP_DST, hasmask, 2, value)
+ def show(self, prefix=''):
+ outstr = prefix + "udp_dst\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class sctp_src(oxm_tlv):
+ """
+ Wrapper class for sctp_src match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_SCTP_SRC, hasmask, 2, value)
+ def show(self, prefix=''):
+ outstr = prefix + "sctp_src\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+
+class sctp_dst(oxm_tlv):
+ """
+ Wrapper class for sctp_dst match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_SCTP_DST, hasmask, 2, value)
+ def show(self, prefix=''):
+ outstr = prefix + "sctp_dst\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class icmpv4_type(oxm_tlv):
+ """
+ Wrapper class for icmpv4_type match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_ICMPV4_TYPE, hasmask, 1, value)
+ def show(self, prefix=''):
+ outstr = prefix + "icmpv4_type\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class icmpv4_code(oxm_tlv):
+ """
+ Wrapper class for icmpv4_code match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_ICMPV4_CODE, hasmask, 1, value)
+ def show(self, prefix=''):
+ outstr = prefix + "icmpv4_code\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outs
+
+class arp_op(oxm_tlv):
+ """
+ Wrapper class for arp_op match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_ARP_OP, hasmask, 2, value)
+ def show(self, prefix=''):
+ outstr = prefix + "arp_op\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outs
+
+class arp_spa(oxm_tlv):
+ """
+ Wrapper class for arp_spa match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ if not hasmask:
+ oxm_tlv.__init__(self, OFPXMT_OFB_ARP_SPA, hasmask, 4, value)
+ else:
+ oxm_tlv.__init__(self, OFPXMT_OFB_ARP_SPA, hasmask, 4, value, mask)
+ def show(self, prefix=''):
+ outstr = prefix + "arp_spa\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class arp_tpa(oxm_tlv):
+ """
+ Wrapper class for arp_tpa match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ if not hasmask:
+ oxm_tlv.__init__(self, OFPXMT_OFB_ARP_TPA, hasmask, 4, value)
+ else:
+ oxm_tlv.__init__(self, OFPXMT_OFB_ARP_TPA, hasmask, 4, value, mask)
+ def show(self, prefix=''):
+ outstr = prefix + "arp_tpa\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+
+class arp_sha(oxm_tlv):
+ """
+ Wrapper class for arp_sha match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ if not hasmask:
+ oxm_tlv.__init__(self, OFPXMT_OFB_ARP_SHA, hasmask, 6, value)
+ else:
+ oxm_tlv.__init__(self, OFPXMT_OFB_ARP_SHA, hasmask, 12, value)
+ def show(self, prefix=''):
+ outstr = prefix + "arp_sha\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class arp_tha(oxm_tlv):
+ """
+ Wrapper class for arp_tha match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ if not hasmask:
+ oxm_tlv.__init__(self, OFPXMT_OFB_ARP_THA, hasmask, 6, value)
+ else:
+ oxm_tlv.__init__(self, OFPXMT_OFB_ARP_THA, hasmask, 12, value)
+ def show(self, prefix=''):
+ outstr = prefix + "arp_tha\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class ipv6_src(oxm_tlv):
+ """
+ Wrapper class for ipv6_src match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ if not hasmask:
+ oxm_tlv.__init__(self, OFPXMT_OFB_IPV6_SRC, False, 16, value)
+ else:
+ oxm_tlv.__init__(self, OFPXMT_OFB_IPV6_SRC, True, 32, value)
+ def show(self, prefix=''):
+ outstr = prefix + "ipv6_src\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class ipv6_dst(oxm_tlv):
+ """
+ Wrapper class for ipv6_dst match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ if not hasmask:
+ oxm_tlv.__init__(self, OFPXMT_OFB_IPV6_DST, False, 16, value)
+ else:
+ oxm_tlv.__init__(self, OFPXMT_OFB_IPV6_DST, True, 32, value)
+ def show(self, prefix=''):
+ outstr = prefix + "ipv6_dst\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class ipv6_flabel(oxm_tlv):
+ """
+ Wrapper class for ipv6_flabel match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ if not hasmask:
+ oxm_tlv.__init__(self, OFPXMT_OFB_IPV6_FLABEL, hasmask, 4, value)
+ else:
+ oxm_tlv.__init__(self, OFPXMT_OFB_IPV6_FLABEL, hasmask, 8, value)
+ def show(self, prefix=''):
+ outstr = prefix + "ipv6_flabel\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class icmpv6_type(oxm_tlv):
+ """
+ Wrapper class for icmpv6_type match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_ICMPV6_TYPE, hasmask, 1, value)
+ def show(self, prefix=''):
+ outstr = prefix + "icmpv6_type\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class icmpv6_code(oxm_tlv):
+ """
+ Wrapper class for icmpv6_code match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_ICMPV6_CODE, hasmask, 1, value)
+ def show(self, prefix=''):
+ outstr = prefix + "icmpv6_code\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outs
+
+class ipv6_nd_target(oxm_tlv):
+ """
+ Wrapper class for ipv6_nd_target match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_IPV6_ND_TARGET, hasmask, 16, value)
+ def show(self, prefix=''):
+ outstr = prefix + "ipv6_nd_target\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class ipv6_nd_sll(oxm_tlv):
+ """
+ Wrapper class for ipv6_nd_sll match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_IPV6_ND_SLL, hasmask, 6, value)
+ def show(self, prefix=''):
+ outstr = prefix + "ipv6_nd_sll\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class ipv6_nd_tll(oxm_tlv):
+ """
+ Wrapper class for ipv6_nd_tll match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_IPV6_ND_TLL, hasmask, 6, value)
+ def show(self, prefix=''):
+ outstr = prefix + "ipv6_nd_tll\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class mpls_label(oxm_tlv):
+ """
+ Wrapper class for mpls_label match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_MPLS_LABEL, hasmask, 4, value)
+ def show(self, prefix=''):
+ outstr = prefix + "mpls_label\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+class mpls_tc(oxm_tlv):
+ """
+ Wrapper class for mpls_ltc match object
+
+ Data members inherited from oxm_tlv:
+ @arg class
+ @arg field
+ @arg hasmask
+ @arg body
+
+ """
+ def __init__(self, value, hasmask = False):
+ oxm_tlv.__init__(self, OFPXMT_OFB_MPLS_TC, hasmask, 1, value)
+ def show(self, prefix=''):
+ outstr = prefix + "mpls_tc\n"
+ outstr += oxm_tlv.show(self, prefix)
+ return outstr
+
+match_class_list = (
+ in_port,
+ in_phy_port,
+ metadata,
+ eth_dst,
+ eth_src,
+ eth_type,
+ vlan_vid,
+ vlan_pcp,
+ ip_dscp,
+ ip_ecn,
+ ip_proto,
+ ipv4_src,
+ ipv4_dst,
+ tcp_src,
+ tcp_dst,
+ udp_src,
+ udp_dst,
+ sctp_src,
+ sctp_dst,
+ icmpv4_type,
+ icmpv4_code,
+ arp_op,
+ arp_spa,
+ arp_tpa,
+ arp_sha,
+ arp_tha,
+ ipv6_src,
+ ipv6_dst,
+ ipv6_flabel,
+ icmpv6_type,
+ icmpv6_code,
+ ipv6_nd_target,
+ ipv6_nd_sll,
+ ipv6_nd_tll,
+ mpls_label,
+ mpls_tc)
diff --git a/src/python/of12/match_list.py b/src/python/of12/match_list.py
new file mode 100644
index 0000000..2a9660c
--- /dev/null
+++ b/src/python/of12/match_list.py
@@ -0,0 +1,45 @@
+import struct
+import match as match
+from match import oxm_tlv
+from binascii import b2a_hex
+from base_list import ofp_base_list
+
+
+class match_list(ofp_base_list):
+
+ def __init__(self):
+ ofp_base_list.__init__(self)
+ self.tlvs = self.items
+ self.name = "match"
+ self.class_list = match.match_class_list
+
+ def __len__(self):
+ return sum([len(i) for i in self])
+
+ def unpack(self, binary_string, bytes=None):
+ if bytes <= 4:
+ return binary_string[4:]
+ if bytes == None:
+ bytes = len(binary_string)
+ offset = 0
+ cur_string = binary_string
+ while offset < bytes:
+ read = 0
+ oxm_class, oxm_fieldhm, oxm_length = struct.unpack("!HBB", cur_string[read:read+4])
+ #Found padding bytes?
+ if not oxm_class:
+ break
+ oxm_field = oxm_fieldhm >> 1
+ oxm_hasmask = oxm_fieldhm & 0x00000001
+ payload = struct.unpack("!" + str(oxm_length) + "s", cur_string[read+4:read+4+oxm_length])[0]
+ if oxm_hasmask:
+ value, mask = payload[:oxm_length/2], payload[oxm_length/2:]
+ else:
+ value, mask = payload, None
+ oxm = oxm_tlv(oxm_field, oxm_hasmask, oxm_length, value,mask, oxm_class)
+ self.tlvs.append(oxm)
+ read = 4 + oxm_length
+ offset += read
+ cur_string = cur_string[read:]
+
+ return cur_string
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,
+ )
+
diff --git a/src/python/of12/parse.py b/src/python/of12/parse.py
new file mode 100644
index 0000000..262ca53
--- /dev/null
+++ b/src/python/of12/parse.py
@@ -0,0 +1,338 @@
+"""
+OpenFlow message parsing functions
+"""
+
+import sys
+import logging
+import message
+from match_list import match_list
+import match
+#from error import *
+#from action import *
+#from action_list import action_list
+import cstruct as ofp
+
+
+
+
+try:
+ logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
+ from scapy.all import *
+ #load_contrib("mpls")
+ #TODO This should really be in scapy!
+ #bind_layers(MPLS, MPLS, s=0)
+except ImportError:
+ sys.exit("Need to install scapy for packet parsing")
+
+"""
+of_message.py
+Contains wrapper functions and classes for the of_message namespace
+that are generated by hand. It includes the rest of the wrapper
+function information into the of_message namespace
+"""
+
+parse_logger = logging.getLogger("parse")
+#parse_logger.setLevel(logging.DEBUG)
+
+# These message types are subclassed
+msg_type_subclassed = [
+ ofp.OFPT_STATS_REQUEST,
+ ofp.OFPT_STATS_REPLY,
+ ofp.OFPT_ERROR
+]
+
+# Maps from sub-types to classes
+stats_reply_to_class_map = {
+ ofp.OFPST_DESC : message.desc_stats_reply,
+ ofp.OFPST_FLOW : message.flow_stats_reply,
+ ofp.OFPST_AGGREGATE : message.aggregate_stats_reply,
+ ofp.OFPST_TABLE : message.table_stats_reply,
+ ofp.OFPST_PORT : message.port_stats_reply,
+ ofp.OFPST_QUEUE : message.queue_stats_reply,
+ ofp.OFPST_GROUP : message.group_stats_reply,
+ ofp.OFPST_GROUP_DESC : message.group_desc_stats_reply
+# ofp.OFPST_EXPERIMENTER
+}
+
+stats_request_to_class_map = {
+ ofp.OFPST_DESC : message.desc_stats_request,
+ ofp.OFPST_FLOW : message.flow_stats_request,
+ ofp.OFPST_AGGREGATE : message.aggregate_stats_request,
+ ofp.OFPST_TABLE : message.table_stats_request,
+ ofp.OFPST_PORT : message.port_stats_request,
+ ofp.OFPST_QUEUE : message.queue_stats_request,
+ ofp.OFPST_GROUP : message.group_stats_request,
+ ofp.OFPST_GROUP_DESC : message.group_desc_stats_request
+# ofp.OFPST_EXPERIMENTER
+}
+
+error_to_class_map = {
+ ofp.OFPET_HELLO_FAILED : message.hello_failed_error_msg,
+ ofp.OFPET_BAD_REQUEST : message.bad_request_error_msg,
+ ofp.OFPET_BAD_ACTION : message.bad_action_error_msg,
+ ofp.OFPET_BAD_INSTRUCTION : message.bad_instruction_error_msg,
+ ofp.OFPET_BAD_MATCH : message.bad_match_error_msg,
+ ofp.OFPET_FLOW_MOD_FAILED : message.flow_mod_failed_error_msg,
+ ofp.OFPET_GROUP_MOD_FAILED : message.group_mod_failed_error_msg,
+ ofp.OFPET_PORT_MOD_FAILED : message.port_mod_failed_error_msg,
+ ofp.OFPET_TABLE_MOD_FAILED : message.table_mod_failed_error_msg,
+ ofp.OFPET_QUEUE_OP_FAILED : message.queue_op_failed_error_msg,
+ ofp.OFPET_SWITCH_CONFIG_FAILED : message.switch_config_failed_error_msg
+}
+
+# Map from header type value to the underlieing message class
+msg_type_to_class_map = {
+ ofp.OFPT_HELLO : message.hello,
+ ofp.OFPT_ERROR : message.error,
+ ofp.OFPT_ECHO_REQUEST : message.echo_request,
+ ofp.OFPT_ECHO_REPLY : message.echo_reply,
+ ofp.OFPT_EXPERIMENTER : message.experimenter,
+ ofp.OFPT_FEATURES_REQUEST : message.features_request,
+ ofp.OFPT_FEATURES_REPLY : message.features_reply,
+ ofp.OFPT_GET_CONFIG_REQUEST : message.get_config_request,
+ ofp.OFPT_GET_CONFIG_REPLY : message.get_config_reply,
+ ofp.OFPT_SET_CONFIG : message.set_config,
+ ofp.OFPT_PACKET_IN : message.packet_in,
+ ofp.OFPT_FLOW_REMOVED : message.flow_removed,
+ ofp.OFPT_PORT_STATUS : message.port_status,
+ ofp.OFPT_PACKET_OUT : message.packet_out,
+ ofp.OFPT_FLOW_MOD : message.flow_mod,
+ ofp.OFPT_GROUP_MOD : message.group_mod,
+ ofp.OFPT_PORT_MOD : message.port_mod,
+ ofp.OFPT_TABLE_MOD : message.table_mod,
+ ofp.OFPT_STATS_REQUEST : message.stats_request,
+ ofp.OFPT_STATS_REPLY : message.stats_reply,
+ ofp.OFPT_BARRIER_REQUEST : message.barrier_request,
+ ofp.OFPT_BARRIER_REPLY : message.barrier_reply,
+ ofp.OFPT_QUEUE_GET_CONFIG_REQUEST : message.queue_get_config_request,
+ ofp.OFPT_QUEUE_GET_CONFIG_REPLY : message.queue_get_config_reply,
+}
+
+def _of_message_to_object(binary_string):
+ """
+ Map a binary string to the corresponding class.
+
+ Appropriately resolves subclasses
+ """
+ hdr = ofp.ofp_header()
+ hdr.unpack(binary_string)
+ # FIXME: Add error detection
+ if not hdr.type in msg_type_subclassed:
+ return msg_type_to_class_map[hdr.type]()
+ if hdr.type == ofp.OFPT_STATS_REQUEST:
+ sub_hdr = ofp.ofp_stats_request()
+ sub_hdr.unpack(binary_string[ofp.OFP_HEADER_BYTES:])
+ try:
+ obj = stats_request_to_class_map[sub_hdr.type]()
+ except LookupError:
+ obj = None
+ return obj
+ elif hdr.type == ofp.OFPT_STATS_REPLY:
+ sub_hdr = ofp.ofp_stats_reply()
+ sub_hdr.unpack(binary_string[ofp.OFP_HEADER_BYTES:])
+ try:
+ obj = stats_reply_to_class_map[sub_hdr.type]()
+ except LookupError:
+ obj = None
+ return obj
+ elif hdr.type == ofp.OFPT_ERROR:
+ sub_hdr = ofp.ofp_error_msg()
+ sub_hdr.unpack(binary_string[ofp.OFP_HEADER_BYTES:])
+ return error_to_class_map[sub_hdr.type]()
+ else:
+ parse_logger.error("Cannot parse pkt to message")
+ return None
+
+def of_message_parse(binary_string, raw=False):
+ """
+ Parse an OpenFlow packet
+
+ Parses a raw OpenFlow packet into a Python class, with class
+ members fully populated.
+
+ @param binary_string The packet (string) to be parsed
+ @param raw If true, interpret the packet as an L2 packet. Not
+ yet supported.
+ @return An object of some message class or None if fails
+ Note that any data beyond that parsed is not returned
+
+ """
+
+ if raw:
+ parse_logger.error("raw packet message parsing not supported")
+ return None
+
+ obj = _of_message_to_object(binary_string)
+ if obj:
+ obj.unpack(binary_string)
+ return obj
+
+
+def of_header_parse(binary_string, raw=False):
+ """
+ Parse only the header from an OpenFlow packet
+
+ Parses the header from a raw OpenFlow packet into a
+ an ofp_header Python class.
+
+ @param binary_string The packet (string) to be parsed
+ @param raw If true, interpret the packet as an L2 packet. Not
+ yet supported.
+ @return An ofp_header object
+
+ """
+
+ if raw:
+ parse_logger.error("raw packet message parsing not supported")
+ return None
+
+ hdr = ofp.ofp_header()
+ hdr.unpack(binary_string)
+
+ return hdr
+
+map_wc_field_to_match_member = {
+ 'OFPFW_DL_VLAN' : 'dl_vlan',
+ 'OFPFW_DL_SRC' : 'dl_src',
+ 'OFPFW_DL_DST' : 'dl_dst',
+ 'OFPFW_DL_TYPE' : 'dl_type',
+ 'OFPFW_NW_PROTO' : 'nw_proto',
+ 'OFPFW_TP_SRC' : 'tp_src',
+ 'OFPFW_TP_DST' : 'tp_dst',
+ 'OFPFW_NW_SRC_SHIFT' : 'nw_src_shift',
+ 'OFPFW_NW_SRC_BITS' : 'nw_src_bits',
+ 'OFPFW_NW_SRC_MASK' : 'nw_src_mask',
+ 'OFPFW_NW_SRC_ALL' : 'nw_src_all',
+ 'OFPFW_NW_DST_SHIFT' : 'nw_dst_shift',
+ 'OFPFW_NW_DST_BITS' : 'nw_dst_bits',
+ 'OFPFW_NW_DST_MASK' : 'nw_dst_mask',
+ 'OFPFW_NW_DST_ALL' : 'nw_dst_all',
+ 'OFPFW_DL_VLAN_PCP' : 'dl_vlan_pcp',
+ 'OFPFW_NW_TOS' : 'nw_tos'
+}
+
+
+def parse_mac(mac_str):
+ """
+ Parse a MAC address
+
+ Parse a MAC address ':' separated string of hex digits to an
+ array of integer values. '00:d0:05:5d:24:00' => [0, 208, 5, 93, 36, 0]
+ @param mac_str The string to convert
+ @return Array of 6 integer values
+ """
+ return map(lambda val:eval("0x" + val), mac_str.split(":"))
+
+def parse_ip(ip_str):
+ """
+ Parse an IP address
+
+ Parse an IP address '.' separated string of decimal digits to an
+ host ordered integer. '172.24.74.77' =>
+ @param ip_str The string to convert
+ @return Integer value
+ """
+ array = map(lambda val:eval(val),ip_str.split("."))
+ val = 0
+ for a in array:
+ val <<= 8
+ val += a
+ return val
+
+def packet_to_flow_match(packet):
+ """
+ Create a flow match that matches packet with the given wildcards
+
+ @param packet The packet to use as a flow template
+ @param pkt_format Currently only L2 is supported. Will indicate the
+ overall packet type for parsing
+ @return An ofp_match object if successful. None if format is not
+ recognized. The wildcards of the match will be cleared for the
+ values extracted from the packet.
+
+ @todo check min length of packet
+ @todo Check if packet is other than L2 format
+ @todo implement other fields covered by OpenFlow 1.2
+ """
+ match_ls = match_list()
+
+ if Ether in packet:
+ ether = packet[Ether]
+ eth_type = match.eth_type(ether.type)
+ eth_dst = match.eth_dst(parse_mac(ether.dst))
+ eth_src = match.eth_src(parse_mac(ether.src))
+ match_ls.add(eth_type)
+ match_ls.add(eth_dst)
+ match_ls.add(eth_src)
+ else:
+ return match_ls
+
+ if Dot1Q in packet:
+ #TODO: nicer way to get last vlan tag?
+ vlan = packet[Dot1Q:0]
+ vlan_vid = match.vlan_vid(vlan.vlan)
+ vlan_pcp = match.vlan_pcp(vlan.prio)
+ match_ls.add(vlan_vid)
+ match_ls.add(vlan_pcp)
+ vlan_pl = vlan.payload
+ while vlan_pl is not None and vlan_pl.name == Dot1Q.name:
+ vlan = vlan_pl
+ vlan_pl = vlan.payload
+ #We need to overwrite the already
+ # inserted eth_type
+ eth_index = match.tlvs.index()
+ eth_type = match.eth_type(vlan.type)
+ match_ls.tlvs.insert(vlan.type,eth_index)
+ #TODO ARP
+
+ if MPLS in packet:
+ mpls = packet[MPLS:0]
+ mpls_label = match.mpls_label(mpls.label)
+ mpls_tc = match.mpls_tc(mpls.cos)
+ match_ls.add(mpls_label)
+ match_ls.add(mpls_tc)
+ return match_ls
+
+ if IP in packet:
+ ip = packet[IP]
+ ipv4_src = match.ipv4_src(parse_ip(ip.src))
+ ipv4_dst = match.ipv4_dst(parse_ip(ip.dst))
+ ip_dscp = match.ip_dscp(ip.tos >> 2)
+ ip_ecn = match.ip_ecn(ip.tos & 0x03)
+ match_ls.add(ipv4_src)
+ match_ls.add(ipv4_dst)
+ match_ls.add(ip_dscp)
+ match_ls.add(ip_ecn)
+ else:
+ return match_ls
+
+ if TCP in packet:
+ tcp = packet[TCP]
+ ip_proto = match.ip_proto(6)
+ tcp_src = match.tcp_src(tcp.sport)
+ tcp_dst = match.tcp_dst(tcp.dport)
+ match_ls.add(ip_proto)
+ match_ls.add(tcp_src)
+ match_ls.add(tcp_dst)
+ return match_ls
+
+ if UDP in packet:
+ udp = packet[UDP]
+ ip_proto = match.ip_proto(17)
+ udp_src = match.tcp_src(udp.sport)
+ udp_dst = match.tcp_dst(udp.dport)
+ match_ls.add(ip_proto)
+ match_ls.add(udp_src)
+ match_ls.add(udp_dst)
+ returnmatch_ls
+
+ if ICMP in packet:
+ icmp = packet[ICMP]
+ ip_proto = match.ip_proto(1)
+ icmp_type = match.icmp_type(icmp.type)
+ icmp_code = match.icmp_code(icmp.code)
+ match_ls.add(icmp_type)
+ match_ls.add(icmp_code)
+ return match_ls
+
+ return match_ls
diff --git a/src/python/oftest/oft12/__init__.py b/src/python/oftest/oft12/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/python/oftest/oft12/__init__.py
diff --git a/src/python/oftest/oft12/packet.py b/src/python/oftest/oft12/packet.py
new file mode 100644
index 0000000..23a3e6e
--- /dev/null
+++ b/src/python/oftest/oft12/packet.py
@@ -0,0 +1,1300 @@
+######################################################################
+#
+# All files associated with the OpenFlow Python Test (oftest) are
+# made available for public use and benefit with the expectation
+# that others will use, modify and enhance the Software and contribute
+# those enhancements back to the community. However, since we would
+# like to make the Software available for broadest use, with as few
+# restrictions as possible permission is hereby granted, free of
+# charge, to any person obtaining a copy of this Software to deal in
+# the Software under the copyrights without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject
+# to the following conditions:
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+######################################################################
+import os
+
+"""
+OpenFlow packet class
+
+This class implements the basic abstraction of an OpenFlow packet. It
+includes parsing functionality and OpenFlow actions related to
+packet modifications.
+"""
+
+import socket
+import struct
+import logging
+import oftest.cstruct as ofp
+import unittest
+import binascii
+import string
+import collections #@UnresolvedImport
+import oftest.action as action
+
+ETHERTYPE_IP = 0x0800
+ETHERTYPE_VLAN = 0x8100
+ETHERTYPE_VLAN_QinQ = 0x88a8
+ETHERTYPE_ARP = 0x0806
+ETHERTYPE_MPLS = 0x8847
+ETHERTYPE_MPLS_MCAST = 0x8848
+ETHERTYPES_MPLS = [ETHERTYPE_MPLS, ETHERTYPE_MPLS_MCAST]
+
+DL_MASK_ALL = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
+NW_MASK_ALL = 0xffffffff
+
+MPLS_BOTTOM_OF_STACK = 0x00000100
+
+# Sigh.. not python26
+#MplsTag = collections.namedtuple("MplsTag", "label tc ttl")
+
+class MplsTag(object):
+ def __init__(self, label, tc, ttl):
+ self.label = label
+ self.tc = tc
+ self.ttl = ttl
+ def pack(self, bos = 0):
+ packed_tag = ((self.label & 0xfffff) << 12) | \
+ ((self.tc & 0x7) << 9) | \
+ (self.ttl & 0xFF) | \
+ (MPLS_BOTTOM_OF_STACK if bos else 0)
+ return packed_tag
+
+ def unpack(packed_tag):
+ tag = MplsTag(packed_tag >> 12,
+ (packed_tag >> 9) & 0x0007,
+ packed_tag & 0xFF)
+ bos = bool(packed_tag & MPLS_BOTTOM_OF_STACK)
+ return (tag, bos)
+ unpack = staticmethod(unpack)
+
+class Packet(object):
+ """
+ Packet abstraction
+
+ This is meant to support the abstraction of a packet in an
+ OpenFlow 1.1 switch so it includes an action set, ingress port,
+ and metadata. These members may be ignored and the rest of the
+ packet parsing and modification functions used to manipulate
+ a packet.
+ """
+
+ icmp_counter = 1
+
+ def __init__(self, in_port=None, data=""):
+ # Use entries in match when possible.
+ self.in_port = in_port
+ self.data = data
+ self.bytes = len(data)
+ self.match = ofp.ofp_match()
+ self.logger = logging.getLogger("packet")
+ self.instructions = []
+ # parsable tags
+ self.ip_header_offset = None
+ self.tcp_header_offset = None
+ self.mpls_tag_offset = None # pointer to outer mpls tag
+ self.vlan_tag_offset = None # pointer to outer vlan tag
+ self.action_set = {}
+ self.queue_id = 0
+
+ if self.data != "":
+ self.parse()
+
+ def show(self):
+ """ Return a ascii hex representation of the packet's data"""
+ ret = ""
+ c = 0
+ for b in list(self.data):
+ if c != 0:
+ if c % 16 == 0:
+ ret += '\n'
+ elif c % 8 == 0:
+ ret += ' '
+ c += 1
+ ret += "%0.2x " % struct.unpack('B', b)
+ return ret
+
+ def __repr__(self):
+ return self.data
+
+ def __str__(self):
+ return self.__repr__()
+
+ def __len__(self):
+ return len(self.data)
+
+ def simple_tcp_packet(self,
+ pktlen=100,
+ dl_dst='00:01:02:03:04:05',
+ dl_src='00:06:07:08:09:0a',
+ dl_vlan_enable=False,
+ dl_vlan_type=ETHERTYPE_VLAN,
+ dl_vlan=0,
+ dl_vlan_pcp=0,
+ dl_vlan_cfi=0,
+ mpls_type=None,
+ mpls_tags=None,
+ ip_src='192.168.0.1',
+ ip_dst='192.168.0.2',
+ ip_tos=0,
+ ip_ttl=64,
+ tcp_sport=1234,
+ tcp_dport=80):
+ """
+ Return a simple dataplane TCP packet
+
+ Supports a few parameters:
+ @param len Length of packet in bytes w/o CRC
+ @param dl_dst Destinatino MAC
+ @param dl_src Source MAC
+ @param dl_vlan_enable True if the packet is with vlan, False otherwise
+ @param dl_vlan_type Ether type for VLAN
+ @param dl_vlan VLAN ID
+ @param dl_vlan_pcp VLAN priority
+ @param ip_src IP source
+ @param ip_dst IP destination
+ @param ip_tos IP ToS
+ @param tcp_dport TCP destination port
+ @param tcp_sport TCP source port
+
+ Generates a simple TCP request. Users shouldn't assume anything
+ about this packet other than that it is a valid ethernet/IP/TCP frame.
+ """
+ self.data = ""
+ self._make_ip_packet(dl_dst, dl_src, dl_vlan_enable, dl_vlan_type,
+ dl_vlan, dl_vlan_pcp, dl_vlan_cfi,
+ mpls_type, mpls_tags,
+ ip_tos, ip_ttl, ip_src, ip_dst, socket.IPPROTO_TCP)
+
+ # Add TCP header
+ self.data += struct.pack("!HHLLBBHHH",
+ tcp_sport,
+ tcp_dport,
+ 1, # tcp.seq
+ 0, # tcp.ack
+ 0x50, # tcp.doff + tcp.res1
+ 0x12, # tcp.syn + tcp.ack
+ 0, # tcp.wnd
+ 0, # tcp.check
+ 0, # tcp.urgent pointer
+ )
+
+ # Fill out packet
+ self.data += "D" * (pktlen - len(self.data))
+ return self
+
+ def simple_icmp_packet(self,
+ pktlen=100,
+ dl_dst='00:01:02:03:04:05',
+ dl_src='00:06:07:08:09:0a',
+ dl_vlan_enable=False,
+ dl_vlan_type=ETHERTYPE_VLAN,
+ dl_vlan=0,
+ dl_vlan_pcp=0,
+ dl_vlan_cfi=0,
+ mpls_type=None,
+ mpls_tags=None,
+ ip_src='192.168.0.1',
+ ip_dst='192.168.0.2',
+ ip_tos=0,
+ ip_ttl=64,
+ icmp_type=8, # ICMP_ECHO_REQUEST
+ icmp_code=0,
+ ):
+ """
+ Return a simple dataplane ICMP packet
+
+ Supports a few parameters:
+ @param len Length of packet in bytes w/o CRC
+ @param dl_dst Destinatino MAC
+ @param dl_src Source MAC
+ @param dl_vlan_enable True if the packet is with vlan, False otherwise
+ @param dl_vlan_type Ether type for VLAN
+ @param dl_vlan VLAN ID
+ @param dl_vlan_pcp VLAN priority
+ @param ip_src IP source
+ @param ip_dst IP destination
+ @param ip_tos IP ToS
+ @param tcp_dport TCP destination port
+ @param ip_sport TCP source port
+
+ Generates a simple TCP request. Users shouldn't assume anything
+ about this packet other than that it is a valid ethernet/IP/TCP frame.
+ """
+ self.data = ""
+ self._make_ip_packet(dl_dst, dl_src, dl_vlan_enable, dl_vlan_type,
+ dl_vlan, dl_vlan_pcp, dl_vlan_cfi,
+ mpls_type, mpls_tags,
+ ip_tos,
+ ip_ttl, ip_src, ip_dst, socket.IPPROTO_ICMP)
+
+ # Add ICMP header
+ self.data += struct.pack("!BBHHH",
+ icmp_type,
+ icmp_code,
+ 0, # icmp.checksum
+ os.getpid() & 0xffff, # icmp.echo.id
+ Packet.icmp_counter # icmp.echo.seq
+ )
+ Packet.icmp_counter += 1
+
+ # Fill out packet
+ self.data += "D" * (pktlen - len(self.data))
+
+ return self
+
+ def _make_ip_packet(self, dl_dst, dl_src, dl_vlan_enable, dl_vlan_type,
+ dl_vlan, dl_vlan_pcp, dl_vlan_cfi, mpls_type, mpls_tags,
+ ip_tos, ip_ttl, ip_src, ip_dst, ip_proto):
+ self.data = ""
+ addr = dl_dst.split(":")
+ for byte in map(lambda z: int(z, 16), addr):
+ self.data += struct.pack("!B", byte)
+ addr = dl_src.split(":")
+ for byte in map(lambda z: int(z, 16), addr):
+ self.data += struct.pack("!B", byte)
+
+ if (dl_vlan_enable):
+ # Form and add VLAN tag
+ self.data += struct.pack("!H", dl_vlan_type)
+ vtag = (dl_vlan & 0x0fff) | \
+ (dl_vlan_pcp & 0x7) << 13 | \
+ (dl_vlan_cfi & 0x1) << 12
+ self.data += struct.pack("!H", vtag)
+
+ if mpls_tags:
+ # Add type/len field
+ self.data += struct.pack("!H", mpls_type)
+ mpls_tags = list(mpls_tags)
+ while len(mpls_tags):
+ tag = mpls_tags.pop(0)
+ packed_tag = tag.pack(bos = not len(mpls_tags))
+ self.data += struct.pack("!I", packed_tag)
+
+ else:
+ # Add type/len field
+ self.data += struct.pack("!H", ETHERTYPE_IP)
+
+ # Add IP header
+ v_and_hlen = 0x45 # assumes no ip or tcp options
+ ip_len = 120 + 40 # assumes no ip or tcp options
+ self.data += struct.pack("!BBHHHBBH", v_and_hlen, ip_tos, ip_len,
+ 0, # ip.id
+ 0, # ip.frag_off
+ ip_ttl, # ip.ttl
+ ip_proto,
+ 0) # ip.checksum
+ # convert ipsrc/dst to ints
+ self.data += struct.pack("!LL", ascii_ip_to_bin(ip_src),
+ ascii_ip_to_bin(ip_dst))
+
+ def length(self):
+ return len(self.data)
+
+ def clear_actions(self):
+ self.action_set = {}
+
+ def parse(self):
+ """
+ Update the headers in self.match based on self.data
+
+ Parses the relevant header features out of the packet, using
+ the table outlined in the OF1.1 spec, Figure 4
+ """
+ self.bytes = len(self.data)
+ self.match.in_port = self.in_port
+ self.match.type = ofp.OFPMT_STANDARD
+ self.match.length = ofp.OFPMT_STANDARD_LENGTH
+ self.match.wildcards = 0
+ self.match.nw_dst_mask = 0
+ self.match.nw_dst_mask = 0
+ self.match.dl_dst_mask = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
+ self.match.dl_src_mask = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
+ self.mpls_tag_offset = None
+ self.ip_header_offset = None
+
+ idx = 0
+ try:
+ idx = self._parse_l2(idx)
+
+ if self.match.dl_type == ETHERTYPE_IP:
+ self.ip_header_offset = idx
+ idx = self._parse_ip(idx)
+ if self.match.nw_proto in [ socket.IPPROTO_TCP,
+ socket.IPPROTO_UDP,
+ socket.IPPROTO_ICMP]:
+ self.tcp_header_offset = idx
+ if self.match.nw_proto != socket.IPPROTO_ICMP:
+ idx = self._parse_l4(idx)
+ else:
+ idx = self._parse_icmp(idx)
+ elif self.match.dl_type == ETHERTYPE_ARP:
+ self._parse_arp(idx)
+ except (parse_error), e:
+ self.logger.warn("Giving up on parsing packet, got %s" %
+ (str(e)))
+ return None
+ return self.match
+
+ def _parse_arp(self, idx):
+ # @todo Implement
+ pass
+
+ def _parse_l2(self, idx):
+ """
+ Parse Layer2 Headers of packet
+
+ Parse ether src,dst,type (and vlan and QinQ headers if exists) from
+ self.data starting at idx
+ """
+ if self.bytes < 14 :
+ raise parse_error("_parse_l2:: packet too shorter <14 bytes")
+
+ self.match.dl_dst = list(struct.unpack("!6B", self.data[idx:idx+6]))
+ self.match.dl_dst_mask = DL_MASK_ALL
+ idx += 6
+ self.match.dl_src = list(struct.unpack("!6B", self.data[idx:idx+6]))
+ self.match.dl_src_mask = DL_MASK_ALL
+ idx += 6
+ #pdb.set_trace()
+ l2_type = struct.unpack("!H", self.data[idx:idx+2])[0]
+ idx += 2
+ if l2_type in [ETHERTYPE_VLAN, ETHERTYPE_VLAN_QinQ] :
+ self.vlan_tag_offset = 12
+ blob = struct.unpack("!H", self.data[idx:idx+2])[0]
+ idx += 2
+ self.match.dl_vlan_pcp = (blob & 0xe000) >> 13
+ #cfi = blob & 0x1000 #@todo figure out what to do if cfi!=0
+ self.match.dl_vlan = blob & 0x0fff
+ l2_type = struct.unpack("!H", self.data[idx:idx+2])[0]
+ # now skip past any more nest VLAN tags (per the spec)
+ while l2_type in [ETHERTYPE_VLAN, ETHERTYPE_VLAN_QinQ] :
+ idx += 4
+ if self.bytes < idx :
+ raise parse_error("_parse_l2(): Too many vlan tags")
+ l2_type = struct.unpack("!H", self.data[idx:idx+2])[0]
+ idx += 2
+ else:
+ self.vlan_tag_offset = None
+ self.match.dl_vlan = ofp.OFPVID_NONE
+ self.match.dl_vlan_pcp = 0
+
+ if l2_type in ETHERTYPES_MPLS:
+ if self.bytes < (idx + 4):
+ raise parse_error("_parse_l2: Invalid MPLS header")
+ self.mpls_tag_offset = idx
+ tag = struct.unpack("!I", self.data[idx:idx+4])[0]
+ self.match.mpls_label = tag >> 12
+ self.match.mpls_tc = (tag >> 9) & 0x0007
+ idx += 4
+ else:
+ self.match.mpls_label = 0
+ self.match.mpls_tc = 0
+
+ self.match.dl_type = l2_type
+ return idx
+
+ def _parse_ip(self, idx):
+ """
+ Parse IP Headers of a packet starting at self.data[idx]
+ """
+ if self.bytes < (idx + 20) :
+ raise parse_error("_parse_ip: Invalid IP header")
+ # the three blanks are id (2bytes), frag offset (2bytes),
+ # and ttl (1byte)
+ (hlen_and_v, self.match.nw_tos, len, _,_,_, self.match.nw_proto) = \
+ struct.unpack("!BBHHHBB", self.data[idx:idx+10])
+ #@todo add fragmentation parsing
+ hlen = hlen_and_v & 0x0f
+ (self.match.nw_src, self.match.nw_dst) = \
+ struct.unpack("!II", self.data[idx + 12:idx+20])
+ self.match.nw_dst_mask = NW_MASK_ALL
+ self.match.nw_src_mask = NW_MASK_ALL
+ return idx + (hlen *4) # this should correctly skip IP options
+
+ def _parse_l4(self, idx):
+ """
+ Parse the src/dst ports of UDP and TCP packets
+ """
+ if self.bytes < (idx + 8):
+ raise parse_error("_parse_l4: Invalid L4 header")
+ (self.match.tp_src, self.match.tp_dst) = \
+ struct.unpack("!HH", self.data[idx:idx+4])
+
+ def _parse_icmp(self, idx):
+ """
+ Parse the type/code of ICMP Packets
+ """
+ if self.bytes < (idx + 4):
+ raise parse_error("_parse_icmp: Invalid icmp header")
+ # yes, type and code get stored into tp_dst and tp_src...
+ (self.match.tp_src, self.match.tp_dst) = \
+ struct.unpack("!BB", self.data[idx:idx+2])
+
+
+ #
+ # NOTE: See comment string in write_action regarding exactly
+ # when actions are executed (for apply vs write instructions)
+ #
+
+ def write_action(self, action):
+ """
+ Write the action into the packet's action set
+
+ Note that we do nothing to the packet when the write_action
+ instruction is executed. We only record the actions for
+ later processing. Because of this, the output port is not
+ explicitly recorded in the packet; that state is recorded
+ in the action_set[set_output] item.
+ """
+ self.action_set[action.__class__] = action
+
+ def _set_1bytes(self,offset,byte):
+ """ Writes the byte at data[offset]
+
+ This function only exists to match the other _set_Xbytes() and
+ is trivial
+
+ """
+ tmp= "%s%s" % (self.data[0:offset],
+ struct.pack('B',byte & 0xff))
+ if len(self.data) > offset + 1 :
+ tmp += self.data[offset+1:len(self.data)]
+ self.data=tmp
+
+ def _set_2bytes(self,offset,short):
+ """ Writes the 2 byte short in network byte order at data[offset] """
+ tmp= "%s%s" % (self.data[0:offset],
+ struct.pack('!H',short & 0xffff))
+ if len(self.data) > offset + 2 :
+ tmp += self.data[offset+2:len(self.data)]
+ self.data=tmp
+
+ def _set_4bytes(self,offset,word,forceNBO=True):
+ """ Writes the 4 byte word at data[offset]
+
+ Use network byte order if forceNBO is True,
+ else it's assumed that word is already in NBO
+
+ """
+ # @todo Verify byte order
+ #pdb.set_trace()
+ fmt ="L"
+ if forceNBO:
+ fmt = '!' + fmt
+
+ tmp= "%s%s" % (self.data[0:offset],
+ struct.pack(fmt,word & 0xffffffff))
+ if len(self.data) > offset + 4 :
+ tmp += self.data[offset+4:len(self.data)]
+ self.data=tmp
+
+ def _set_6bytes(self,offset,byte_list):
+ """ Writes the 6 byte sequence in the given order to data[offset] """
+ # @todo Do as a slice
+ tmp= self.data[0:offset]
+ tmp += struct.pack("BBBBBB", *byte_list)
+ if len(self.data) > offset + 6 :
+ tmp += self.data[offset+6:len(self.data)]
+ self.data=tmp
+
+ def _update_l4_checksum(self):
+ """ Recalculate the L4 checksum, if there
+
+ Can be safely called on non-tcp/non-udp packets as a NOOP
+ """
+ if (self.ip_header_offset is None or
+ self.tcp_header_offset is None):
+ return
+ if self.match.nw_proto == socket.IPPROTO_TCP:
+ return self._update_tcp_checksum()
+ elif self.match.nw_proto == socket.IPPROTO_UDP:
+ return self._update_udp_checksum()
+
+ def _update_tcp_checksum(self):
+ """ Recalculate the TCP checksum
+
+ @warning: Must only be called on actual TCP Packets
+ """
+ #@todo implemnt tcp checksum update
+ pass
+
+ def _update_udp_checksum(self):
+ """ Recalculate the TCP checksum
+
+ @warning: Must only be called on actual TCP Packets
+ """
+ #@todo implemnt udp checksum update
+ pass
+
+ def set_metadata(self, value, mask):
+ self.match.metadata = (self.match.metadata & ~mask) | \
+ (value & mask)
+
+ #
+ # These are the main action operations that take the
+ # required parameters
+ #
+ # Note that 'group', 'experimenter' and 'set_output' are only
+ # implemented for the action versions.
+
+ def set_queue(self, queue_id):
+ self.queue_id = queue_id
+
+ def set_vlan_vid(self, vid):
+ # @todo Verify proper location of VLAN id
+ if self.vlan_tag_offset is None:
+ self.logger.debug("set_vlan_vid(): Adding new vlan tag to untagged packet")
+ self.push_vlan(ETHERTYPE_VLAN)
+ offset = self.vlan_tag_offset + 2
+ short = struct.unpack('!H', self.data[offset:offset+2])[0]
+ short = (short & 0xf000) | ((vid & 0x0fff) )
+ self.data = self.data[0:offset] + struct.pack('!H',short) + \
+ self.data[offset+2:len(self.data)]
+ self.match.dl_vlan = vid & 0x0fff
+ self.logger.debug("set_vlan_vid(): setting packet vlan_vid to 0x%x " %
+ self.match.dl_vlan)
+
+ def set_vlan_pcp(self, pcp):
+ # @todo Verify proper location of VLAN pcp
+ if self.vlan_tag_offset is None:
+ return
+ offset = self.vlan_tag_offset + 2
+ short = struct.unpack('!H', self.data[offset:offset+2])[0]
+ short = (pcp<<13 & 0xf000) | ((short & 0x0fff) )
+ self.data = self.data[0:offset] + struct.pack('!H',short) + \
+ self.data[offset+2:len(self.data)]
+ self.match.dl_vlan_pcp = pcp & 0xf
+
+ def set_dl_src(self, dl_src):
+ self._set_6bytes(6, dl_src)
+ self.match.dl_src = dl_src
+
+ def set_dl_dst(self, dl_dst):
+ self._set_6bytes(0, dl_dst)
+ self.match.dl_dst = dl_dst
+
+ def set_nw_src(self, nw_src):
+ if self.ip_header_offset is None:
+ return
+ self._set_4bytes(self.ip_header_offset + 12, nw_src)
+ self._update_l4_checksum()
+ self.match.nw_src = nw_src
+
+ def set_nw_dst(self, nw_dst):
+ # @todo Verify byte order
+ if self.ip_header_offset is None:
+ return
+ self._set_4bytes(self.ip_header_offset + 16, nw_dst)
+ self._update_l4_checksum()
+ self.match.nw_dst = nw_dst
+
+ def set_nw_tos(self, tos):
+ if self.ip_header_offset is None:
+ return
+ self._set_1bytes(self.ip_header_offset + 1, tos)
+ self.match.nw_tos = tos
+
+ def set_nw_ecn(self, ecn):
+ #@todo look up ecn implementation details
+ pass
+
+ def set_tp_src(self, tp_src):
+ if self.tcp_header_offset is None:
+ return
+ if (self.match.nw_proto == socket.IPPROTO_TCP or
+ self.match.nw_proto == socket.IPPROTO_UDP):
+ self._set_2bytes(self.tcp_header_offset, tp_src)
+ elif (self.match.nw_proto == socket.IPPROTO_ICMP):
+ self._set_1bytes(self.tcp_header_offset, tp_src)
+ self._update_l4_checksum()
+ self.match.tp_src = tp_src
+
+ def set_tp_dst(self, tp_dst):
+ if self.tcp_header_offset is None:
+ return
+ if (self.match.nw_proto == socket.IPPROTO_TCP or
+ self.match.nw_proto == socket.IPPROTO_UDP):
+ self._set_2bytes(self.tcp_header_offset +2, tp_dst)
+ elif (self.match.nw_proto == socket.IPPROTO_ICMP):
+ self._set_1bytes(self.tcp_header_offset + 1, tp_dst)
+ self._update_l4_checksum()
+ self.match.tp_dst = tp_dst
+
+ IP_OFFSET_TTL = 8
+
+ def copy_ttl_out(self):
+ if self.mpls_tag_offset is None:
+ # No MPLS tag.
+ return
+ outerTag = struct.unpack("!I", self.data[self.mpls_tag_offset:
+ self.mpls_tag_offset+4])[0]
+ if not (outerTag & MPLS_BOTTOM_OF_STACK):
+ # Payload is another MPLS tag:
+ innerTag = struct.unpack("!I", self.data[self.mpls_tag_offset+4:
+ self.mpls_tag_offset+8])[0]
+ outerTag = (outerTag & 0xFFFFFF00) | (innerTag & 0x000000FF)
+ self._set_4bytes(self.mpls_tag_offset, outerTag)
+ else:
+ # This MPLS tag is the bottom of the stack.
+ # See if the payload looks like it might be IPv4.
+ versionLen = struct.unpack("B",
+ self.data[self.mpls_tag_offset+4])[0]
+ if versionLen >> 4 != 4:
+ # This is not IPv4.
+ return;
+ # This looks like IPv4, so copy the TTL.
+ ipTTL = struct.unpack("B", self.data[self.mpls_tag_offset + 4 +
+ Packet.IP_OFFSET_TTL])[0]
+ outerTag = (outerTag & 0xFFFFFF00) | (ipTTL & 0xFF)
+ self._set_4bytes(self.mpls_tag_offset, outerTag)
+ return
+
+ def copy_ttl_in(self):
+ if self.mpls_tag_offset is None:
+ # No MPLS tag.
+ return
+ outerTag = struct.unpack("!I", self.data[self.mpls_tag_offset:
+ self.mpls_tag_offset+4])[0]
+ if not (outerTag & MPLS_BOTTOM_OF_STACK):
+ # Payload is another MPLS tag:
+ innerTag = struct.unpack("!I", self.data[self.mpls_tag_offset+4:
+ self.mpls_tag_offset+8])[0]
+ innerTag = (innerTag & 0xFFFFFF00) | (outerTag & 0x000000FF)
+ self._set_4bytes(self.mpls_tag_offset+4, innerTag)
+ else:
+ # This MPLS tag is the bottom of the stack.
+ # See if the payload looks like it might be IPv4.
+ versionLen = struct.unpack("B", self.data[self.mpls_tag_offset+4])[0]
+ if versionLen >> 4 != 4:
+ # This is not IPv4.
+ return;
+ # This looks like IPv4, so copy the TTL.
+ self._set_1bytes(self.mpls_tag_offset + 4 + Packet.IP_OFFSET_TTL,
+ outerTag & 0x000000FF)
+ #@todo update checksum
+ return
+
+ def set_mpls_label(self, mpls_label):
+ if self.mpls_tag_offset is None:
+ return
+ tag = struct.unpack("!I", self.data[self.mpls_tag_offset:
+ self.mpls_tag_offset+4])[0]
+ tag = ((mpls_label & 0xfffff) << 12) | (tag & 0x00000fff)
+ self.match.mpls_label = mpls_label
+ self._set_4bytes(self.mpls_tag_offset, tag)
+
+ def set_mpls_tc(self, mpls_tc):
+ if self.mpls_tag_offset is None:
+ return
+ tag = struct.unpack("!I", self.data[self.mpls_tag_offset:
+ self.mpls_tag_offset+4])[0]
+ tag = ((mpls_tc & 0x7) << 9) | (tag & 0xfffff1ff)
+ self.match.mpls_tc = mpls_tc
+ self._set_4bytes(self.mpls_tag_offset, tag)
+
+ def set_mpls_ttl(self, ttl):
+ if self.mpls_tag_offset is None:
+ return
+ self._set_1bytes(self.mpls_tag_offset + 3, ttl)
+
+ def dec_mpls_ttl(self):
+ if self.mpls_tag_offset is None:
+ return
+ ttl = struct.unpack("B", self.data[self.mpls_tag_offset + 3])[0]
+ self.set_mpls_ttl(ttl - 1)
+
+ def push_vlan(self, ethertype):
+ if len(self) < 14:
+ self.logger.error("NOT Pushing a new VLAN tag: packet too short!")
+ pass # invalid ethernet frame, can't add vlan tag
+
+ # from 4.8.1 of the spec, default values are zero
+ # on a push operation if no VLAN tag already exists
+ l2_type = struct.unpack("!H", self.data[12:14])[0]
+ if ((l2_type == ETHERTYPE_VLAN) or (l2_type == ETHERTYPE_VLAN_QinQ)):
+ current_tag = struct.unpack("!H", self.data[14:16])[0]
+ else:
+ current_tag = 0
+ new_tag = struct.pack('!HH',
+ # one of 0x8100 or x88a8
+ # could check to enforce this?
+ ethertype & 0xffff,
+ current_tag
+ )
+ self.data = self.data[0:12] + new_tag + self.data[12:len(self.data)]
+ self.parse()
+
+ def pop_vlan(self):
+ if self.vlan_tag_offset is None:
+ pass
+ self.data = self.data[0:12] + self.data[16:len(self.data)]
+ self.parse()
+
+ def push_mpls(self, ethertype):
+ tag = MplsTag(0, 0, 0)
+ bos = False
+
+ if self.mpls_tag_offset:
+ # The new tag defaults to the old one.
+ packed_tag = struct.unpack("!I", self.data[self.mpls_tag_offset:
+ self.mpls_tag_offset+4])[0]
+ (tag, _) = MplsTag.unpack(packed_tag)
+
+ else:
+ # Pushing a new label stack, set the BoS bit and get TTL from IP.
+ bos = True
+ if self.ip_header_offset:
+ ttl = struct.unpack("B", self.data[self.ip_header_offset + \
+ Packet.IP_OFFSET_TTL])[0]
+ tag = MplsTag(0, 0, ttl)
+
+ self.data = self.data[0:14] + \
+ struct.pack("!I", tag.pack(bos)) + \
+ self.data[14:]
+ self._set_2bytes(12, ethertype)
+ # Reparse to update offsets, ethertype, etc.
+ self.parse()
+
+ def pop_mpls(self, ethertype):
+ # Ignore if no existing tags.
+ if self.mpls_tag_offset:
+ self.data = self.data[0:self.mpls_tag_offset] + \
+ self.data[self.mpls_tag_offset + 4:]
+ self._set_2bytes(12, ethertype)
+
+ # Reparse to update offsets, ethertype, etc.
+ self.parse()
+
+ def set_nw_ttl(self, ttl):
+ if self.ip_header_offset is None:
+ return
+ self._set_1bytes(self.ip_header_offset + Packet.IP_OFFSET_TTL, ttl)
+ self._update_l4_checksum()
+ # don't need to update self.match; no ttl in it
+
+ def dec_nw_ttl(self):
+ if self.ip_header_offset is None:
+ return
+ offset = self.ip_header_offset + Packet.IP_OFFSET_TTL
+ old_ttl = struct.unpack("b",self.data[offset:offset + 1])[0]
+ self.set_nw_ttl( old_ttl - 1)
+
+ #
+ # All action functions need to take the action object for params
+ # These take an action object to facilitate the switch implementation
+ #
+
+ def action_output(self, action, switch):
+ if action.port < ofp.OFPP_MAX:
+ switch.dataplane.send(action.port, self.data,
+ queue_id=self.queue_id)
+ elif action.port == ofp.OFPP_ALL:
+ for of_port in switch.ports.iterkeys():
+ if of_port != self.in_port:
+ switch.dataplane.send(of_port, self.data,
+ queue_id=self.queue_id)
+ elif action.port == ofp.OFPP_IN_PORT:
+ switch.dataplane.send(self.in_port, self.data,
+ queue_id=self.queue_id)
+ else:
+ switch.logger.error("NEED to implement action_output" +
+ " for port %d" % action.port)
+
+ def action_set_queue(self, action, switch):
+ self.set_queue(action.queue_id)
+
+ def action_set_vlan_vid(self, action, switch):
+ self.set_vlan_vid(action.vlan_vid)
+
+ def action_set_vlan_pcp(self, action, switch):
+ self.set_vlan_pcp(action.vlan_pcp)
+
+ def action_set_dl_src(self, action, switch):
+ self.set_dl_src(action.dl_addr)
+
+ def action_set_dl_dst(self, action, switch):
+ self.set_dl_dst(action.dl_addr)
+
+ def action_set_nw_src(self, action, switch):
+ self.set_nw_src(action.nw_addr)
+
+ def action_set_nw_dst(self, action, switch):
+ self.set_nw_dst(action.nw_addr)
+
+ def action_set_nw_tos(self, action, switch):
+ self.set_nw_tos(action.nw_tos)
+
+ def action_set_nw_ecn(self, action, switch):
+ self.set_nw_ecn(action.nw_ecn)
+
+ def action_set_tp_src(self, action, switch):
+ self.set_tp_src(action.tp_port)
+
+ def action_set_tp_dst(self, action, switch):
+ self.set_tp_dst(action.tp_port)
+
+ def action_copy_ttl_out(self, action, switch):
+ self.copy_ttl_out()
+
+ def action_copy_ttl_in(self, action, switch):
+ self.copy_ttl_in()
+
+ def action_set_mpls_label(self, action, switch):
+ self.set_mpls_label(action.mpls_label)
+
+ def action_set_mpls_tc(self, action, switch):
+ self.set_mpls_tc(action.mpls_tc)
+
+ def action_set_mpls_ttl(self, action, switch):
+ self.set_mpls_ttl(action.mpls_ttl)
+
+ def action_dec_mpls_ttl(self, action, switch):
+ self.dec_mpls_ttl()
+
+ def action_push_vlan(self, action, switch):
+ self.push_vlan(action.ethertype)
+
+ def action_pop_vlan(self, action, switch):
+ self.pop_vlan()
+
+ def action_push_mpls(self, action, switch):
+ self.push_mpls(action.ethertype)
+
+ def action_pop_mpls(self, action, switch):
+ self.pop_mpls(action.ethertype)
+
+ def action_experimenter(self, action, switch):
+ pass
+
+ def action_set_nw_ttl(self, action, switch):
+ self.set_nw_ttl(action.nw_ttl)
+
+ def action_dec_nw_ttl(self, action, switch):
+ self.dec_nw_ttl()
+
+ def action_group(self, action, switch):
+ pass
+
+ def execute_action_set(self, switch):
+ """
+ Execute the actions in the action set for the packet
+ according to the order given in ordered_action_list.
+
+ This determines the order in which
+ actions in the packet's action set are executed
+
+ @param switch The parent switch object (for sending pkts out)
+
+ @todo Verify the ordering in this list
+ """
+ cls = action.action_copy_ttl_in
+ if cls in self.action_set.keys():
+ self.logger.debug("Action copy_ttl_in")
+ self.action_copy_ttl_in(self.action_set[cls], switch)
+
+ cls = action.action_pop_mpls
+ if cls in self.action_set.keys():
+ self.logger.debug("Action pop_mpls")
+ self.action_pop_mpls(self.action_set[cls], switch)
+ cls = action.action_pop_vlan
+ if cls in self.action_set.keys():
+ self.logger.debug("Action pop_vlan")
+ self.action_pop_vlan(self.action_set[cls], switch)
+ cls = action.action_push_mpls
+ if cls in self.action_set.keys():
+ self.logger.debug("Action push_mpls")
+ self.action_push_mpls(self.action_set[cls], switch)
+ cls = action.action_push_vlan
+ if cls in self.action_set.keys():
+ self.logger.debug("Action push_vlan")
+ self.action_push_vlan(self.action_set[cls], switch)
+
+ cls = action.action_dec_mpls_ttl
+ if cls in self.action_set.keys():
+ self.logger.debug("Action dec_mpls_ttl")
+ self.action_dec_mpls_ttl(self.action_set[cls], switch)
+ cls = action.action_dec_nw_ttl
+ if cls in self.action_set.keys():
+ self.logger.debug("Action dec_nw_ttl")
+ self.action_dec_nw_ttl(self.action_set[cls], switch)
+ cls = action.action_copy_ttl_out
+ if cls in self.action_set.keys():
+ self.logger.debug("Action copy_ttl_out")
+ self.action_copy_ttl_out(self.action_set[cls], switch)
+
+ cls = action.action_set_dl_dst
+ if cls in self.action_set.keys():
+ self.logger.debug("Action set_dl_dst")
+ self.action_set_dl_dst(self.action_set[cls], switch)
+ cls = action.action_set_dl_src
+ if cls in self.action_set.keys():
+ self.logger.debug("Action set_dl_src")
+ self.action_set_dl_src(self.action_set[cls], switch)
+ cls = action.action_set_mpls_label
+ if cls in self.action_set.keys():
+ self.logger.debug("Action set_mpls_label")
+ self.action_set_mpls_label(self.action_set[cls], switch)
+ cls = action.action_set_mpls_tc
+ if cls in self.action_set.keys():
+ self.logger.debug("Action set_mpls_tc")
+ self.action_set_mpls_tc(self.action_set[cls], switch)
+ cls = action.action_set_mpls_ttl
+ if cls in self.action_set.keys():
+ self.logger.debug("Action set_mpls_ttl")
+ self.action_set_mpls_ttl(self.action_set[cls], switch)
+ cls = action.action_set_nw_dst
+ if cls in self.action_set.keys():
+ self.logger.debug("Action set_nw_dst")
+ self.action_set_nw_dst(self.action_set[cls], switch)
+ cls = action.action_set_nw_ecn
+ if cls in self.action_set.keys():
+ self.logger.debug("Action set_nw_ecn")
+ self.action_set_nw_ecn(self.action_set[cls], switch)
+ cls = action.action_set_nw_src
+ if cls in self.action_set.keys():
+ self.logger.debug("Action set_nw_src")
+ self.action_set_nw_src(self.action_set[cls], switch)
+ cls = action.action_set_nw_tos
+ if cls in self.action_set.keys():
+ self.logger.debug("Action set_nw_tos")
+ self.action_set_nw_tos(self.action_set[cls], switch)
+ cls = action.action_set_nw_ttl
+ if cls in self.action_set.keys():
+ self.logger.debug("Action set_nw_ttl")
+ self.action_set_nw_ttl(self.action_set[cls], switch)
+ cls = action.action_set_queue
+ if cls in self.action_set.keys():
+ self.logger.debug("Action set_queue")
+ self.action_set_queue(self.action_set[cls], switch)
+ cls = action.action_set_tp_dst
+ if cls in self.action_set.keys():
+ self.logger.debug("Action set_tp_dst")
+ self.action_set_tp_dst(self.action_set[cls], switch)
+ cls = action.action_set_tp_src
+ if cls in self.action_set.keys():
+ self.logger.debug("Action set_tp_src")
+ self.action_set_tp_src(self.action_set[cls], switch)
+ cls = action.action_set_vlan_pcp
+ if cls in self.action_set.keys():
+ self.logger.debug("Action set_vlan_pcp")
+ self.action_set_vlan_pcp(self.action_set[cls], switch)
+ cls = action.action_set_vlan_vid
+ if cls in self.action_set.keys():
+ self.logger.debug("Action set_vlan_vid")
+ self.action_set_vlan_vid(self.action_set[cls], switch)
+
+ cls = action.action_group
+ if cls in self.action_set.keys():
+ self.logger.debug("Action group")
+ self.action_group(self.action_set[cls], switch)
+ cls = action.action_experimenter
+ if cls in self.action_set.keys():
+ self.logger.debug("Action experimenter")
+ self.action_experimenter(self.action_set[cls], switch)
+ cls = action.action_output
+ if cls in self.action_set.keys():
+ self.logger.debug("Action set_output")
+ self.action_output(self.action_set[cls], switch)
+
+
+def ascii_ip_to_bin(ip):
+ """ Take '192.168.0.1' and return the NBO decimal equivalent 0xc0a80101 """
+ #Lookup the cleaner, one-line way of doing this
+ # or if there isn't just a library (!?)
+ s = ip.split('.')
+ return struct.unpack("!L", struct.pack("BBBB", int(s[0]),
+ int(s[1]),
+ int(s[2]),
+ int(s[3]) ))[0]
+
+
+class parse_error(Exception):
+ """
+ Thrown internally if there is an error in packet parsing
+ """
+
+ def __init__(self, why):
+ self.why = why
+
+ def __str__(self):
+ return "%s:: %s" % (super.__str__(self), self.why)
+
+class packet_test(unittest.TestCase):
+ """
+ Unit tests for packet class
+ """
+
+ def ascii_to_data(self, str):
+ return binascii.unhexlify(str.translate(string.maketrans('',''),
+ string.whitespace))
+
+ def setUp(self):
+ """
+ Simple packet data for parsing tests.
+
+ Ethernet II, Src: Fujitsu_ef:cd:8d (00:17:42:ef:cd:8d),
+ Dst: ZhsZeitm_5d:24:00 (00:d0:05:5d:24:00)
+ Internet Protocol, Src: 172.24.74.96 (172.24.74.96),
+ Dst: 171.64.74.58 (171.64.74.58)
+ Transmission Control Protocol, Src Port: 59581 (59581),
+ Dst Port: ssh (22), Seq: 2694, Ack: 2749, Len: 48
+ """
+ pktdata = self.ascii_to_data(
+ """00 d0 05 5d 24 00 00 17 42 ef cd 8d 08 00 45 10
+ 00 64 65 67 40 00 40 06 e9 29 ac 18 4a 60 ab 40
+ 4a 3a e8 bd 00 16 7c 28 2f 88 f2 bd 7a 03 80 18
+ 00 b5 ec 49 00 00 01 01 08 0a 00 d1 46 8b 32 ed
+ 7c 88 78 4b 8a dc 0a 1f c4 d3 02 a3 ae 1d 3c aa
+ 6f 1a 36 9f 27 11 12 71 5b 5d 88 f2 97 fa e7 f9
+ 99 c1 9f 9c 7f c5 1e 3e 45 c6 a6 ac ec 0b 87 64
+ 98 dd""")
+ self.pkt = Packet(data=pktdata)
+
+ """
+ MPLS packet data for MPLS parsing tests.
+
+ Ethernet II, Src: Fujitsu_ef:cd:8d (00:17:42:ef:cd:8d),
+ Dst: ZhsZeitm_5d:24:00 (00:d0:05:5d:24:00)
+ MPLS, Label: 0xFEFEF, TC: 5, S: 1, TTL: 0xAA
+ Internet Protocol, Src: 172.24.74.96 (172.24.74.96),
+ Dst: 171.64.74.58 (171.64.74.58)
+ Transmission Control Protocol, Src Port: 59581 (59581),
+ Dst Port: ssh (22), Seq: 2694, Ack: 2749, Len: 48
+ """
+ mplspktdata = self.ascii_to_data(
+ """00 d0 05 5d 24 00 00 17 42 ef cd 8d 88 47
+ FE FE FB AA
+ 45 10 00 64 65 67 40 00 40 06 e9 29 ac 18 4a 60
+ ab 40 4a 3a
+ e8 bd 00 16 7c 28 2f 88 f2 bd 7a 03 80 18
+ 00 b5 ec 49 00 00 01 01 08 0a 00 d1 46 8b 32 ed
+ 7c 88 78 4b 8a dc 0a 1f c4 d3 02 a3 ae 1d 3c aa
+ 6f 1a 36 9f 27 11 12 71 5b 5d 88 f2 97 fa e7 f9
+ 99 c1 9f 9c 7f c5 1e 3e 45 c6 a6 ac ec 0b 87 64
+ 98 dd""")
+ self.mplspkt = Packet(data=mplspktdata)
+
+ def runTest(self):
+ self.assertTrue(self.pkt)
+
+class l2_parsing_test(packet_test):
+ def runTest(self):
+ match = self.pkt.match
+ self.assertEqual(match.dl_dst,[0x00,0xd0,0x05,0x5d,0x24,0x00])
+ self.assertEqual(match.dl_src,[0x00,0x17,0x42,0xef,0xcd,0x8d])
+ self.assertEqual(match.dl_type,ETHERTYPE_IP)
+
+class mpls_parsing_test(packet_test):
+ def runTest(self):
+ match = self.mplspkt.match
+ self.assertEqual(match.mpls_label, 0xFEFEF)
+ self.assertEqual(match.mpls_tc, 5)
+
+class ip_parsing_test(packet_test):
+ def runTest(self):
+ match = self.pkt.match
+ # @todo Verify byte ordering of the following
+ self.assertEqual(match.nw_dst,ascii_ip_to_bin('171.64.74.58'))
+ self.assertEqual(match.nw_src,ascii_ip_to_bin('172.24.74.96'))
+ self.assertEqual(match.nw_proto, socket.IPPROTO_TCP)
+
+class mpls_setting_test(packet_test):
+ def runTest(self):
+ orig_len = len(self.mplspkt)
+ label = 0x12345
+ tc = 6
+ ttl = 0x78
+ self.mplspkt.set_mpls_label(label)
+ self.mplspkt.set_mpls_tc(tc)
+ self.mplspkt.set_mpls_ttl(ttl)
+ self.mplspkt.dec_mpls_ttl()
+ self.mplspkt.parse()
+
+ self.assertEqual(len(self.mplspkt), orig_len)
+ self.assertTrue(self.mplspkt.mpls_tag_offset)
+ match = self.mplspkt.match
+
+ self.assertEqual(match.mpls_label, label)
+ self.assertEqual(match.mpls_tc, tc)
+ new_ttl = struct.unpack("B", self.mplspkt.data[self.mplspkt.mpls_tag_offset + 3:
+ self.mplspkt.mpls_tag_offset + 4])[0]
+ self.assertEqual(new_ttl, ttl - 1)
+
+class mpls_pop_test(packet_test):
+ def runTest(self):
+ orig_len = len(self.mplspkt)
+ self.mplspkt.pop_mpls(ETHERTYPE_IP)
+ self.mplspkt.parse()
+
+ self.assertEqual(len(self.mplspkt), orig_len - 4)
+ self.assertFalse(self.mplspkt.mpls_tag_offset)
+ match = self.mplspkt.match
+
+ self.assertEqual(match.dl_type,ETHERTYPE_IP)
+ self.assertEqual(match.nw_dst,ascii_ip_to_bin('171.64.74.58'))
+ self.assertEqual(match.nw_src,ascii_ip_to_bin('172.24.74.96'))
+ self.assertEqual(match.nw_proto, socket.IPPROTO_TCP)
+
+class mpls_push_test(packet_test):
+ def runTest(self):
+ orig_len = len(self.pkt)
+ self.pkt.push_mpls(ETHERTYPE_MPLS)
+ self.pkt.parse()
+
+ self.assertEqual(len(self.pkt), orig_len + 4)
+ self.assertTrue(self.pkt.mpls_tag_offset)
+ match = self.pkt.match
+
+ self.assertEqual(match.dl_type, ETHERTYPE_MPLS)
+ self.assertEqual(match.mpls_label, 0)
+ self.assertEqual(match.mpls_tc, 0)
+
+class ip_setting_test(packet_test):
+ def runTest(self):
+ orig_len = len(self.pkt)
+ ip1 = '11.22.33.44'
+ ip2 = '55.66.77.88'
+ self.pkt.set_nw_src(ascii_ip_to_bin(ip1))
+ self.pkt.set_nw_dst(ascii_ip_to_bin(ip2))
+ self.pkt.parse()
+ self.assertEqual(len(self.pkt), orig_len)
+ match = self.pkt.match
+
+ # @todo Verify byte ordering of the following
+ self.assertEqual(match.nw_src,ascii_ip_to_bin(ip1))
+ self.assertEqual(match.nw_dst,ascii_ip_to_bin(ip2))
+
+
+
+
+class l4_parsing_test(packet_test):
+ def runTest(self):
+ match = self.pkt.match
+ self.assertEqual(match.tp_dst,22)
+ self.assertEqual(match.tp_src,59581)
+
+class l4_setting_test(packet_test):
+ def runTest(self):
+ orig_len = len(self.pkt)
+ self.pkt.set_tp_src(777)
+ self.pkt.set_tp_dst(666)
+ self.pkt.parse()
+ self.assertEqual(len(self.pkt), orig_len)
+ match = self.pkt.match
+ self.assertEqual(match.tp_src,777)
+ self.assertEqual(match.tp_dst,666)
+
+class simple_tcp_test(unittest.TestCase):
+ """ Make sure that simple_tcp_test does what it should
+ pktlen=100,
+ dl_dst='00:01:02:03:04:05',
+ dl_src='00:06:07:08:09:0a',
+ dl_vlan_enable=False,
+ dl_vlan=0,
+ dl_vlan_pcp=0,
+ dl_vlan_cfi=0,
+ ip_src='192.168.0.1',
+ ip_dst='192.168.0.2',
+ ip_tos=0,
+ tcp_sport=1234,
+ tcp_dport=80):
+ """
+ def setUp(self):
+ self.pkt = Packet().simple_tcp_packet()
+ self.pkt.parse()
+ logging.basicConfig(filename="", level=logging.DEBUG)
+ self.logger = logging.getLogger('unittest')
+
+ def runTest(self):
+ match = self.pkt.match
+ self.assertEqual(match.dl_dst, [0x00, 0x01, 0x02, 0x03, 0x04, 0x05])
+ self.assertEqual(match.dl_src, [0x00, 0x06, 0x07, 0x08, 0x09, 0x0a])
+ self.assertEqual(match.dl_type, ETHERTYPE_IP)
+ self.assertEqual(match.nw_src, ascii_ip_to_bin('192.168.0.1'))
+ self.assertEqual(match.nw_dst, ascii_ip_to_bin('192.168.0.2'))
+ self.assertEqual(match.tp_dst, 80)
+ self.assertEqual(match.tp_src, 1234)
+
+class simple_vlan_test(simple_tcp_test):
+ """ Make sure that simple_tcp_test does what it should with vlans
+
+ """
+
+ def runTest(self):
+ self.pkt = Packet().simple_tcp_packet(dl_vlan_enable=True,dl_vlan=0x0abc)
+ self.pkt.parse()
+ match = self.pkt.match
+ #self.logger.debug("Packet=\n%s" % self.pkt.show())
+ self.assertEqual(match.dl_dst, [0x00, 0x01, 0x02, 0x03, 0x04, 0x05])
+ self.assertEqual(match.dl_src, [0x00, 0x06, 0x07, 0x08, 0x09, 0x0a])
+ self.assertEqual(match.dl_type, ETHERTYPE_IP)
+ self.assertEqual(match.nw_src, ascii_ip_to_bin('192.168.0.1'))
+ self.assertEqual(match.nw_dst, ascii_ip_to_bin('192.168.0.2'))
+ self.assertEqual(match.tp_dst, 80)
+ self.assertEqual(match.tp_src, 1234)
+ self.assertEqual(match.dl_vlan, 0xabc)
+
+class vlan_mod(simple_tcp_test):
+ """ Start with a packet with no vlan, add one, change it, remove it"""
+ def runTest(self):
+ old_len = len(self.pkt)
+ match = self.pkt.match
+ self.assertEqual(match.dl_vlan, 0xffff)
+ self.assertEqual(len(self.pkt), old_len)
+ #self.logger.debug("PKT=\n" + self.pkt.show())
+ self.pkt.push_vlan(ETHERTYPE_VLAN) # implicitly pushes vid=0
+ self.assertEqual(len(self.pkt), old_len + 4)
+ self.assertEqual(match.dl_vlan, 0)
+ #self.logger.debug("PKT=\n" + self.pkt.show())
+ self.assertEqual(match.dl_type,ETHERTYPE_IP)
+ self.pkt.set_vlan_vid(0xbabe)
+ self.assertEqual(match.dl_vlan, 0x0abe)
+
+class simple_tcp_with_mpls_test(unittest.TestCase):
+ """ Make sure that simple_tcp_packet does what it should
+ pktlen=100,
+ dl_dst='00:01:02:03:04:05',
+ dl_src='00:06:07:08:09:0a',
+ dl_vlan_enable=False,
+ dl_vlan=0,
+ dl_vlan_pcp=0,
+ dl_vlan_cfi=0,
+ ip_src='192.168.0.1',
+ ip_dst='192.168.0.2',
+ ip_tos=0,
+ tcp_sport=1234,
+ tcp_dport=80):
+ """
+ def setUp(self):
+ tag1 = MplsTag(0xabcde, 0x5, 0xAA)
+ tag2 = MplsTag(0x54321, 0x2, 0xBB)
+ mpls_tags = (tag1, tag2)
+
+ self.pkt = Packet().simple_tcp_packet(mpls_type=ETHERTYPE_MPLS,
+ mpls_tags=mpls_tags)
+ self.pkt.parse()
+
+ def runTest(self):
+ match = self.pkt.match
+ self.assertEqual(match.dl_dst, [0x00, 0x01, 0x02, 0x03, 0x04, 0x05])
+ self.assertEqual(match.dl_src, [0x00, 0x06, 0x07, 0x08, 0x09, 0x0a])
+ self.assertEqual(match.dl_type, ETHERTYPE_MPLS)
+ self.assertEqual(match.mpls_label, 0xabcde)
+ self.assertEqual(match.mpls_tc, 0x5)
+
+if __name__ == '__main__':
+ print("Running packet tests\n")
+ unittest.main()
+
diff --git a/src/python/oftest/oft12/testutils.py b/src/python/oftest/oft12/testutils.py
new file mode 100644
index 0000000..963208f
--- /dev/null
+++ b/src/python/oftest/oft12/testutils.py
@@ -0,0 +1,1517 @@
+
+import sys
+import logging
+from cStringIO import StringIO
+#import types
+
+import of12.cstruct as ofp
+import of12.match as oxm_field
+import of12.message as message
+import of12.action as action
+import of12.parse as parse
+import of12.instruction as instruction
+from packet import Packet
+
+
+try:
+ logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
+ from scapy.all import *
+ #load_contrib("mpls")
+ #TODO This should really be in scapy!
+ #bind_layers(MPLS, MPLS, s=0)
+except ImportError:
+ sys.exit("Need to install scapy for packet parsing")
+
+global skipped_test_count
+skipped_test_count = 0
+
+# Some useful defines
+IP_ETHERTYPE = 0x800
+IPV6_ETHERTYPE = 0x86dd
+ETHERTYPE_VLAN = 0x8100
+ETHERTYPE_MPLS = 0x8847
+TCP_PROTOCOL = 0x6
+UDP_PROTOCOL = 0x11
+ICMPV6_PROTOCOL = 0x3a
+
+
+
+def clear_switch(parent, port_list, logger):
+ """
+ Clear the switch configuration
+
+ @param parent Object implementing controller and assert equal
+ @param logger Logging object
+ """
+ parent.assertTrue(len(port_list) > 2, "Not enough ports for test")
+ for port in port_list:
+ clear_port_config(parent, port, logger)
+ initialize_table_config(parent.controller, logger)
+ delete_all_flows(parent.controller, logger)
+ delete_all_groups(parent.controller, logger)
+
+ return port_list
+
+def initialize_table_config(ctrl, logger):
+ """
+ Initialize all table configs to default setting ("CONTROLLER")
+ @param ctrl The controller object for the test
+ """
+ logger.info("Initializing all table configs")
+ request = message.table_mod()
+ request.config = ofp.OFPTC_TABLE_MISS_CONTROLLER
+ rv = 0
+ for table_id in [0, 1, 2, 3, 4, 5, 6, 7]:
+ request.table_id = table_id
+ rv |= ctrl.message_send(request)
+ return rv
+
+def delete_all_flows(ctrl, logger):
+ """
+ Delete all flows on the switch
+ @param ctrl The controller object for the test
+ @param logger Logging object
+ """
+
+ logger.info("Deleting all flows")
+ #DEFAULT_TABLE_COUNT = 4
+ return delete_all_flows_one_table(ctrl, logger, table_id=0xff)
+
+def delete_all_flows_one_table(ctrl, logger, table_id=0):
+ """
+ Delete all flows on a table
+ @param ctrl The controller object for the test
+ @param logger Logging object
+ @param table_id Table ID
+ """
+ logger.info("Deleting all flows on table ID: " + str(table_id))
+ msg = message.flow_mod()
+ msg.out_port = ofp.OFPP_ANY
+ msg.out_group = ofp.OFPG_ANY
+ msg.command = ofp.OFPFC_DELETE
+ msg.buffer_id = 0xffffffff
+ msg.table_id = table_id
+ logger.debug(msg.show())
+
+ return ctrl.message_send(msg)
+
+def delete_all_groups(ctrl, logger):
+ """
+ Delete all groups on the switch
+ @param ctrl The controller object for the test
+ @param logger Logging object
+ """
+
+ logger.info("Deleting all groups")
+ msg = message.group_mod()
+ msg.group_id = ofp.OFPG_ALL
+ msg.command = ofp.OFPGC_DELETE
+ logger.debug(msg.show())
+ return ctrl.message_send(msg)
+
+def clear_port_config(parent, port, logger):
+ """
+ Clear the port configuration
+
+ @param parent Object implementing controller and assert equal
+ @param logger Logging object
+ """
+ rv = port_config_set(parent.controller, port,
+ 0, 0, logger)
+ parent.assertEqual(rv, 0, "Failed to reset port config")
+
+def simple_tcp_packet(dl_dst='00:01:02:03:04:05',
+ dl_src='00:06:07:08:09:0a',
+ vlan_tags=[], # {type,vid,pcp,cfi} TODO type
+ mpls_tags=[], # {type,label,tc,ttl} TODO type
+ ip_src='192.168.0.1',
+ ip_dst='192.168.0.2',
+ ip_tos=0,
+ ip_ttl=64,
+ tcp_sport=1234,
+ tcp_dport=80,
+ payload_len = 46):
+ pkt = Ether(dst=dl_dst, src=dl_src)
+
+ vlans_num = 0
+ while len(vlan_tags):
+ tag = vlan_tags.pop(0)
+ dot1q = Dot1Q()
+ if 'vid' in tag:
+ dot1q.vlan = tag['vid']
+ if 'pcp' in tag:
+ dot1q.prio = tag['pcp']
+ if 'cfi' in tag:
+ dot1q.id = tag['cfi']
+ pkt = pkt / dot1q
+ if 'type' in tag:
+ if vlans_num == 0:
+ pkt[Ether].setfieldval('type', tag['type'])
+ else:
+ pkt[Dot1Q:vlans_num].setfieldval('type', tag['type'])
+ vlans_num+=1
+
+ mplss_num = 0
+ while len(mpls_tags):
+ tag = mpls_tags.pop(0)
+ mpls = MPLS()
+ if 'label' in tag:
+ mpls.label = tag['label']
+ if 'tc' in tag:
+ mpls.cos = tag['tc']
+ if 'ttl' in tag:
+ mpls.ttl = tag['ttl']
+ pkt = pkt / mpls
+ if 'type' in tag:
+ if mplss_num == 0:
+ if vlans_num == 0:
+ pkt[Ether].setfieldval('type', tag['type'])
+ else:
+ pkt[Dot1Q:vlans_num].setfieldval('type', tag['type'])
+ mplss_num+=1
+
+ pkt = pkt / IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl) \
+ / TCP(sport=tcp_sport, dport=tcp_dport)
+
+ pkt = pkt / ("D" * payload_len)
+
+ return pkt
+
+def simple_icmp_packet(dl_dst='00:01:02:03:04:05',
+ dl_src='00:06:07:08:09:0a',
+ vlan_tags=[], # {type,vid,pcp,cfi} TODO type
+ mpls_tags=[], # {type,label,tc,ttl} TODO type
+ ip_src='192.168.0.1',
+ ip_dst='192.168.0.2',
+ ip_tos=0,
+ ip_ttl=64,
+ icmp_type=8, # ICMP_ECHO_REQUEST
+ icmp_code=0,
+ payload_len=0):
+
+ #TODO simple_ip_packet
+ pkt = Ether(dst=dl_dst, src=dl_src)
+
+ vlans_num = 0
+ while len(vlan_tags):
+ tag = vlan_tags.pop(0)
+ dot1q = Dot1Q()
+ if 'vid' in tag:
+ dot1q.vlan = tag['vid']
+ if 'pcp' in tag:
+ dot1q.prio = tag['pcp']
+ if 'cfi' in tag:
+ dot1q.id = tag['cfi']
+ pkt = pkt / dot1q
+ if 'type' in tag:
+ if vlans_num == 0:
+ pkt[Ether].setfieldval('type', tag['type'])
+ else:
+ pkt[Dot1Q:vlans_num].setfieldval('type', tag['type'])
+ vlans_num+=1
+
+ mplss_num = 0
+ while len(mpls_tags):
+ tag = mpls_tags.pop(0)
+ mpls = MPLS()
+ if 'label' in tag:
+ mpls.label = tag['label']
+ if 'tc' in tag:
+ mpls.cos = tag['tc']
+ if 'ttl' in tag:
+ mpls.ttl = tag['ttl']
+ pkt = pkt / mpls
+ if 'type' in tag:
+ if mplss_num == 0:
+ if vlans_num == 0:
+ pkt[Ether].setfieldval('type', tag['type'])
+ else:
+ pkt[Dot1Q:vlans_num].setfieldval('type', tag['type'])
+ mplss_num+=1
+
+ pkt = pkt / IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl) \
+ / ICMP(type=icmp_type, code=icmp_code)
+
+ pkt = pkt / ("D" * payload_len)
+
+ return pkt
+
+def simple_ipv6_packet(pktlen=100,
+ dl_dst='00:01:02:03:04:05',
+ dl_src='00:06:07:08:09:0a',
+ dl_vlan_enable=False,
+ dl_vlan=0,
+ dl_vlan_pcp=0,
+ dl_vlan_cfi=0,
+ ip_src='fe80::2420:52ff:fe8f:5189',
+ ip_dst='fe80::2420:52ff:fe8f:5190',
+ ip_tos=0,
+ tcp_sport=0,
+ tcp_dport=0,
+ EH = False,
+ EHpkt = IPv6ExtHdrDestOpt()
+ ):
+
+ """
+ Return a simple IPv6 packet
+
+ Supports a few parameters:
+ @param len Length of packet in bytes w/o CRC
+ @param dl_dst Destinatino MAC
+ @param dl_src Source MAC
+ @param dl_vlan_enable True if the packet is with vlan, False otherwise
+ @param dl_vlan VLAN ID
+ @param dl_vlan_pcp VLAN priority
+ @param ip_src IPv6 source
+ @param ip_dst IPv6 destination
+ @param ip_tos IP ToS
+ @param tcp_dport TCP destination port
+ @param ip_sport TCP source port
+
+ """
+ # Note Dot1Q.id is really CFI
+ if (dl_vlan_enable):
+ pkt = Ether(dst=dl_dst, src=dl_src)/ \
+ Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
+ IPv6(src=ip_src, dst=ip_dst)
+
+ else:
+ pkt = Ether(dst=dl_dst, src=dl_src)/ \
+ IPv6(src=ip_src, dst=ip_dst)
+
+ # Add IPv6 Extension Headers
+ if EH:
+ pkt = pkt / EHpkt
+
+ if (tcp_sport >0 and tcp_dport >0):
+ pkt = pkt / TCP(sport=tcp_sport, dport=tcp_dport)
+
+ if pktlen > len(pkt) :
+ pkt = pkt/("D" * (pktlen - len(pkt)))
+
+ return pkt
+
+def simple_icmpv6_packet(pktlen=100,
+ dl_dst='00:01:02:03:04:05',
+ dl_src='00:06:07:08:09:0a',
+ dl_vlan_enable=False,
+ dl_vlan=0,
+ dl_vlan_pcp=0,
+ dl_vlan_cfi=0,
+ ip_src='fe80::2420:52ff:fe8f:5189',
+ ip_dst='fe80::2420:52ff:fe8f:5190',
+ ip_tos=0,
+ tcp_sport=0,
+ tcp_dport=0,
+ EH = False,
+ EHpkt = IPv6ExtHdrDestOpt(),
+ route_adv = False,
+ sll_enabled = False
+ ):
+
+ """
+ Return a simple dataplane ICMPv6 packet
+
+ Supports a few parameters:
+ @param len Length of packet in bytes w/o CRC
+ @param dl_dst Destinatino MAC
+ @param dl_src Source MAC
+ @param dl_vlan_enable True if the packet is with vlan, False otherwise
+ @param dl_vlan VLAN ID
+ @param dl_vlan_pcp VLAN priority
+ @param ip_src IPv6 source
+ @param ip_dst IPv6 destination
+ @param ip_tos IP ToS
+ @param tcp_dport TCP destination port
+ @param ip_sport TCP source port
+
+ """
+ if (dl_vlan_enable):
+ pkt = Ether(dst=dl_dst, src=dl_src)/ \
+ Dot1Q(prio=dl_vlan_pcp, id=dl_vlan_cfi, vlan=dl_vlan)/ \
+ IPv6(src=ip_src, dst=ip_dst)
+
+ else:
+ pkt = Ether(dst=dl_dst, src=dl_src)/ \
+ IPv6(src=ip_src, dst=ip_dst)
+
+
+ # Add IPv6 Extension Headers
+ if EH:
+ pkt = pkt / EHpkt
+
+ if route_adv:
+ pkt = pkt/ \
+ ICMPv6ND_RA(chlim=255, H=0L, M=0L, O=1L, routerlifetime=1800, P=0L, retranstimer=0, prf=0L, res=0L)/ \
+ ICMPv6NDOptPrefixInfo(A=1L, res2=0, res1=0L, L=1L, len=4, prefix='fd00:141:64:1::', R=0L, validlifetime=1814400, prefixlen=64, preferredlifetime=604800, type=3)
+ if sll_enabled :
+ pkt = pkt/ \
+ ICMPv6NDOptSrcLLAddr(type=1, len=1, lladdr='66:6f:df:2d:7c:9c')
+ else :
+ pkt = pkt/ \
+ ICMPv6EchoRequest()
+ if (tcp_sport >0 and tcp_dport >0):
+ pkt = pkt / TCP(sport=tcp_sport, dport=tcp_dport)
+
+ if pktlen > len(pkt) :
+ pkt = pkt/("D" * (pktlen - len(pkt)))
+
+ return pkt
+
+
+def do_barrier(ctrl):
+ b = message.barrier_request()
+ ctrl.transact(b)
+
+
+def port_config_get(controller, port_no, logger):
+ """
+ Get a port's configuration
+
+ Gets the switch feature configuration and grabs one port's
+ configuration
+
+ @returns (hwaddr, config, advert) The hwaddress, configuration and
+ advertised values
+ """
+ request = message.features_request()
+ reply, _ = controller.transact(request, timeout=2)
+ if reply is None:
+ logger.warn("Get feature request failed")
+ return None, None, None
+ logger.debug(reply.show())
+ for idx in range(len(reply.ports)):
+ if reply.ports[idx].port_no == port_no:
+ return (reply.ports[idx].hw_addr, reply.ports[idx].config,
+ reply.ports[idx].advertised)
+
+ logger.warn("Did not find port number for port config")
+ return None, None, None
+
+def port_config_set(controller, port_no, config, mask, logger):
+ """
+ Set the port configuration according the given parameters
+
+ Gets the switch feature configuration and updates one port's
+ configuration value according to config and mask
+ """
+ logger.info("Setting port " + str(port_no) + " to config " + str(config))
+ request = message.features_request()
+ reply, _ = controller.transact(request, timeout=2)
+ if reply is None:
+ return -1
+ logger.debug(reply.show())
+ for idx in range(len(reply.ports)):
+ if reply.ports[idx].port_no == port_no:
+ break
+ if idx >= len(reply.ports):
+ return -1
+ mod = message.port_mod()
+ mod.port_no = port_no
+ mod.hw_addr = reply.ports[idx].hw_addr
+ mod.config = config
+ mod.mask = mask
+ mod.advertise = reply.ports[idx].advertised
+ rv = controller.message_send(mod)
+ return rv
+
+def receive_pkt_check(dataplane, pkt, yes_ports, no_ports, assert_if, logger):
+ """
+ Check for proper receive packets across all ports
+ @param dataplane The dataplane object
+ @param pkt Expected packet; may be None if yes_ports is empty
+ @param yes_ports Set or list of ports that should recieve packet
+ @param no_ports Set or list of ports that should not receive packet
+ @param assert_if Object that implements assertXXX
+ """
+ for ofport in yes_ports:
+ logger.debug("Checking for pkt on port " + str(ofport))
+ (_, rcv_pkt, _) = dataplane.poll(
+ port_number=ofport, timeout=1)
+ assert_if.assertTrue(rcv_pkt is not None,
+ "Did not receive pkt on " + str(ofport))
+ assert_if.assertEqual(str(pkt), str(rcv_pkt),
+ "Response packet does not match send packet " +
+ "on port " + str(ofport))
+
+ for ofport in no_ports:
+ logger.debug("Negative check for pkt on port " + str(ofport))
+ (_, rcv_pkt, _) = dataplane.poll(
+ port_number=ofport, timeout=1)
+ assert_if.assertTrue(rcv_pkt is None,
+ "Unexpected pkt on port " + str(ofport))
+
+
+def pkt_verify(parent, rcv_pkt, exp_pkt):
+ if str(exp_pkt) != str(rcv_pkt):
+ parent.logger.error("ERROR: Packet match failed.")
+ parent.logger.debug("Expected (" + str(len(exp_pkt)) + ")")
+ parent.logger.debug(str(exp_pkt).encode('hex'))
+ sys.stdout = tmpout = StringIO()
+ exp_pkt.show()
+ sys.stdout = sys.__stdout__
+ parent.logger.debug(tmpout.getvalue())
+ parent.logger.debug("Received (" + str(len(rcv_pkt)) + ")")
+ parent.logger.debug(str(rcv_pkt).encode('hex'))
+ sys.stdout = tmpout = StringIO()
+ Ether(rcv_pkt).show()
+ sys.stdout = sys.__stdout__
+ parent.logger.debug(tmpout.getvalue())
+ parent.assertEqual(str(exp_pkt), str(rcv_pkt),
+ "Packet match error")
+
+ return rcv_pkt
+
+def receive_pkt_verify(parent, egr_port, exp_pkt):
+ """
+ Receive a packet and verify it matches an expected value
+
+ parent must implement dataplane, assertTrue and assertEqual
+ """
+ (rcv_port, rcv_pkt, _) = parent.dataplane.poll(port_number=egr_port,
+ timeout=1)
+
+ if exp_pkt is None:
+ if rcv_pkt is None:
+ return None
+ else:
+ parent.logger.error("ERROR: Received unexpected packet from " + str(egr_port));
+ return rcv_pkt
+
+ if rcv_pkt is None:
+ parent.logger.error("ERROR: No packet received from " + str(egr_port))
+
+ parent.assertTrue(rcv_pkt is not None,
+ "Did not receive packet port " + str(egr_port))
+ parent.logger.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
+ str(rcv_port))
+
+ return pkt_verify(parent, rcv_pkt, exp_pkt)
+
+def packetin_verify(parent, exp_pkt):
+ """
+ Receive packet_in and verify it matches an expected value
+ """
+ (response, _) = parent.controller.poll(ofp.OFPT_PACKET_IN, 2)
+
+ parent.assertTrue(response is not None, 'Packet in message not received')
+ if str(exp_pkt) != response.data:
+ parent.logger.debug("pkt len " + str(len(str(exp_pkt))) + ": "
+ + str(exp_pkt).encode('hex'))
+ parent.logger.debug("resp len " + str(len(str(response.data))) + ": "
+ + str(response.data).encode('hex'))
+ parent.assertEqual(str(exp_pkt), response.data,
+ 'PACKET_IN packet does not match send packet')
+
+def match_verify(parent, req_match, res_match):
+ """
+ Verify flow matches agree; if they disagree, report where
+
+ parent must implement assertEqual
+ Use str() to ensure content is compared and not pointers
+ """
+
+ parent.assertEqual(req_match.wildcards, res_match.wildcards,
+ 'Match failed: wildcards: ' + hex(req_match.wildcards) +
+ " != " + hex(res_match.wildcards))
+ parent.assertEqual(req_match.in_port, res_match.in_port,
+ 'Match failed: in_port: ' + str(req_match.in_port) +
+ " != " + str(res_match.in_port))
+ parent.assertEqual(str(req_match.dl_src), str(res_match.dl_src),
+ 'Match failed: dl_src: ' + str(req_match.dl_src) +
+ " != " + str(res_match.dl_src))
+ parent.assertEqual(str(req_match.dl_dst), str(res_match.dl_dst),
+ 'Match failed: dl_dst: ' + str(req_match.dl_dst) +
+ " != " + str(res_match.dl_dst))
+ parent.assertEqual(req_match.dl_vlan, res_match.dl_vlan,
+ 'Match failed: dl_vlan: ' + str(req_match.dl_vlan) +
+ " != " + str(res_match.dl_vlan))
+ parent.assertEqual(req_match.dl_vlan_pcp, res_match.dl_vlan_pcp,
+ 'Match failed: dl_vlan_pcp: ' +
+ str(req_match.dl_vlan_pcp) + " != " +
+ str(res_match.dl_vlan_pcp))
+ parent.assertEqual(req_match.dl_type, res_match.dl_type,
+ 'Match failed: dl_type: ' + str(req_match.dl_type) +
+ " != " + str(res_match.dl_type))
+
+ if (not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
+ and (req_match.dl_type == IP_ETHERTYPE)):
+ parent.assertEqual(req_match.nw_tos, res_match.nw_tos,
+ 'Match failed: nw_tos: ' + str(req_match.nw_tos) +
+ " != " + str(res_match.nw_tos))
+ parent.assertEqual(req_match.nw_proto, res_match.nw_proto,
+ 'Match failed: nw_proto: ' + str(req_match.nw_proto) +
+ " != " + str(res_match.nw_proto))
+ parent.assertEqual(req_match.nw_src, res_match.nw_src,
+ 'Match failed: nw_src: ' + str(req_match.nw_src) +
+ " != " + str(res_match.nw_src))
+ parent.assertEqual(req_match.nw_dst, res_match.nw_dst,
+ 'Match failed: nw_dst: ' + str(req_match.nw_dst) +
+ " != " + str(res_match.nw_dst))
+
+ if (not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
+ and ((req_match.nw_proto == TCP_PROTOCOL)
+ or (req_match.nw_proto == UDP_PROTOCOL))):
+ parent.assertEqual(req_match.tp_src, res_match.tp_src,
+ 'Match failed: tp_src: ' +
+ str(req_match.tp_src) +
+ " != " + str(res_match.tp_src))
+ parent.assertEqual(req_match.tp_dst, res_match.tp_dst,
+ 'Match failed: tp_dst: ' +
+ str(req_match.tp_dst) +
+ " != " + str(res_match.tp_dst))
+
+def flow_removed_verify(parent, request=None, pkt_count=-1, byte_count=-1):
+ """
+ Receive a flow removed msg and verify it matches expected
+
+ @params parent Must implement controller, assertEqual
+ @param pkt_count If >= 0, verify packet count
+ @param byte_count If >= 0, verify byte count
+ """
+ (response, _) = parent.controller.poll(ofp.OFPT_FLOW_REMOVED, 2)
+ parent.assertTrue(response is not None, 'No flow removed message received')
+
+ if request is None:
+ return
+
+ parent.assertEqual(request.cookie, response.cookie,
+ "Flow removed cookie error: " +
+ hex(request.cookie) + " != " + hex(response.cookie))
+
+ req_match = request.match
+ res_match = response.match
+ verifyMatchField(req_match, res_match)
+
+ if (req_match.wildcards != 0):
+ parent.assertEqual(request.priority, response.priority,
+ 'Flow remove prio mismatch: ' +
+ str(request.priority) + " != " +
+ str(response.priority))
+ parent.assertEqual(response.reason, ofp.OFPRR_HARD_TIMEOUT,
+ 'Flow remove reason is not HARD TIMEOUT:' +
+ str(response.reason))
+ if pkt_count >= 0:
+ parent.assertEqual(response.packet_count, pkt_count,
+ 'Flow removed failed, packet count: ' +
+ str(response.packet_count) + " != " +
+ str(pkt_count))
+ if byte_count >= 0:
+ parent.assertEqual(response.byte_count, byte_count,
+ 'Flow removed failed, byte count: ' +
+ str(response.byte_count) + " != " +
+ str(byte_count))
+def flow_msg_create(parent, pkt, ing_port=0, match_fields=None, instruction_list=None,
+ action_list=None,wildcards=0, egr_port=None,
+ egr_queue=None, table_id=0, check_expire=False):
+ """
+ Multi-purpose flow_mod creation utility
+
+ Match on packet with given wildcards.
+ See flow_match_test for other parameter descriptoins
+
+ if egr_queue is set
+ append an out_queue action to egr_queue to the actions_list
+ else if egr_port is set:
+ append an output action to egr_port to the actions_list
+ if the instruction_list is empty,
+ append an APPLY instruction to it
+ Add the action_list to the first write or apply instruction
+
+ @param egr_queue if not None, make the output an enqueue action
+ @param table_id Table ID for writing a flow_mod
+ """
+
+ if match_fields is None:
+ match_fields = parse.packet_to_flow_match(pkt)
+ parent.assertTrue(match_fields is not None, "Flow match from pkt failed")
+ in_port = oxm_field.in_port(ing_port)
+ match_fields.add(in_port)
+ request = message.flow_mod()
+ request.match_fields = match_fields
+ request.buffer_id = 0xffffffff
+ request.table_id = table_id
+
+ if check_expire:
+ request.flags |= ofp.OFPFF_SEND_FLOW_REM
+ request.hard_timeout = 1
+
+ if action_list is None:
+ action_list = []
+ if instruction_list is None:
+ instruction_list = []
+
+ # Set up output/enqueue action if directed
+ if egr_queue is not None:
+ parent.assertTrue(egr_port is not None, "Egress port not set")
+ act = action.action_set_queue()
+ act.port = egr_port
+ act.queue_id = egr_queue
+ action_list.append(act)
+ elif egr_port is not None:
+ act = action.action_output()
+ act.port = egr_port
+ action_list.append(act)
+
+ inst = None
+ if len(instruction_list) == 0:
+ inst = instruction.instruction_apply_actions()
+ instruction_list.append(inst)
+ else:
+ for inst in instruction_list:
+ if (inst.type == ofp.OFPIT_WRITE_ACTIONS or
+ inst.type == ofp.OFPIT_APPLY_ACTIONS):
+ break
+
+ # add all the actions to the last inst
+ for act in action_list:
+ parent.logger.debug("Adding action " + act.show())
+ rv = inst.actions.add(act)
+ parent.assertTrue(rv, "Could not add action" + act.show())
+ # NOTE that the inst has already been added to the flow_mod
+
+ # add all the instrutions to the flow_mod
+ for i in instruction_list:
+ parent.logger.debug("Adding instruction " + inst.show())
+ rv = request.instructions.add(i)
+ parent.assertTrue(rv, "Could not add instruction " + i.show())
+
+
+ parent.logger.debug(request.show())
+ return request
+
+def flow_msg_install(parent, request, clear_table=True):
+ """
+ Install a flow mod message in the switch
+
+ @param parent Must implement controller, assertEqual, assertTrue
+ @param request The request, all set to go
+ @param clear_table If true, clear the flow table before installing
+ """
+ if clear_table:
+ parent.logger.debug("Clear flow table")
+ if request.table_id:
+ table_id = request.table_id
+ else:
+ table_id = 0
+ rc = delete_all_flows_one_table(parent.controller,
+ parent.logger,
+ table_id)
+ parent.assertEqual(rc, 0, "Failed to delete all flows on table: "
+ + str(table_id))
+ do_barrier(parent.controller)
+
+ parent.logger.debug("Insert flow::\n%s" % request.show())
+ rv = parent.controller.message_send(request)
+ parent.assertTrue(rv != -1, "Error installing flow mod")
+ do_barrier(parent.controller)
+
+def error_verify(parent, exp_type, exp_code):
+ """
+ Receive an error msg and verify if it is as expected
+
+ @param parent Must implement controller, assertEqual
+ @param exp_type Expected error type
+ @param exp_code Expected error code
+ """
+ (response, raw) = parent.controller.poll(ofp.OFPT_ERROR, 2)
+ parent.assertTrue(response is not None, 'No error message received')
+
+ if (exp_type is None) or (exp_code is None):
+ parent.logger.debug("Parametrs are not sufficient")
+ return
+
+ parent.assertEqual(exp_type, response.type,
+ 'Error message type mismatch: ' +
+ str(exp_type) + " != " +
+ str(response.type))
+ parent.assertEqual(exp_code, response.code,
+ 'Error message code mismatch: ' +
+ str(exp_code) + " != " +
+ str(response.code))
+
+def flow_match_test_port_pair(parent, ing_port, egr_port, match=None,
+ wildcards=0, mask=None,
+ dl_vlan=-1, pkt=None, exp_pkt=None,
+ apply_action_list=None, check_expire=False):
+ """
+ Flow match test on single TCP packet
+
+ Run test with packet through switch from ing_port to egr_port
+ See flow_match_test for parameter descriptions
+ """
+
+ parent.logger.info("Pkt match test: " + str(ing_port) + " to " + str(egr_port))
+ parent.logger.debug(" WC: " + hex(wildcards) + " vlan: " + str(dl_vlan) +
+ " expire: " + str(check_expire))
+ if pkt is None:
+ if dl_vlan >= 0:
+ pkt = simple_tcp_packet(vlan_tags=[{'vid': dl_vlan}])
+ else:
+ pkt = simple_tcp_packet()
+
+ match = parse.packet_to_flow_match(pkt)
+ parent.assertTrue(match is not None, "Flow match from pkt failed")
+
+ if mask is not None:
+ match.dl_src_mask = mask['dl_src']
+ match.dl_dst_mask = mask['dl_dst']
+ match.nw_src_mask = mask['nw_src']
+ match.nw_dst_mask = mask['nw_dst']
+ #Set unmatching values on corresponding match fields
+ for i in range(ofp.OFP_ETH_ALEN):
+ match.dl_src[i] = match.dl_src[i] ^ match.dl_src_mask[i]
+ match.dl_dst[i] = match.dl_dst[i] ^ match.dl_dst_mask[i]
+ match.nw_src = match.nw_src ^ match.nw_src_mask
+ match.nw_dst = match.nw_dst ^ match.nw_dst_mask
+
+ request = flow_msg_create(parent, pkt, ing_port=ing_port,
+ match=match,
+ wildcards=wildcards, egr_port=egr_port,
+ action_list=apply_action_list)
+
+ flow_msg_install(parent, request)
+
+ parent.logger.debug("Send packet: " + str(ing_port) + " to " + str(egr_port))
+ parent.dataplane.send(ing_port, str(pkt))
+
+ if exp_pkt is None:
+ exp_pkt = pkt
+ receive_pkt_verify(parent, egr_port, exp_pkt)
+
+ if check_expire:
+ #@todo Not all HW supports both pkt and byte counters
+ flow_removed_verify(parent, request, pkt_count=1, byte_count=len(pkt))
+def flow_match_test(parent, port_map, match=None, wildcards=0,
+ mask=None, dl_vlan=-1, pkt=None,
+ exp_pkt=None, apply_action_list=None,
+ check_expire=False, max_test=0):
+ """
+ Run flow_match_test_port_pair on all port pairs
+
+ @param max_test If > 0 no more than this number of tests are executed.
+ @param parent Must implement controller, dataplane, assertTrue, assertEqual
+ and logger
+ @param pkt If not None, use this packet for ingress
+ @param match If not None, use this value in flow_mod
+ @param wildcards For flow match entry
+ @param mask DL/NW address bit masks as a dictionary. If set, it is tested
+ against the corresponding match fields with the opposite values
+ @param dl_vlan If not -1, and pkt is None, create a pkt w/ VLAN tag
+ @param exp_pkt If not None, use this as the expected output pkt; els use pkt
+ @param action_list Additional actions to add to flow mod
+ @param check_expire Check for flow expiration message
+ """
+ of_ports = port_map.keys()
+ of_ports.sort()
+ parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
+ test_count = 0
+
+ for ing_idx in range(len(of_ports)):
+ ingress_port = of_ports[ing_idx]
+ for egr_idx in range(len(of_ports)):
+ if egr_idx == ing_idx:
+ continue
+ egress_port = of_ports[egr_idx]
+ flow_match_test_port_pair(parent, ingress_port, egress_port,
+ match=match, wildcards=wildcards,
+ dl_vlan=dl_vlan, mask=mask,
+ pkt=pkt, exp_pkt=exp_pkt,
+ apply_action_list=apply_action_list,
+ check_expire=check_expire)
+ test_count += 1
+ if (max_test > 0) and (test_count >= max_test):
+ parent.logger.info("Ran " + str(test_count) + " tests; exiting")
+ return
+
+def flow_match_test_port_pair_vlan(parent, ing_port, egr_port, wildcards=0,
+ dl_vlan=ofp.OFPVID_NONE, dl_vlan_pcp=0,
+ dl_vlan_type=ETHERTYPE_VLAN,
+ dl_vlan_int=-1, dl_vlan_pcp_int=0,
+ vid_match=ofp.OFPVID_NONE, pcp_match=0,
+ exp_vid=-1, exp_pcp=0,
+ exp_vlan_type=ETHERTYPE_VLAN,
+ match_exp=True,
+ add_tag_exp=False,
+ exp_msg=ofp.OFPT_FLOW_REMOVED,
+ exp_msg_type=0, exp_msg_code=0,
+ pkt=None, exp_pkt=None,
+ action_list=None, check_expire=False):
+ """
+ Flow match test for various vlan matching patterns on single TCP packet
+
+ Run test with packet through switch from ing_port to egr_port
+ See flow_match_test_vlan for parameter descriptions
+ """
+ parent.logger.info("Pkt match test: " + str(ing_port) + " to " + str(egr_port))
+ parent.logger.debug(" WC: " + hex(wildcards) + " vlan: " + str(dl_vlan) +
+ " expire: " + str(check_expire))
+ if pkt is None:
+ if dl_vlan >= 0 and dl_vlan != ofp.OFPVID_NONE:
+ if dl_vlan_int >= 0 and dl_vlan_int != ofp.OFPVID_NONE:
+ pkt = simple_tcp_packet(
+ vlan_tags=[{'type': dl_vlan_type, 'vid': dl_vlan, 'pcp': dl_vlan_pcp},
+ {'vid': dl_vlan_int, 'pcp': dl_vlan_pcp_int}])
+ else:
+ pkt = simple_tcp_packet(
+ vlan_tags=[{'type': dl_vlan_type, 'vid': dl_vlan, 'pcp': dl_vlan_pcp}])
+ else:
+ pkt = simple_tcp_packet()
+
+ if exp_pkt is None:
+ if exp_vid >= 0 and exp_vid != ofp.OFPVID_NONE:
+ if add_tag_exp:
+ if dl_vlan >= 0 and dl_vlan != ofp.OFPVID_NONE:
+ if dl_vlan_int >= 0 and dl_vlan_int != ofp.OFPVID_NONE:
+ exp_pkt = simple_tcp_packet(
+ vlan_tags=[{'type': exp_vlan_type, 'vid': exp_vid, 'pcp': exp_pcp},
+ {'type': dl_vlan_type, 'vid': dl_vlan, 'pcp': dl_vlan_pcp},
+ {'vid': dl_vlan_int, 'pcp': dl_vlan_pcp_int}])
+ else:
+ exp_pkt = simple_tcp_packet(
+ vlan_tags=[{'type': exp_vlan_type, 'vid': exp_vid, 'pcp': exp_pcp},
+ {'type': dl_vlan_type, 'vid': dl_vlan, 'pcp': dl_vlan_pcp}])
+ else:
+ exp_pkt = simple_tcp_packet(
+ vlan_tags=[{'type': exp_vlan_type, 'vid': exp_vid, 'pcp': exp_pcp}])
+ else:
+ if dl_vlan_int >= 0:
+ exp_pkt = simple_tcp_packet(
+ vlan_tags=[{'type': exp_vlan_type, 'vid': exp_vid, 'pcp': exp_pcp},
+ {'vid': dl_vlan_int, 'pcp': dl_vlan_pcp_int}])
+
+ else:
+ exp_pkt = simple_tcp_packet(
+ vlan_tags=[{'type': exp_vlan_type, 'vid': exp_vid, 'pcp': exp_pcp}])
+ else:
+ #subtract action
+ if dl_vlan_int >= 0:
+ exp_pkt = simple_tcp_packet(
+ vlan_tags=[{'vid': dl_vlan_int, 'pcp': dl_vlan_pcp_int}])
+ else:
+ exp_pkt = simple_tcp_packet()
+
+ match = parse.packet_to_flow_match(pkt)
+ parent.assertTrue(match is not None, "Flow match from pkt failed")
+
+ match.dl_vlan = vid_match
+ match.dl_vlan_pcp = pcp_match
+ match.wildcards = wildcards
+
+ request = flow_msg_create(parent, pkt, ing_port=ing_port,
+ wildcards=wildcards,
+ match=match,
+ egr_port=egr_port,
+ action_list=action_list)
+
+ flow_msg_install(parent, request)
+
+ parent.logger.debug("Send packet: " + str(ing_port) + " to " + str(egr_port))
+ parent.logger.debug("Sent:" + str(pkt).encode('hex'))
+ parent.dataplane.send(ing_port, str(pkt))
+
+ if match_exp:
+ receive_pkt_verify(parent, egr_port, exp_pkt)
+ if check_expire:
+ #@todo Not all HW supports both pkt and byte counters
+ flow_removed_verify(parent, request, pkt_count=1, byte_count=len(pkt))
+ else:
+ if exp_msg is ofp.OFPT_FLOW_REMOVED:
+ if check_expire:
+ flow_removed_verify(parent, request, pkt_count=0, byte_count=0)
+ elif exp_msg is ofp.OFPT_ERROR:
+ error_verify(parent, exp_msg_type, exp_msg_code)
+ else:
+ parent.assertTrue(0, "Rcv: Unexpected Message: " + str(exp_msg))
+
+ (_, rcv_pkt, _) = parent.dataplane.poll(timeout=1)
+ parent.assertFalse(rcv_pkt is not None, "Packet on dataplane")
+
+def flow_match_test_vlan(parent, port_map, wildcards=0,
+ dl_vlan=ofp.OFPVID_NONE, dl_vlan_pcp=0, dl_vlan_type=ETHERTYPE_VLAN,
+ dl_vlan_int=-1, dl_vlan_pcp_int=0,
+ vid_match=ofp.OFPVID_NONE, pcp_match=0,
+ exp_vid=-1, exp_pcp=0,
+ exp_vlan_type=ETHERTYPE_VLAN,
+ match_exp=True,
+ add_tag_exp=False,
+ exp_msg=ofp.OFPT_FLOW_REMOVED,
+ exp_msg_type=0, exp_msg_code=0,
+ pkt=None, exp_pkt=None,
+ action_list=None,
+ check_expire=False,
+ max_test=0):
+ """
+ Run flow_match_test_port_pair on all port pairs
+
+ @param max_test If > 0 no more than this number of tests are executed.
+ @param parent Must implement controller, dataplane, assertTrue, assertEqual
+ and logger
+ @param wildcards For flow match entry
+ @param dl_vlan If not -1, and pkt is not None, create a pkt w/ VLAN tag
+ @param dl_vlan_pcp VLAN PCP associated with dl_vlan
+ @param dl_vlan_type VLAN ether type associated with dl_vlan
+ @param dl_vlan_int If not -1, create pkt w/ Inner Vlan tag
+ @param dl_vlan_pcp_int VLAN PCP associated with dl_vlan_2nd
+ @param vid_match Matching value for VLAN VID field
+ @param pcp_match Matching value for VLAN PCP field
+ @param exp_vid Expected VLAN VID value. If -1, no VLAN expected
+ @param exp_vlan_type Expected VLAN ether type
+ @param exp_pcp Expected VLAN PCP value
+ @param match_exp Set whether packet is expected to receive
+ @param add_tag_exp If True, expected_packet has an additional vlan tag,
+ If not, expected_packet's vlan tag is replaced as specified
+ @param exp_msg Expected message
+ @param exp_msg_type Expected message type associated with the message
+ @param exp_msg_code Expected message code associated with the msg_type
+ @param pkt If not None, use this packet for ingress
+ @param exp_pkt If not None, use this as the expected output pkt
+ @param action_list Additional actions to add to flow mod
+ @param check_expire Check for flow expiration message
+ """
+ of_ports = port_map.keys()
+ of_ports.sort()
+ parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
+ test_count = 0
+
+ for ing_idx in range(len(of_ports)):
+ ingress_port = of_ports[ing_idx]
+ for egr_idx in range(len(of_ports)):
+ if egr_idx == ing_idx:
+ continue
+ egress_port = of_ports[egr_idx]
+ flow_match_test_port_pair_vlan(parent, ingress_port, egress_port,
+ wildcards=wildcards,
+ dl_vlan=dl_vlan,
+ dl_vlan_pcp=dl_vlan_pcp,
+ dl_vlan_type=dl_vlan_type,
+ dl_vlan_int=dl_vlan_int,
+ dl_vlan_pcp_int=dl_vlan_pcp_int,
+ vid_match=vid_match,
+ pcp_match=pcp_match,
+ exp_vid=exp_vid,
+ exp_pcp=exp_pcp,
+ exp_vlan_type=exp_vlan_type,
+ exp_msg=exp_msg,
+ exp_msg_type=exp_msg_type,
+ exp_msg_code=exp_msg_code,
+ match_exp=match_exp,
+ add_tag_exp=add_tag_exp,
+ pkt=pkt, exp_pkt=exp_pkt,
+ action_list=action_list,
+ check_expire=check_expire)
+ test_count += 1
+ if (max_test > 0) and (test_count >= max_test):
+ parent.logger.info("Ran " + str(test_count) + " tests; exiting")
+ return
+
+def test_param_get(config, key, default=None):
+ """
+ Return value passed via test-params if present
+
+ @param config The configuration structure for OFTest
+ @param key The lookup key
+ @param default Default value to use if not found
+
+ If the pair 'key=val' appeared in the string passed to --test-params
+ on the command line, return val (as interpreted by exec). Otherwise
+ return default value.
+ """
+ try:
+ exec config["test_params"]
+ except:
+ return default
+
+ s = "val = " + str(key)
+ try:
+ val = None
+ exec s
+ return val
+ except:
+ return default
+
+def action_generate(parent, field_to_mod, mod_field_vals):
+ """
+ Create an action to modify the field indicated in field_to_mod
+
+ @param parent Must implement, assertTrue
+ @param field_to_mod The field to modify as a string name
+ @param mod_field_vals Hash of values to use for modified values
+ """
+
+ act = None
+
+ if field_to_mod in ['pktlen']:
+ return None
+
+ if field_to_mod == 'dl_dst':
+ act = action.action_set_dl_dst()
+ act.dl_addr = parse.parse_mac(mod_field_vals['dl_dst'])
+ elif field_to_mod == 'dl_src':
+ act = action.action_set_dl_src()
+ act.dl_addr = parse.parse_mac(mod_field_vals['dl_src'])
+ elif field_to_mod == 'vlan_tags':
+ if len(mod_field_vals['vlan_tags']):
+ act = action.action_pop_vlan()
+ else:
+ pass
+# elif field_to_mod == 'dl_vlan_enable':
+# if not mod_field_vals['dl_vlan_enable']: # Strip VLAN tag
+# act = action.action_pop_vlan()
+# # Add VLAN tag is handled by dl_vlan field
+# # Will return None in this case
+# elif field_to_mod == 'dl_vlan':
+# act = action.action_set_vlan_vid()
+# act.vlan_vid = mod_field_vals['dl_vlan']
+# elif field_to_mod == 'dl_vlan_pcp':
+# act = action.action_set_vlan_pcp()
+# act.vlan_pcp = mod_field_vals['dl_vlan_pcp']
+ elif field_to_mod == 'ip_src':
+ act = action.action_set_nw_src()
+ act.nw_addr = parse.parse_ip(mod_field_vals['ip_src'])
+ elif field_to_mod == 'ip_dst':
+ act = action.action_set_nw_dst()
+ act.nw_addr = parse.parse_ip(mod_field_vals['ip_dst'])
+ elif field_to_mod == 'ip_tos':
+ act = action.action_set_nw_tos()
+ act.nw_tos = mod_field_vals['ip_tos']
+ elif field_to_mod == 'tcp_sport':
+ act = action.action_set_tp_src()
+ act.tp_port = mod_field_vals['tcp_sport']
+ elif field_to_mod == 'tcp_dport':
+ act = action.action_set_tp_dst()
+ act.tp_port = mod_field_vals['tcp_dport']
+ else:
+ parent.assertTrue(0, "Unknown field to modify: " + str(field_to_mod))
+
+ return act
+
+def pkt_action_setup(parent, start_field_vals={}, mod_field_vals={},
+ mod_fields={}, check_test_params=False):
+ """
+ Set up the ingress and expected packet and action list for a test
+
+ @param parent Must implement, assertTrue, config hash and logger
+ @param start_field_values Field values to use for ingress packet (optional)
+ @param mod_field_values Field values to use for modified packet (optional)
+ @param mod_fields The list of fields to be modified by the switch in the test.
+ @params check_test_params If True, will check the parameters vid, add_vlan
+ and strip_vlan from the command line.
+
+ Returns a triple: pkt-to-send, expected-pkt, action-list
+ """
+
+ new_actions = []
+
+
+ base_pkt_params = {}
+ base_pkt_params['dl_dst'] = '00:DE:F0:12:34:56'
+ base_pkt_params['dl_src'] = '00:23:45:67:89:AB'
+# base_pkt_params['dl_vlan_enable'] = False
+# base_pkt_params['dl_vlan'] = 2
+# base_pkt_params['dl_vlan_pcp'] = 0
+ base_pkt_params['ip_src'] = '192.168.0.1'
+ base_pkt_params['ip_dst'] = '192.168.0.2'
+ base_pkt_params['ip_tos'] = 0
+ base_pkt_params['tcp_sport'] = 1234
+ base_pkt_params['tcp_dport'] = 80
+ for keyname in start_field_vals.keys():
+ base_pkt_params[keyname] = start_field_vals[keyname]
+
+ mod_pkt_params = {}
+ mod_pkt_params['dl_dst'] = '00:21:0F:ED:CB:A9'
+ mod_pkt_params['dl_src'] = '00:ED:CB:A9:87:65'
+# mod_pkt_params['dl_vlan_enable'] = False
+# mod_pkt_params['dl_vlan'] = 3
+# mod_pkt_params['dl_vlan_pcp'] = 7
+ mod_pkt_params['ip_src'] = '10.20.30.40'
+ mod_pkt_params['ip_dst'] = '50.60.70.80'
+ mod_pkt_params['ip_tos'] = 0xf0
+ mod_pkt_params['tcp_sport'] = 4321
+ mod_pkt_params['tcp_dport'] = 8765
+ for keyname in mod_field_vals.keys():
+ mod_pkt_params[keyname] = mod_field_vals[keyname]
+
+ # Check for test param modifications
+ strip = False
+ if check_test_params:
+ add_vlan = test_param_get(parent.config, 'add_vlan')
+ strip_vlan = test_param_get(parent.config, 'strip_vlan')
+ vid = test_param_get(parent.config, 'vid')
+
+ if add_vlan and strip_vlan:
+ parent.assertTrue(0, "Add and strip VLAN both specified")
+
+ if vid:
+ base_pkt_params['dl_vlan_enable'] = True
+ base_pkt_params['dl_vlan'] = vid
+ if 'dl_vlan' in mod_fields:
+ mod_pkt_params['dl_vlan'] = vid + 1
+
+ if add_vlan:
+ base_pkt_params['dl_vlan_enable'] = False
+ mod_pkt_params['dl_vlan_enable'] = True
+ mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] + 4
+ mod_fields.append('pktlen')
+ mod_fields.append('dl_vlan_enable')
+ if 'dl_vlan' not in mod_fields:
+ mod_fields.append('dl_vlan')
+ elif strip_vlan:
+ base_pkt_params['dl_vlan_enable'] = True
+ mod_pkt_params['dl_vlan_enable'] = False
+ mod_pkt_params['pktlen'] = base_pkt_params['pktlen'] - 4
+ mod_fields.append('dl_vlan_enable')
+ mod_fields.append('pktlen')
+
+ # Build the ingress packet
+ ingress_pkt = simple_tcp_packet(**base_pkt_params)
+
+ # Build the expected packet, modifying the indicated fields
+ for item in mod_fields:
+ base_pkt_params[item] = mod_pkt_params[item]
+ act = action_generate(parent, item, mod_pkt_params)
+ if act:
+ new_actions.append(act)
+
+ expected_pkt = simple_tcp_packet(**base_pkt_params)
+
+ return (ingress_pkt, expected_pkt, new_actions)
+
+def wildcard_all_set(match):
+ match.wildcards = ofp.OFPFW_ALL
+ match.nw_dst_mask = 0xffffffff
+ match.nw_src_mask = 0xffffffff
+ match.dl_dst_mask = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
+ match.dl_src_mask = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
+ match.metadata_mask = 0xffffffffffffffff
+
+def skip_message_emit(parent, s):
+ """
+ Print out a 'skipped' message to stderr
+
+ @param s The string to print out to the log file
+ @param parent Must implement config and logger objects
+ """
+ global skipped_test_count
+
+ skipped_test_count += 1
+ parent.logger.info("Skipping: " + s)
+ if parent.config["dbg_level"] < logging.WARNING:
+ sys.stderr.write("(skipped) ")
+ else:
+ sys.stderr.write("(S)")
+
+def do_echo_request_reply_test(test,controller):
+ request = message.echo_request()
+ response, _ = controller.transact(request)
+ test.assertEqual(response.header.type, ofp.OFPT_ECHO_REPLY,
+ 'response is not echo_reply')
+ test.assertEqual(request.header.xid, response.header.xid,
+ 'response xid != request xid')
+ test.assertEqual(len(response.data), 0, 'response data non-empty')
+
+def match_all_generate():
+ match = ofp.ofp_match()
+ return match
+
+def simple_tcp_packet_w_mpls(
+ dl_dst='00:01:02:03:04:05',
+ dl_src='00:06:07:08:09:0a',
+ mpls_type=0x8847,
+ mpls_label=-1,
+ mpls_tc=0,
+ mpls_ttl=64,
+ mpls_label_int=-1,
+ mpls_tc_int=0,
+ mpls_ttl_int=32,
+ mpls_label_ext=-1,
+ mpls_tc_ext=0,
+ mpls_ttl_ext=128,
+ ip_src='192.168.0.1',
+ ip_dst='192.168.0.2',
+ ip_tos=0,
+ ip_ttl=192,
+ tcp_sport=1234,
+ tcp_dport=80
+ ):
+ """
+ Return a simple dataplane TCP packet w/wo MPLS tags
+
+ Supports a few parameters:
+ @param len Length of packet in bytes w/o CRC
+ @param dl_dst Destinatino MAC
+ @param dl_src Source MAC
+ @param mpls_type MPLS type as ether type
+ @param mpls_label MPLS LABEL if not -1
+ @param mpls_tc MPLS TC
+ @param mpls_ttl MPLS TTL
+ @param mpls_label_int Inner MPLS LABEL if not -1. The shim will be added
+ inside of mpls_label shim.
+ @param mpls_tc_int Inner MPLS TC
+ @param mpls_ttl_int Inner MPLS TTL
+ @param mpls_label_ext External MPLS LABEL if not -1. The shim will be
+ added outside of mpls_label shim
+ @param mpls_tc_ext External MPLS TC
+ @param mpls_ttl_ext External MPLS TTL
+ @param ip_src IP source
+ @param ip_dst IP destination
+ @param ip_tos IP ToS
+ @param tcp_dport TCP destination port
+ @param ip_sport TCP source port
+
+ Generates a simple MPLS/IP/TCP request. Users
+ shouldn't assume anything about this packet other than that
+ it is a valid ethernet/IP/TCP frame.
+ """
+
+ mpls_tags = []
+
+ if mpls_label_ext >= 0:
+ mpls_tags.append({'type': mpls_type, 'label': mpls_label_ext, 'tc': mpls_tc_ext, 'ttl': mpls_ttl_ext})
+
+ if mpls_label >= 0:
+ mpls_tags.append({'type': mpls_type, 'label': mpls_label, 'tc': mpls_tc, 'ttl': mpls_ttl})
+
+ if mpls_label_int >= 0:
+ mpls_tags.append({'type': mpls_type, 'label': mpls_label_int, 'tc': mpls_tc_int, 'ttl': mpls_ttl_int})
+
+ pkt = simple_tcp_packet(dl_dst=dl_dst,
+ dl_src=dl_src,
+ mpls_tags=mpls_tags,
+ ip_src=ip_src,
+ ip_dst=ip_dst,
+ ip_tos=ip_tos,
+ ip_ttl=ip_ttl,
+ tcp_sport=tcp_sport,
+ tcp_dport=tcp_dport)
+ return pkt
+
+def flow_match_test_port_pair_mpls(parent, ing_port, egr_port, wildcards=0,
+ mpls_type=0x8847,
+ mpls_label=-1, mpls_tc=0,mpls_ttl=64,
+ mpls_label_int=-1, mpls_tc_int=0,
+ mpls_ttl_int=32,
+ ip_ttl=192,
+ exp_mpls_type=0x8847,
+ exp_mpls_label=-1, exp_mpls_tc=0,
+ exp_mpls_ttl=64,
+ exp_mpls_ttl_int=32,
+ exp_ip_ttl=192,
+ label_match=0, tc_match=0,
+ dl_type_match=ETHERTYPE_MPLS,
+ match_exp=True,
+ add_tag_exp=False,
+ exp_msg=ofp.OFPT_FLOW_REMOVED,
+ exp_msg_type=0, exp_msg_code=0,
+ pkt=None,
+ exp_pkt=None, action_list=None,
+ check_expire=False):
+ """
+ Flow match test on single packet w/ MPLS tags
+
+ Run test with packet through switch from ing_port to egr_port
+ See flow_match_test for parameter descriptions
+ """
+ parent.logger.info("Pkt match test: " + str(ing_port) + " to " + str(egr_port))
+ parent.logger.debug(" WC: " + hex(wildcards) + " MPLS: " +
+ str(mpls_label) + " expire: " + str(check_expire))
+
+ if pkt is None:
+
+ pkt = simple_tcp_packet_w_mpls(mpls_type=mpls_type,
+ mpls_label=mpls_label,
+ mpls_tc=mpls_tc,
+ mpls_ttl=mpls_ttl,
+ mpls_label_int=mpls_label_int,
+ mpls_tc_int=mpls_tc_int,
+ mpls_ttl_int=mpls_ttl_int,
+ ip_ttl=ip_ttl)
+
+ if exp_pkt is None:
+ if add_tag_exp:
+ exp_pkt = simple_tcp_packet_w_mpls(
+ mpls_type=exp_mpls_type,
+ mpls_label_ext=exp_mpls_label,
+ mpls_tc_ext=exp_mpls_tc,
+ mpls_ttl_ext=exp_mpls_ttl,
+ mpls_label=mpls_label,
+ mpls_tc=mpls_tc,
+ mpls_ttl=mpls_ttl,
+ mpls_label_int=mpls_label_int,
+ mpls_tc_int=mpls_tc_int,
+ mpls_ttl_int=exp_mpls_ttl_int,
+ ip_ttl=exp_ip_ttl)
+ else:
+ if (exp_mpls_label < 0) and (mpls_label_int >= 0):
+ exp_pkt = simple_tcp_packet_w_mpls(
+ mpls_type=mpls_type,
+ mpls_label=mpls_label_int,
+ mpls_tc=mpls_tc_int,
+ mpls_ttl=exp_mpls_ttl_int,
+ ip_ttl=exp_ip_ttl)
+ else:
+ exp_pkt = simple_tcp_packet_w_mpls(
+ mpls_type=exp_mpls_type,
+ mpls_label=exp_mpls_label,
+ mpls_tc=exp_mpls_tc,
+ mpls_ttl=exp_mpls_ttl,
+ mpls_label_int=mpls_label_int,
+ mpls_tc_int=mpls_tc_int,
+ mpls_ttl_int=exp_mpls_ttl_int,
+ ip_ttl=exp_ip_ttl)
+ wildcards = (ofp.OFPFW_ALL & ~(ofp.OFPFW_DL_TYPE | ofp.OFPFW_MPLS_LABEL | ofp.OFPFW_MPLS_TC)) | wildcards
+
+ match = parse.packet_to_flow_match(pkt)
+ parent.assertTrue(match is not None, "Flow match from pkt failed")
+
+ match.mpls_label = label_match
+ match.mpls_tc = tc_match
+ match.wildcards = wildcards
+
+ match.dl_type = dl_type_match
+ match.nw_tos = 0
+ match.nw_proto = 0
+ match.nw_src = 0
+ match.nw_src_mask = 0xFFFFFFFF
+ match.nw_dst = 0
+ match.nw_dst_mask = 0xFFFFFFFF
+ match.tp_src = 0
+ match.tp_dst = 0
+
+ request = flow_msg_create(parent, pkt, ing_port=ing_port,
+ wildcards=wildcards,
+ match=match,
+ egr_port=egr_port,
+ action_list=action_list)
+
+ flow_msg_install(parent, request)
+
+ parent.logger.debug("Send packet: " + str(ing_port) + " to " + str(egr_port))
+ #parent.logger.debug(str(pkt).encode("hex"))
+ parent.dataplane.send(ing_port, str(pkt))
+
+ if match_exp:
+ receive_pkt_verify(parent, egr_port, exp_pkt)
+ if check_expire:
+ #@todo Not all HW supports both pkt and byte counters
+ flow_removed_verify(parent, request, pkt_count=1, byte_count=len(pkt))
+ else:
+ if exp_msg == ofp.OFPT_FLOW_REMOVED:
+ if check_expire:
+ flow_removed_verify(parent, request, pkt_count=0, byte_count=0)
+ elif exp_msg == ofp.OFPT_ERROR:
+ error_verify(parent, exp_msg_type, exp_msg_code)
+ else:
+ parent.assertTrue(0, "Rcv: Unexpected Message: " + str(exp_msg))
+ (_, rcv_pkt, _) = parent.dataplane.poll(timeout=1)
+ parent.assertFalse(rcv_pkt is not None, "Packet on dataplane")
+
+def flow_match_test_mpls(parent, port_map, wildcards=0,
+ mpls_type=0x8847,
+ mpls_label=-1, mpls_tc=0, mpls_ttl=64,
+ mpls_label_int=-1, mpls_tc_int=0, mpls_ttl_int=32,
+ ip_ttl = 192,
+ label_match=0, tc_match=0,
+ dl_type_match=ETHERTYPE_MPLS,
+ exp_mpls_type=0x8847,
+ exp_mpls_label=-1, exp_mpls_tc=0, exp_mpls_ttl=64,
+ exp_mpls_ttl_int=32,
+ exp_ip_ttl=192,
+ match_exp=True,
+ add_tag_exp=False,
+ exp_msg=ofp.OFPT_FLOW_REMOVED,
+ exp_msg_type=0, exp_msg_code=0,
+ pkt=None,
+ exp_pkt=None, action_list=None, check_expire=False,
+ max_test=0):
+ """
+ Run flow_match_test_port_pair on all port pairs
+
+ @param max_test If > 0 no more than this number of tests are executed.
+ @param parent Must implement controller, dataplane, assertTrue, assertEqual
+ and logger
+ @param wildcards For flow match entry
+ @param mpls_type MPLS type
+ @param mpls_label If not -1 create a pkt w/ MPLS tag
+ @param mpls_tc MPLS TC associated with MPLS label
+ @param mpls_ttl MPLS TTL associated with MPLS label
+ @param mpls_label_int If not -1 create a pkt w/ Inner MPLS tag
+ @param mpls_tc_int MPLS TC associated with Inner MPLS label
+ @param mpls_ttl_int MPLS TTL associated with Inner MPLS label
+ @param ip_ttl IP TTL
+ @param label_match Matching value for MPLS LABEL field
+ @param tc_match Matching value for MPLS TC field
+ @param exp_mpls_label Expected MPLS LABEL value. If -1, no MPLS expected
+ @param exp_mpls_tc Expected MPLS TC value
+ @param exp_mpls_ttl Expected MPLS TTL value
+ @param exp_mpls_ttl_int Expected Inner MPLS TTL value
+ @param ip_ttl Expected IP TTL
+ @param match_exp Set whether packet is expected to receive
+ @param add_tag_exp If True, expected_packet has an additional MPLS shim,
+ If not expected_packet's MPLS shim is replaced as specified
+ @param exp_msg Expected message
+ @param exp_msg_type Expected message type associated with the message
+ @param exp_msg_code Expected message code associated with the msg_type
+ @param pkt If not None, use this packet for ingress
+ @param exp_pkt If not None, use this as the expected output pkt; els use pkt
+ @param action_list Additional actions to add to flow mod
+ @param check_expire Check for flow expiration message
+ """
+ of_ports = port_map.keys()
+ of_ports.sort()
+ parent.assertTrue(len(of_ports) > 1, "Not enough ports for test")
+ test_count = 0
+
+ for ing_idx in range(len(of_ports)):
+ ingress_port = of_ports[ing_idx]
+ for egr_idx in range(len(of_ports)):
+ if egr_idx == ing_idx:
+ continue
+ egress_port = of_ports[egr_idx]
+ flow_match_test_port_pair_mpls(parent, ingress_port, egress_port,
+ wildcards=wildcards,
+ mpls_type=mpls_type,
+ mpls_label=mpls_label,
+ mpls_tc=mpls_tc,
+ mpls_ttl=mpls_ttl,
+ mpls_label_int=mpls_label_int,
+ mpls_tc_int=mpls_tc_int,
+ mpls_ttl_int=mpls_ttl_int,
+ ip_ttl=ip_ttl,
+ label_match=label_match,
+ tc_match=tc_match,
+ dl_type_match=dl_type_match,
+ exp_mpls_type=exp_mpls_type,
+ exp_mpls_label=exp_mpls_label,
+ exp_mpls_tc=exp_mpls_tc,
+ exp_mpls_ttl=exp_mpls_ttl,
+ exp_mpls_ttl_int=exp_mpls_ttl_int,
+ exp_ip_ttl=exp_ip_ttl,
+ match_exp=match_exp,
+ exp_msg=exp_msg,
+ exp_msg_type=exp_msg_type,
+ exp_msg_code=exp_msg_code,
+ add_tag_exp=add_tag_exp,
+ pkt=pkt, exp_pkt=exp_pkt,
+ action_list=action_list,
+ check_expire=check_expire)
+ test_count += 1
+ if (max_test > 0) and (test_count >= max_test):
+ parent.logger.info("Ran " + str(test_count) + " tests; exiting")
+ return
+
+def flow_stats_get(parent, match_fields = None):
+ """ Get the flow_stats from the switch
+ Test the response to make sure it's really a flow_stats object
+ """
+ request = message.flow_stats_request()
+ request.out_port = ofp.OFPP_ANY
+ request.out_group = ofp.OFPG_ANY
+ request.table_id = 0xff
+ if match_fields != None:
+ request.match_fields = match_fields
+ response, _ = parent.controller.transact(request, timeout=2)
+ parent.assertTrue(response is not None, "Did not get response")
+ parent.assertTrue(isinstance(response,message.flow_stats_reply),
+ "Expected a flow_stats_reply, but didn't get it")
+ return response