move and check in OpenFlow protocol modules

Move all the protocol code out of the oftest package and into a of10 package to
prepare for supporting more OpenFlow versions.

The generated code is now checked-in to make it simpler to use OFTest.

Backwards compatibility with out of tree tests is maintained by aliasing the
old module names. The basic test module has been changed to use the new API.
diff --git a/src/python/oftest/.gitignore b/src/python/oftest/.gitignore
deleted file mode 100644
index 097bad4..0000000
--- a/src/python/oftest/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-action.py
-class_maps.py
-cstruct.py
-error.py
-message.py
diff --git a/src/python/oftest/__init__.py b/src/python/oftest/__init__.py
index 3974e08..65a5648 100644
--- a/src/python/oftest/__init__.py
+++ b/src/python/oftest/__init__.py
@@ -1,4 +1,5 @@
 '''Docstring to silence pylint; ignores --ignore option for __init__.py'''
+import sys
 
 # Global config dictionary
 # Populated by oft.
@@ -7,3 +8,9 @@
 # Global DataPlane instance used by all tests.
 # Populated by oft.
 dataplane_instance = None
+
+# Alias of10 modules into oftest namespace for backwards compatbility
+import of10
+from of10 import *
+for modname in of10.__all__:
+    sys.modules["oftest." + modname] = sys.modules["of10." + modname]
diff --git a/src/python/oftest/action_list.py b/src/python/oftest/action_list.py
deleted file mode 100644
index fbbddea..0000000
--- a/src/python/oftest/action_list.py
+++ /dev/null
@@ -1,189 +0,0 @@
-"""
-OpenFlow actions list class
-"""
-
-from action import *
-from cstruct import ofp_header
-import copy
-
-# # Map OFP action identifiers to the actual structures used on the wire
-# action_object_map = {
-#     OFPAT_OUTPUT                        : ofp_action_output,
-#     OFPAT_SET_VLAN_VID                  : ofp_action_vlan_vid,
-#     OFPAT_SET_VLAN_PCP                  : ofp_action_vlan_pcp,
-#     OFPAT_STRIP_VLAN                    : ofp_action_header,
-#     OFPAT_SET_DL_SRC                    : ofp_action_dl_addr,
-#     OFPAT_SET_DL_DST                    : ofp_action_dl_addr,
-#     OFPAT_SET_NW_SRC                    : ofp_action_nw_addr,
-#     OFPAT_SET_NW_DST                    : ofp_action_nw_addr,
-#     OFPAT_SET_NW_TOS                    : ofp_action_nw_tos,
-#     OFPAT_SET_TP_SRC                    : ofp_action_tp_port,
-#     OFPAT_SET_TP_DST                    : ofp_action_tp_port,
-#     OFPAT_ENQUEUE                       : ofp_action_enqueue
-# }
-
-action_object_map = {
-    OFPAT_OUTPUT                        : action_output,
-    OFPAT_SET_VLAN_VID                  : action_set_vlan_vid,
-    OFPAT_SET_VLAN_PCP                  : action_set_vlan_pcp,
-    OFPAT_STRIP_VLAN                    : action_strip_vlan,
-    OFPAT_SET_DL_SRC                    : action_set_dl_src,
-    OFPAT_SET_DL_DST                    : action_set_dl_dst,
-    OFPAT_SET_NW_SRC                    : action_set_nw_src,
-    OFPAT_SET_NW_DST                    : action_set_nw_dst,
-    OFPAT_SET_NW_TOS                    : action_set_nw_tos,
-    OFPAT_SET_TP_SRC                    : action_set_tp_src,
-    OFPAT_SET_TP_DST                    : action_set_tp_dst,
-    OFPAT_ENQUEUE                       : action_enqueue,
-    OFPAT_VENDOR                        : action_vendor
-}
-
-class action_list(object):
-    """
-    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, actions=None):
-        if actions == None:
-            actions = []
-        self.actions = actions
-
-    def pack(self):
-        """
-        Pack a list of actions
-
-        Returns the packed string
-        """
-
-        packed = ""
-        for act in self.actions:
-            packed += act.pack()
-        return packed
-
-    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
-
-    def add(self, action):
-        """
-        Add an action to an action list
-
-        @param action The action to add
-
-        """
-        if not isinstance(action, action_class_list):
-            raise ValueError("%s is not an action" % type(action))
-        self.actions.append(copy.deepcopy(action))
-        return True # for backwards compatibility
-
-    def remove_type(self, type):
-        """
-        Remove the first action on the list of the given type
-
-        @param type The type of action to search
-
-        @return The object removed, if any; otherwise None
-
-        """
-        for index in xrange(len(self.actions)):
-            if self.actions[index].type == type:
-                return self.actions.pop(index)
-        return None
-
-    def find_type(self, type):
-        """
-        Find the first action on the list of the given type
-
-        @param type The type of action to search
-
-        @return The object with the matching type if any; otherwise None
-
-        """
-        for index in xrange(len(self.actions)):
-            if self.actions[index].type == type:
-                return self.actions[index]
-        return None
-
-    def extend(self, other):
-        """
-        Add the actions in other to this list
-
-        @param other An object of type action_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.actions:
-            self.add(act)
-        return True # for backwards compatibility
-        
-    def __len__(self):
-        length = 0
-        for act in self.actions:
-            length += act.__len__()
-        return length
-
-    def __eq__(self, other):
-        if type(self) != type(other): return False
-        if self.actions != other.actions: return False
-        return True
-
-    def __ne__(self, other): return not self.__eq__(other)
-        
-    def show(self, prefix=''):
-        outstr = prefix + "Action List with " + str(len(self.actions)) + \
-            " actions\n"
-        count = 0
-        for obj in self.actions:
-            count += 1
-            outstr += prefix + "  Action " + str(count) + ": \n"
-            outstr += obj.show(prefix + '    ')
-        return outstr
diff --git a/src/python/oftest/base_tests.py b/src/python/oftest/base_tests.py
index f91ae60..056f6e9 100644
--- a/src/python/oftest/base_tests.py
+++ b/src/python/oftest/base_tests.py
@@ -11,11 +11,8 @@
 import oftest
 from oftest import config
 import oftest.controller as controller
-import oftest.cstruct as ofp
-import oftest.message as message
 import oftest.dataplane as dataplane
-import oftest.action as action
-
+import of10.message as message
 from oftest.testutils import *
 
 class SimpleProtocol(unittest.TestCase):
diff --git a/src/python/oftest/controller.py b/src/python/oftest/controller.py
index fa346c3..47049a0 100644
--- a/src/python/oftest/controller.py
+++ b/src/python/oftest/controller.py
@@ -32,8 +32,8 @@
 from threading import Thread
 from threading import Lock
 from threading import Condition
-from message import *
-from parse import *
+from of10.message import *
+from of10.parse import *
 from ofutils import *
 # For some reason, it seems select to be last (or later).
 # Otherwise get an attribute error when calling select.select
diff --git a/src/python/oftest/parse.py b/src/python/oftest/parse.py
deleted file mode 100644
index a3421a1..0000000
--- a/src/python/oftest/parse.py
+++ /dev/null
@@ -1,343 +0,0 @@
-"""
-OpenFlow message parsing functions
-"""
-
-import sys
-import logging
-from message import *
-from error import *
-from action import *
-from action_list import action_list
-from cstruct import *
-try:
-    import scapy.all as scapy
-except:
-    try:
-        import scapy as scapy
-    except:
-        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 = [
-    OFPT_STATS_REQUEST,
-    OFPT_STATS_REPLY,
-    OFPT_ERROR
-]
-
-# Maps from sub-types to classes
-stats_reply_to_class_map = {
-    OFPST_DESC                      : desc_stats_reply,
-    OFPST_AGGREGATE                 : aggregate_stats_reply,
-    OFPST_FLOW                      : flow_stats_reply,
-    OFPST_TABLE                     : table_stats_reply,
-    OFPST_PORT                      : port_stats_reply,
-    OFPST_QUEUE                     : queue_stats_reply
-}
-
-stats_request_to_class_map = {
-    OFPST_DESC                      : desc_stats_request,
-    OFPST_AGGREGATE                 : aggregate_stats_request,
-    OFPST_FLOW                      : flow_stats_request,
-    OFPST_TABLE                     : table_stats_request,
-    OFPST_PORT                      : port_stats_request,
-    OFPST_QUEUE                     : queue_stats_request
-}
-
-error_to_class_map = {
-    OFPET_HELLO_FAILED              : hello_failed_error_msg,
-    OFPET_BAD_REQUEST               : bad_request_error_msg,
-    OFPET_BAD_ACTION                : bad_action_error_msg,
-    OFPET_FLOW_MOD_FAILED           : flow_mod_failed_error_msg,
-    OFPET_PORT_MOD_FAILED           : port_mod_failed_error_msg,
-    OFPET_QUEUE_OP_FAILED           : queue_op_failed_error_msg
-}
-
-# Map from header type value to the underlieing message class
-msg_type_to_class_map = {
-    OFPT_HELLO                      : hello,
-    OFPT_ERROR                      : error,
-    OFPT_ECHO_REQUEST               : echo_request,
-    OFPT_ECHO_REPLY                 : echo_reply,
-    OFPT_VENDOR                     : vendor,
-    OFPT_FEATURES_REQUEST           : features_request,
-    OFPT_FEATURES_REPLY             : features_reply,
-    OFPT_GET_CONFIG_REQUEST         : get_config_request,
-    OFPT_GET_CONFIG_REPLY           : get_config_reply,
-    OFPT_SET_CONFIG                 : set_config,
-    OFPT_PACKET_IN                  : packet_in,
-    OFPT_FLOW_REMOVED               : flow_removed,
-    OFPT_PORT_STATUS                : port_status,
-    OFPT_PACKET_OUT                 : packet_out,
-    OFPT_FLOW_MOD                   : flow_mod,
-    OFPT_PORT_MOD                   : port_mod,
-    OFPT_STATS_REQUEST              : stats_request,
-    OFPT_STATS_REPLY                : stats_reply,
-    OFPT_BARRIER_REQUEST            : barrier_request,
-    OFPT_BARRIER_REPLY              : barrier_reply,
-    OFPT_QUEUE_GET_CONFIG_REQUEST   : queue_get_config_request,
-    OFPT_QUEUE_GET_CONFIG_REPLY     : queue_get_config_reply
-}
-
-def _of_message_to_object(binary_string):
-    """
-    Map a binary string to the corresponding class.
-
-    Appropriately resolves subclasses
-    """
-    hdr = 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 == OFPT_STATS_REQUEST:
-        sub_hdr = ofp_stats_request()
-        sub_hdr.unpack(binary_string[OFP_HEADER_BYTES:])
-        try:
-            obj = stats_request_to_class_map[sub_hdr.type]()
-        except KeyError:
-            obj = None
-        return obj
-    elif hdr.type == OFPT_STATS_REPLY:
-        sub_hdr = ofp_stats_reply()
-        sub_hdr.unpack(binary_string[OFP_HEADER_BYTES:])
-        try:
-            obj = stats_reply_to_class_map[sub_hdr.type]()
-        except KeyError:
-            obj = None
-        return obj
-    elif hdr.type == OFPT_ERROR:
-        sub_hdr = ofp_error_msg()
-        sub_hdr.unpack(binary_string[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_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: int(val, 16), 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: int(val), ip_str.split("."))
-    val = 0
-    for a in array:
-        val <<= 8
-        val += a
-    return val
-
-def packet_type_classify(ether):
-    try:
-        dot1q = ether[scapy.Dot1Q]
-    except:
-        dot1q = None
-
-    try:
-        ip = ether[scapy.IP]
-    except:
-        ip = None
-
-    try:
-        tcp = ether[scapy.TCP]
-    except:
-        tcp = None
-
-    try:
-        udp = ether[scapy.UDP]
-    except:
-        udp = None
-
-    try:
-        icmp = ether[scapy.ICMP]
-    except:
-        icmp = None
-
-    try:
-        arp = ether[scapy.ARP]
-    except:
-        arp = None
-    return (dot1q, ip, tcp, udp, icmp, arp)
-
-def packet_to_flow_match(packet, pkt_format="L2"):
-    """
-    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
-    """
-
-    #@todo check min length of packet
-    if pkt_format.upper() != "L2":
-        parse_logger.error("Only L2 supported for packet_to_flow")
-        return None
-
-    if type(packet) == type(""):
-        ether = scapy.Ether(packet)
-    else:
-        ether = packet
-
-    # For now, assume ether IP packet and ignore wildcards
-    try:
-        (dot1q, ip, tcp, udp, icmp, arp) = packet_type_classify(ether)
-    except:
-        parse_logger.error("packet_to_flow_match: Classify error")
-        return None
-
-    match = ofp_match()
-    match.wildcards = OFPFW_ALL
-    #@todo Check if packet is other than L2 format
-    match.dl_dst = parse_mac(ether.dst)
-    match.wildcards &= ~OFPFW_DL_DST
-    match.dl_src = parse_mac(ether.src)
-    match.wildcards &= ~OFPFW_DL_SRC
-    match.dl_type = ether.type
-    match.wildcards &= ~OFPFW_DL_TYPE
-
-    if dot1q:
-        match.dl_vlan = dot1q.vlan
-        match.dl_vlan_pcp = dot1q.prio
-        match.dl_type = dot1q.type
-    else:
-        match.dl_vlan = OFP_VLAN_NONE
-        match.dl_vlan_pcp = 0
-    match.wildcards &= ~OFPFW_DL_VLAN
-    match.wildcards &= ~OFPFW_DL_VLAN_PCP
-
-    if ip:
-        match.nw_src = parse_ip(ip.src)
-        match.wildcards &= ~OFPFW_NW_SRC_MASK
-        match.nw_dst = parse_ip(ip.dst)
-        match.wildcards &= ~OFPFW_NW_DST_MASK
-        match.nw_tos = ip.tos
-        match.wildcards &= ~OFPFW_NW_TOS
-
-    if tcp:
-        match.nw_proto = 6
-        match.wildcards &= ~OFPFW_NW_PROTO
-    elif not tcp and udp:
-        tcp = udp
-        match.nw_proto = 17
-        match.wildcards &= ~OFPFW_NW_PROTO
-
-    if tcp:
-        match.tp_src = tcp.sport
-        match.wildcards &= ~OFPFW_TP_SRC
-        match.tp_dst = tcp.dport
-        match.wildcards &= ~OFPFW_TP_DST
-
-    if icmp:
-        match.nw_proto = 1
-        match.tp_src = icmp.type
-        match.tp_dst = icmp.code
-        match.wildcards &= ~OFPFW_NW_PROTO
-
-    if arp:
-        match.nw_proto = arp.op
-        match.wildcards &= ~OFPFW_NW_PROTO
-        match.nw_src = parse_ip(arp.psrc)
-        match.wildcards &= ~OFPFW_NW_SRC_MASK
-        match.nw_dst = parse_ip(arp.pdst)
-        match.wildcards &= ~OFPFW_NW_DST_MASK
-
-    return match
diff --git a/src/python/oftest/testutils.py b/src/python/oftest/testutils.py
index e8dec6e..480604d 100644
--- a/src/python/oftest/testutils.py
+++ b/src/python/oftest/testutils.py
@@ -1,6 +1,8 @@
-
 import sys
 import copy
+import logging
+import types
+import time
 
 try:
     import scapy.all as scapy
@@ -12,14 +14,11 @@
 
 from oftest import config
 import oftest.controller as controller
-import oftest.cstruct as ofp
-import oftest.message as message
 import oftest.dataplane as dataplane
-import oftest.action as action
-import oftest.parse as parse
-import logging
-import types
-import time
+import of10.cstruct as ofp
+import of10.message as message
+import of10.action as action
+import of10.parse as parse
 
 global skipped_test_count
 skipped_test_count = 0