Initial oftest skeleton with wrapper generators and pylibopenflow
diff --git a/tools/pylibopenflow/pylib/of/__init__.py b/tools/pylibopenflow/pylib/of/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/pylibopenflow/pylib/of/__init__.py
diff --git a/tools/pylibopenflow/pylib/of/msg.py b/tools/pylibopenflow/pylib/of/msg.py
new file mode 100644
index 0000000..8617f56
--- /dev/null
+++ b/tools/pylibopenflow/pylib/of/msg.py
@@ -0,0 +1,117 @@
+"""This module parses OpenFlow packets.
+
+Unfortunately, this has to be updated manually for each OpenFlow version
+and packet type.  Ugly.
+
+(C) Copyright Stanford University
+Date October 2009
+Created by ykk
+"""
+class parser:
+    """Parser for  OpenFlow packets
+    
+    (C) Copyright Stanford University
+    Date October 2009
+    Created by ykk
+    """
+    def __init__(self, messages):
+        """Initialize
+        """
+        ##Internal reference to OpenFlow messages
+        self.__messages = messages
+
+    def describe(self, packet):
+        """Parse OpenFlow packet and return string description
+        """
+        dic = self.__messages.peek_from_front("ofp_header", packet)
+        desc = self.header_describe(dic)
+        if (dic["type"][0] == self.__messages.get_value("OFPT_HELLO")):
+            pass
+        elif (dic["type"][0] == self.__messages.get_value("OFPT_SET_CONFIG")):
+            desc += "\n\t"+self.switch_config_describe(packet)
+        elif (dic["type"][0] == self.__messages.get_value("OFPT_FLOW_MOD")):
+            (fmdic, remaining) = self.__messages.unpack_from_front("ofp_flow_mod", packet)
+            desc += self.flow_mod_describe(fmdic, "\n\t")
+            desc += "\n\twith remaining "+str(len(remaining))+" bytes"
+        else:
+            desc += "\n\tUnparsed..."
+        return desc
+
+    def flow_mod_describe(self, packet, prefix=""):
+        """Parse flow mod and return description
+        """
+        dic = self.__assert_dic(packet, "ofp_flow_mod")
+        if (dic == None):
+            return ""
+        return prefix+\
+               "Flow_mod of command "+self.__messages.get_enum_name("ofp_flow_mod_command", dic["command"][0])+\
+               " idle/hard timeout:"+str(dic["idle_timeout"][0])+"/"+str(dic["hard_timeout"][0])+\
+               self.match_describe(dic, "match.", "\n\t")+\
+               prefix+\
+               "(priority:"+str(dic["priority"][0])+\
+               "/buffer id:"+str(dic["buffer_id"][0])+\
+               "/out port:"+str(dic["out_port"][0])+")"
+
+    def match_describe(self, dic, nameprefix="", prefix=""):
+        """Return description for ofp match
+        """
+        return prefix+"match wildcards:%x" % dic[nameprefix+"wildcards"][0]+\
+               " inport="+str(dic[nameprefix+"in_port"][0])+\
+               prefix+"     "+\
+               " ethertype="+str(dic[nameprefix+"dl_type"][0])+\
+               " vlan="+str(dic[nameprefix+"dl_vlan"][0])+\
+               " "+self.eth_describe(dic[nameprefix+"dl_src"])+"->"+\
+               self.eth_describe(dic[nameprefix+"dl_dst"])+\
+               prefix+"     "+\
+               " ipproto="+str(dic[nameprefix+"nw_proto"][0])+\
+               " "+self.ip_describe(dic[nameprefix+"nw_src"][0])+\
+               "->"+self.ip_describe(dic[nameprefix+"nw_src"][0])+\
+               prefix+"     "+\
+               " transport "+str(dic[nameprefix+"tp_src"][0])+\
+               "->"+str(dic[nameprefix+"tp_dst"][0])
+               
+    def switch_config_describe(self, packet):
+        """Parse OpenFlow switch config and return description
+        """
+        dic = self.__assert_dic(packet, "ofp_switch_config")
+        if (dic == None):
+            return ""
+        return "with flag "+str(self.__messages.get_enum_name("ofp_config_flags", dic["flags"][0]))+\
+               " and miss send length "+str(dic["miss_send_len"][0])
+        
+    def header_describe(self, packet):
+        """Parse OpenFlow header and return string description
+        """
+        dic = self.__assert_dic(packet, "ofp_header")
+        if (dic == None):
+            return ""
+        return self.__messages.get_enum_name("ofp_type", dic["type"][0])+" packet "+\
+               "(length:"+str(dic["length"][0])+\
+               "/xid:"+str(dic["xid"][0])+")"
+
+    def ip_describe(self, value):
+        """Return string for ip address
+        """
+        desc = ""
+        for i in range(0,4):
+            (value, cv) = divmod(value, 256)
+            desc = str(cv).strip() +"." + desc
+        return desc
+    
+    def eth_describe(self, etheraddr):
+        """Return string for ethernet address
+        """
+        desc = ""
+        for value in etheraddr:
+            desc += ":"+("%x" % value).zfill(2)
+        return desc[1:]
+
+    def __assert_dic(self, packet, typename):
+        """Assert and ensure dictionary is given
+        """
+        dic = None
+        if (isinstance(packet, str)):
+            dic = self.__messages.peek_from_front(typename, packet)
+        elif (isinstance(packet, dict)):
+            dic = packet
+        return dic
diff --git a/tools/pylibopenflow/pylib/of/network.py b/tools/pylibopenflow/pylib/of/network.py
new file mode 100644
index 0000000..6765a12
--- /dev/null
+++ b/tools/pylibopenflow/pylib/of/network.py
@@ -0,0 +1,191 @@
+"""This module holds the network.
+
+Copyright(C) 2009, Stanford University
+Date October 2009
+Created by ykk
+"""
+import random
+import openflow
+
+class network:
+    """Class holding information about OpenFlow network
+    """
+    def __init__(self):
+        """Initialize
+        """
+        ##List of switches
+        self.switches = []
+        ##Dictionary of links
+        self.links = {}
+        ##Reference to connections
+        self.connections = openflow.connections()
+
+    def add_switch(self, sw):
+        """Add switch to network
+        """
+        self.switches.append(sw)
+        self.connections.add_connection(sw, sw.connection)
+
+    def add_link(self, link):
+        """Add link to network
+        """
+        try:
+            self.links[link.switch1,link.switch2].append(link)
+        except KeyError:
+            self.links[link.switch1,link.switch2] = []
+            self.links[link.switch1,link.switch2].append(link)
+
+class link:
+    """Class to hold information about link
+
+    Copyright(C) 2009, Stanford University
+    Date November 2009
+    Created by ykk
+    """
+    def __init__(self, switch1, switch2):
+        """Initialize link between specified switches
+        """
+        ##Reference to first switch
+        self.switch1 = switch1
+        ##Reference to second switch
+        self.switch2 = switch2
+
+class switch:
+    """Class holding information about OpenFlow switch
+
+    Copyright(C) 2009, Stanford University
+    Date October 2009
+    Created by ykk
+    """
+    def __init__(self, miss_send_len=128,
+                 sock=None, dpid=None, n_buffers=100, n_tables=1,
+                 capability=None):
+        """Initialize switch
+        """
+        ##Socket to controller
+        self.sock = sock
+        ##Datapath id of switch
+        if (dpid != None):
+            self.datapath_id = dpid
+        else:
+            self.datapath_id = random.randrange(1, pow(2,64))
+        ##Number of buffers
+        self.n_buffers = n_buffers
+        ##Number of tables
+        self.n_tables= n_tables
+        ##Capabilities
+        if (isinstance(capability, switch_capabilities)):
+            self.capability = capability
+        else:
+            self.capability = switch_capabilities(miss_send_len)
+        ##Valid Actions
+        self.valid_actions = 0
+        ##List of port
+        self.port = []
+
+class switch_capabilities:
+    """Class to hold switch capabilities
+    """
+    def __init__(self, miss_send_len=128):
+        """Initialize
+
+        Copyright(C) 2009, Stanford University
+        Date October 2009
+        Created by ykk
+        """
+        ##Capabilities support by datapath
+        self.flow_stats = True
+        self.table_stats = True
+        self.port_stats = True
+        self.stp = True
+        self.multi_phy_tx = True
+        self.ip_resam = False
+        ##Switch config
+        self.send_exp = None
+        self.ip_frag = 0
+        self.miss_send_len = miss_send_len
+        ##Valid actions
+        self.act_output = True
+        self.act_set_vlan_vid = True
+        self.act_set_vlan_pcp = True
+        self.act_strip_vlan = True
+        self.act_set_dl_src = True
+        self.act_set_dl_dst = True
+        self.act_set_nw_src = True
+        self.act_set_nw_dst = True
+        self.act_set_tp_src = True
+        self.act_set_tp_dst = True
+        self.act_vendor = False
+
+    def get_capability(self, ofmsg):
+        """Return value for uint32_t capability field
+        """
+        value = 0
+        if (self.flow_stats):
+            value += ofmsg.get_value("OFPC_FLOW_STATS")
+        if (self.table_stats):
+            value += ofmsg.get_value("OFPC_TABLE_STATS")
+        if (self.port_stats):
+            value += ofmsg.get_value("OFPC_PORT_STATS")
+        if (self.stp):
+            value += ofmsg.get_value("OFPC_STP")
+        if (self.multi_phy_tx):
+            value += ofmsg.get_value("OFPC_MULTI_PHY_TX")
+        if (self.ip_resam):
+            value += ofmsg.get_value("OFPC_IP_REASM")
+        return value
+
+    def get_actions(self, ofmsg):
+        """Return value for uint32_t action field
+        """
+        value = 0
+        if (self.act_output):
+            value += (1 << (ofmsg.get_value("OFPAT_OUTPUT")+1))
+        if (self.act_set_vlan_vid):
+            value += (1 << (ofmsg.get_value("OFPAT_SET_VLAN_VID")+1))
+        if (self.act_set_vlan_pcp):
+            value += (1 << (ofmsg.get_value("OFPAT_SET_VLAN_PCP")+1))
+        if (self.act_strip_vlan):
+            value += (1 << (ofmsg.get_value("OFPAT_STRIP_VLAN")+1))
+        if (self.act_set_dl_src):
+            value += (1 << (ofmsg.get_value("OFPAT_SET_DL_SRC")+1))
+        if (self.act_set_dl_dst):
+            value += (1 << (ofmsg.get_value("OFPAT_SET_DL_DST")+1))
+        if (self.act_set_nw_src):
+            value += (1 << (ofmsg.get_value("OFPAT_SET_NW_SRC")+1))
+        if (self.act_set_nw_dst):
+            value += (1 << (ofmsg.get_value("OFPAT_SET_NW_DST")+1))
+        if (self.act_set_tp_src):
+            value += (1 << (ofmsg.get_value("OFPAT_SET_TP_SRC")+1))
+        if (self.act_set_tp_dst):
+            value += (1 << (ofmsg.get_value("OFPAT_SET_TP_DST")+1))
+        return value
+
+class port:
+    """Class to hold information about port
+    
+    Copyright(C) 2009, Stanford University
+    Date October 2009
+    Created by ykk
+    """
+    def __init__(self, port_no, stp=(2 << 8), hw_addr=None, name=""):
+        """Initialize
+        """
+        ##Port properties
+        self.port_no = port_no
+        if (hw_addr != None):
+            self.hw_addr = hw_addr
+        else:
+            self.hw_addr = random.randrange(1, pow(2,48))
+        self.name = name
+        ##Port config
+        self.port_down = False
+        self.no_stp = False
+        self.no_recv = False
+        self.no_recv_stp = False
+        self.no_flood = False
+        self.no_fwd = False
+        self.no_packet_in = False
+        #Port state
+        self.link_down = False
+        self.stp = stp
diff --git a/tools/pylibopenflow/pylib/of/pythonize.py b/tools/pylibopenflow/pylib/of/pythonize.py
new file mode 100644
index 0000000..687512b
--- /dev/null
+++ b/tools/pylibopenflow/pylib/of/pythonize.py
@@ -0,0 +1,57 @@
+"""This module generate Python code for OpenFlow structs.
+
+(C) Copyright Stanford University
+Date December 2009
+Created by ykk
+"""
+import cpythonize
+from config import *
+
+class rules(cpythonize.rules):
+    """Class that specify rules for pythonization of OpenFlow messages
+
+    (C) Copyright Stanford University
+    Date December 2009
+    Created by ykk
+    """
+    def __init__(self, ofmsg):
+        """Initialize rules
+        """
+        cpythonize.rules.__init__(self)
+        ##Reference to ofmsg
+        self.__ofmsg = ofmsg
+        ##Default values for members
+        self.default_values[('ofp_header','version')] = self.__ofmsg.get_value('OFP_VERSION')
+        self.default_values[('ofp_switch_config',\
+                             'miss_send_len')] = self.__ofmsg.get_value('OFP_DEFAULT_MISS_SEND_LEN')
+        for x in ['ofp_flow_mod','ofp_flow_expired','ofp_flow_stats']:
+            self.default_values[(x,'priority')] = self.__ofmsg.get_value('OFP_DEFAULT_PRIORITY')
+        #Default values for struct
+        self.struct_default[('ofp_flow_mod',
+                             'header')] = ".type = OFPT_FLOW_MOD"
+#                             'header')] = ".type = "+str(self.__ofmsg.get_value('OFPT_FLOW_MOD'))
+        ##Macros to exclude
+        self.excluded_macros = ['OFP_ASSERT(EXPR)','OFP_ASSERT(_EXPR)','OFP_ASSERT',
+                                'icmp_type','icmp_code','OFP_PACKED',
+                                'OPENFLOW_OPENFLOW_H']
+        ##Enforce mapping
+        if GEN_ENUM_VALUES_LIST:
+            self.enforced_maps['ofp_header'] = [ ('type','ofp_type_values') ]
+        elif GEN_ENUM_DICTIONARY:
+            self.enforced_maps['ofp_header'] = \
+                [ ('type','ofp_type_map.values()') ]
+        
+class pythonizer(cpythonize.pythonizer):
+    """Class that pythonize C structures of OpenFlow messages
+
+    (C) Copyright Stanford University
+    Date December 2009
+    Created by ykk
+    """
+    def __init__(self, ofmsg):
+        """Initialize
+        """
+        ofrules =  rules(ofmsg)
+        cpythonize.pythonizer.__init__(self, ofmsg, ofrules)
+        ##Reference to OpenFlow message class
+        self.__ofmsg = ofmsg
diff --git a/tools/pylibopenflow/pylib/of/simu.py b/tools/pylibopenflow/pylib/of/simu.py
new file mode 100644
index 0000000..508b076
--- /dev/null
+++ b/tools/pylibopenflow/pylib/of/simu.py
@@ -0,0 +1,144 @@
+"""This module simulates the network.
+
+Copyright(C) 2009, Stanford University
+Date November 2009
+Created by ykk
+"""
+import openflow
+import output
+import of.msg
+import of.network
+
+class network(of.network.network):
+    """Class to simulate OpenFlow network
+
+    Copyright(C) 2009, Stanford University
+    Date November 2009
+    Created by ykk
+    """
+    def __init__(self):
+        """Initialize network
+        """
+        of.network.network.__init__(self)
+        ##Name of use for output
+        self.name = self.__class__.__name__+str(id(self))
+
+class link(of.network.link):
+    """Class to simulate link
+
+    Copyright(C) 2009, Stanford University
+    Date November 2009
+    Created by ykk
+    """
+    def __init__(self, switch1, switch2, isUp=True):
+        """Initialize link
+        """
+        of.network.link.__init__(self, switch1, switch2)
+        ##Name of use for output
+        self.name = self.__class__.__name__+str(id(self))
+        ##Indicate if link is up
+        self.isUp = isUp
+
+class switch(of.network.switch):
+    """Class to simulate OpenFlow switch
+
+    Copyright(C) 2009, Stanford University
+    Date November 2009
+    Created by ykk
+    """
+    def __init__(self,  messages, controller, port, miss_send_len=128,
+                 dpid=None, n_buffers=100, n_tables=1,
+                 capability=None, parser=None, connection=None):
+        """Initialize switch
+        """
+        of.network.switch.__init__(self,  miss_send_len,
+                                   None, dpid, n_buffers, n_tables,
+                                   capability)
+        ##Name of use for output
+        self.name = self.__class__.__name__+str(id(self))
+        ##Reference to OpenFlow messages
+        self.__messages = messages
+        ##Reference to connection
+        self.connection = openflow.tcpsocket(messages, controller, port)
+        self.sock = self.connection.sock
+        ##Reference to Parser
+        self.parser = None
+        if (parser == None):
+            self.parser = of.msg.parser(messages)
+        else:
+            self.parser = parser
+
+    def receive_openflow(self, packet):
+        """Switch receive OpenFlow packet, and respond accordingly
+        """
+        dic = self.__messages.peek_from_front("ofp_header", packet)
+        if (dic["type"][0] == self.__messages.get_value("OFPT_HELLO")):
+            output.dbg("Receive hello", self.name)
+        elif (dic["type"][0] == self.__messages.get_value("OFPT_ECHO_REQUEST")):
+            self.reply_echo(dic["xid"][0])
+        elif (dic["type"][0] == self.__messages.get_value("OFPT_FEATURES_REQUEST")):
+            self.reply_features(dic["xid"][0])
+        elif (dic["type"][0] == self.__messages.get_value("OFPT_FLOW_MOD")):
+            self.handle_flow_mod(packet)
+        else:
+            output.dbg("Unprocessed message "+self.parser.header_describe(dic),
+                       self.name)
+
+    def send_hello(self):
+        """Send hello
+        """
+        self.connection.structsend("ofp_hello",
+                                   0, self.__messages.get_value("OFPT_HELLO"),
+                                   0, 0)
+        output.dbg("Send hello",self.name)
+
+    def send_packet(self, inport, bufferid=None, packet="", xid=0, reason=None):
+        """Send packet in
+        Assume no match as reason, bufferid = 0xFFFFFFFF,
+        and empty packet by default
+        """
+        if (reason == None):
+            reason = self.__messages.get_value("OFPR_NO_MATCH")
+        if (bufferid == None):
+            bufferid = int("0xFFFFFFFF",16)
+        pktin = self.__messages.pack("ofp_packet_in",
+                                     0, self.__messages.get_value("OFPT_PACKET_IN"),
+                                     0, xid, #header
+                                     bufferid, len(packet),
+                                     inport, reason, 0)
+        self.connection.structsend_raw(pktin+packet)
+        output.dbg("Send packet ",self.name)
+
+    def send_echo(self, xid=0):
+        """Send echo
+        """
+        self.connection.structsend_xid("ofp_header",
+                                       0, self.__messages.get_value("OFPT_ECHO_REQUEST"),
+                                       0, xid)
+        output.dbg("Send echo", self.name)
+
+    def reply_echo(self, xid):
+        """Reply to echo request
+        """
+        self.connection.structsend_xid("ofp_header",
+                                       0, self.__messages.get_value("OFPT_ECHO_REPLY"),
+                                       0, xid)                                 
+        output.dbg("Reply echo of xid:"+str(xid),self.name)
+
+    def reply_features(self, xid):
+        """Reply to feature request
+        """
+        self.connection.structsend_xid("ofp_switch_features",
+                                       0, self.__messages.get_value("OFPT_FEATURES_REPLY"),
+                                       0, xid,
+                                       self.datapath_id, self.n_buffers,
+                                       self.n_tables,0,0,0,
+                                       self.capability.get_capability(self.__messages),
+                                       self.capability.get_actions(self.__messages))
+        output.dbg("Replied features request of xid "+str(xid), self.name)
+        
+    def handle_flow_mod(self, packet):
+        """Handle flow mod: just print it here
+        """
+        output.dbg(self.parser.flow_mod_describe(packet), self.name)
+