Adding test files
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ed33838
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+*.pyc
+*~
+.project
+.pydevproject
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..bf5e05a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,45 @@
+OFTest suite for PMC OLT
+
+---
+
+# Introduction
+
+Small suite of tests that describe the behaviour needed from the OLT for CORD.
+
+This is based on the OFTest framework. See here for details on OFTest, including prerequisites and steps to set up: https://github.com/floodlight/oftest
+
+---
+
+# Running instructions
+
+Firstly make sure the prerequisites for OFTest are installed - Python and Scapy.
+
+Clone both the OFTest repository and this repository side-by-side.
+
+You'll need to connect the OLT port and one of the ONU ports connected to interfaces on the server - for example, ONU port 1 to eth1 on the server, and OLT port 129 to eth2 on the server.
+
+Then you can run the tests as follows:
+
+    sudo oftest/oft --test-dir=olt-oftest/ -i 1@eth1 -i 129@eth2 --port 6633 -V 1.3
+
+If you need to change the port numbers used, for example to use ONU port 3:
+
+    sudo ./oftest/oft --test-dir=olt-oftest/ -i 1@h1-eth0 -i 129@h129-eth0 --port 6633 -V 1.3 --test-params="onu_port=3:olt_port:129"
+
+---
+
+# Running on OVS
+
+We've also provided a Mininet topology that runs an OVS instance with port 1 and port 129 so we can run the tests and verify the correct behaviour without using the OLT. The OVS switch stands in for the OLT in the test framework.
+
+First install Mininet and its dependencies.
+
+Then start the switch:
+     
+    sudo olt-oftest/olt-topo.py
+
+Now you can run the tests on the OVS switch using:
+
+    sudo ./oftest/oft --test-dir=olt-oftest/ -i 1@h1-eth0 -i 129@h129-eth0 --port 6633 -V 1.3
+
+---
\ No newline at end of file
diff --git a/olt-topo.py b/olt-topo.py
new file mode 100755
index 0000000..438a59f
--- /dev/null
+++ b/olt-topo.py
@@ -0,0 +1,34 @@
+#!/usr/bin/python
+
+from mininet.topo import Topo
+from mininet.node import RemoteController
+from mininet.net import Mininet
+from mininet.util import irange
+from mininet.cli import CLI
+from mininet.log import setLogLevel
+
+class OltTopo( Topo ):
+    "Single switch with OLT port 129 and configurable number of ONU ports"
+
+    def build( self, k=1, **_opts ):
+        "k: number of onu"
+        self.k = k
+        switch = self.addSwitch( 's1' )
+        for h in irange( 1, k ):
+            host = self.addHost( 'h%s' % h, inNamespace=False )
+            self.addLink( host, switch )
+
+        olt_port = self.addHost( 'h129', inNamespace=False )
+        self.addLink( olt_port, switch, port2=129 )
+
+if __name__ == '__main__':
+    setLogLevel('debug')
+    topo = OltTopo()
+
+    net = Mininet( topo=topo, controller=RemoteController )
+
+    net.start()
+
+    CLI( net )
+
+    net.stop()
diff --git a/olt.py b/olt.py
new file mode 100644
index 0000000..95a51f6
--- /dev/null
+++ b/olt.py
@@ -0,0 +1,223 @@
+'''
+OFTests for functionality needed from the OLT.
+'''
+import logging
+from oftest import config
+import oftest.base_tests as base_tests
+import oftest.packet as scapy
+
+import ofp
+
+from oftest.testutils import *
+
+onu_port = test_param_get("onu_port", 1)
+olt_port = test_param_get("olt_port", 129)
+
+def testPacketIn(self, match, parsed_pkt):
+    delete_all_flows(self.controller)
+
+    pkt = str(parsed_pkt)
+
+    request = ofp.message.flow_add(
+        table_id=test_param_get("table", 0),
+        cookie=42,
+        match=match,
+        instructions=[
+            ofp.instruction.apply_actions(
+                actions=[
+                    ofp.action.output(
+                        port=ofp.OFPP_CONTROLLER,
+                        max_len=ofp.OFPCML_NO_BUFFER)])],
+        buffer_id=ofp.OFP_NO_BUFFER,
+        priority=1000)
+
+    logging.info("Inserting flow sending matching packets to controller")
+    self.controller.message_send(request)
+    do_barrier(self.controller)
+
+    for of_port in config["port_map"].keys():
+        logging.info("PacketInExact test, port %d", of_port)
+        self.dataplane.send(of_port, pkt)
+        verify_packet_in(self, pkt, of_port, ofp.OFPR_ACTION)
+        verify_packets(self, pkt, [])
+
+class EapolPacketIn(base_tests.SimpleDataPlane):
+    
+    """Verify packet-ins are sent for EAPOL packets """
+    
+    def runTest(self):
+        logging.info("Running EAPOL Packet In test")
+
+        match = ofp.match()
+        match.oxm_list.append(ofp.oxm.eth_type(0x888e))
+        # Use ethertype 0x888e and multicast destination MAC address
+        pkt = simple_eth_packet(pktlen=60, eth_dst='01:00:5E:7F:FF:FF', eth_type=0x888e)
+        
+        testPacketIn(self, match, pkt)
+
+class ARPPacketIn(base_tests.SimpleDataPlane):
+    
+    """Verify packet-ins are sent for ARP packets """
+    
+    def runTest(self):
+        logging.info("Running ARP Packet In test")
+
+        match = ofp.match()
+        match.oxm_list.append(ofp.oxm.eth_type(0x0806))
+
+        # Use ethertype 0x0806
+        pkt = simple_eth_packet(eth_type=0x0806)
+        
+        testPacketIn(self, match, pkt)
+        
+class RadiusPacketIn(base_tests.SimpleDataPlane):
+    
+    """Verify packet-ins are sent for Radius packets """
+    
+    def runTest(self):
+        logging.info("Running Radius Packet In test")
+
+        pkt = simple_udp_packet(udp_sport=1812, udp_dport=1812)
+        
+        match = ofp.match()
+        match.oxm_list.append(ofp.oxm.eth_type(0x0800))
+        match.oxm_list.append(ofp.oxm.ip_proto(17))
+        match.oxm_list.append(ofp.oxm.udp_src(1812))
+        match.oxm_list.append(ofp.oxm.udp_dst(1812))
+        
+        testPacketIn(self, match, pkt)
+        
+        # Other UDP packets should not match the rule
+        dhcpPkt = simple_udp_packet(udp_sport=68, udp_dport=67)
+        
+        self.dataplane.send(1, str(dhcpPkt))
+        verify_no_packet_in(self, dhcpPkt, 1)
+        
+        
+class DHCPPacketIn(base_tests.SimpleDataPlane):
+    
+    """Verify packet-ins are sent for DHCP packets """
+    
+    def runTest(self):
+        logging.info("Running DHCP Packet In test")
+
+        pkt = simple_udp_packet(udp_sport=68, udp_dport=67)
+        
+        match = ofp.match()
+        match.oxm_list.append(ofp.oxm.eth_type(0x0800))
+        match.oxm_list.append(ofp.oxm.ip_proto(17))
+        match.oxm_list.append(ofp.oxm.udp_src(68))
+        match.oxm_list.append(ofp.oxm.udp_dst(67))
+        
+        testPacketIn(self, match, pkt)
+        
+        # Other UDP packets should not match the rule
+        radiusPkt = simple_udp_packet(udp_sport=1812, udp_dport=1812)
+        
+        self.dataplane.send(1, str(radiusPkt))
+        verify_no_packet_in(self, radiusPkt, 1)    
+        
+class IGMPPacketIn(base_tests.SimpleDataPlane):
+    
+    """Verify packet-ins are sent for IGMP packets """
+    
+    def runTest(self):
+        logging.info("Running IGMP Packet In test")
+
+        match = ofp.match()
+        match.oxm_list.append(ofp.oxm.eth_type(0x800))
+        match.oxm_list.append(ofp.oxm.ip_proto(2))
+        
+        pkt = scapy.Ether(dst='01:00:5E:7F:FF:FF', src='00:00:00:00:00:01')/ \
+            scapy.IP(src='10.0.0.1', dst='10.0.0.2', ttl=60, tos=0, id=0, proto=2)
+
+        pkt = pkt/("0" * (100 - len(pkt)))
+        
+        testPacketIn(self, match, pkt)
+        
+class PushVlan(base_tests.SimpleDataPlane):
+    
+    """Verify the switch can push a VLAN tag and forward out a port """
+    
+    def runTest(self):
+        logging.info("Running push VLAN test")
+        
+        vlan_id = 200
+        
+        delete_all_flows(self.controller)
+        
+        match = ofp.match()
+        match.oxm_list.append(ofp.oxm.in_port(onu_port))
+        match.oxm_list.append(ofp.oxm.vlan_vid(ofp.OFP_VLAN_NONE))
+        
+        request = ofp.message.flow_add(
+            table_id=test_param_get("table", 0),
+            cookie=42,
+            match=match,
+            instructions=[
+                ofp.instruction.apply_actions(
+                    actions=[
+                        ofp.action.push_vlan(ethertype=0x8100),
+                        ofp.action.set_field(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | vlan_id)),
+                        ofp.action.output(port=olt_port)])],
+            buffer_id=ofp.OFP_NO_BUFFER,
+            priority=1000)
+
+        logging.info("Inserting flow sending matching packets to controller")
+        self.controller.message_send(request)
+        do_barrier(self.controller)
+        
+        inPkt = simple_udp_packet()
+        outPkt = simple_udp_packet(pktlen=104, dl_vlan_enable=True, 
+                                   vlan_vid=vlan_id, vlan_pcp=0, dl_vlan_cfi=0)
+        
+        # Send untagged packet in the ONU port and expect tagged packet out the OLT port
+        self.dataplane.send(onu_port, str(inPkt))
+        verify_packet(self, outPkt, olt_port)
+        
+        # Send untagged packet in the OLT port and expect no packets to come out
+        self.dataplane.send(olt_port, str(inPkt))
+        verify_packets(self, outPkt, [])
+        
+class PopVlan(base_tests.SimpleDataPlane):
+    
+    """Verify the switch can pop a VLAN tag and forward out a port """
+    
+    def runTest(self):
+        logging.info("Running pop VLAN test")
+        
+        vlan_id = 200
+        
+        delete_all_flows(self.controller)
+        
+        match = ofp.match()
+        match.oxm_list.append(ofp.oxm.in_port(olt_port))
+        match.oxm_list.append(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | vlan_id))
+        
+        request = ofp.message.flow_add(
+            table_id=test_param_get("table", 0),
+            cookie=42,
+            match=match,
+            instructions=[
+                ofp.instruction.apply_actions(
+                    actions=[
+                        ofp.action.pop_vlan(),
+                        ofp.action.output(port=1)])],
+            buffer_id=ofp.OFP_NO_BUFFER,
+            priority=1000)
+
+        logging.info("Inserting flow sending matching packets to controller")
+        self.controller.message_send(request)
+        do_barrier(self.controller)
+        
+        inPkt = simple_udp_packet(pktlen=104, dl_vlan_enable=True, 
+                                  vlan_vid=vlan_id, vlan_pcp=0, dl_vlan_cfi=0)
+        outPkt = simple_udp_packet()
+        
+        # Send tagged packet in the OLT port and expect untagged packet out the OLT port
+        self.dataplane.send(olt_port, str(inPkt))
+        verify_packet(self, outPkt, onu_port)
+        
+        # Send tagged packet in the ONU port and expect no packets to come out
+        self.dataplane.send(onu_port, str(inPkt))
+        verify_packets(self, outPkt, [])
\ No newline at end of file