copy in of11 package
These modules were copied from the oft-1.1 branch.
diff --git a/src/python/of11/parse.py b/src/python/of11/parse.py
new file mode 100644
index 0000000..dfe24c6
--- /dev/null
+++ b/src/python/of11/parse.py
@@ -0,0 +1,231 @@
+"""
+OpenFlow message parsing functions
+"""
+
+import logging
+import message
+import cstruct as ofp
+
+"""
+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_AGGREGATE : message.aggregate_stats_reply,
+ ofp.OFPST_FLOW : message.flow_stats_reply,
+ ofp.OFPST_TABLE : message.table_stats_reply,
+ ofp.OFPST_PORT : message.port_stats_reply,
+ ofp.OFPST_QUEUE : message.queue_stats_reply
+}
+
+stats_request_to_class_map = {
+ ofp.OFPST_DESC : message.desc_stats_request,
+ ofp.OFPST_AGGREGATE : message.aggregate_stats_request,
+ ofp.OFPST_FLOW : message.flow_stats_request,
+ ofp.OFPST_TABLE : message.table_stats_request,
+ ofp.OFPST_PORT : message.port_stats_request,
+ ofp.OFPST_QUEUE : message.queue_stats_request
+}
+
+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_FLOW_MOD_FAILED : message.flow_mod_failed_error_msg,
+ ofp.OFPET_PORT_MOD_FAILED : message.port_mod_failed_error_msg,
+ ofp.OFPET_QUEUE_OP_FAILED : message.queue_op_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_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 ICMP and ARP fields
+ """
+
+ return packet.parse()