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