| ''' |
| 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 |
| import time |
| |
| from oftest.testutils import * |
| |
| onu_port = test_param_get("onu_port", 1) |
| onu_port2 = test_param_get("onu_port2", 2) |
| 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"]: |
| 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 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 TestMeter(base_tests.SimpleDataPlane): |
| |
| def runTest(self): |
| logging.info("Running Meter tests") |
| dropMeterBand = ofp.meter_band.drop(rate = 500) |
| meter_mod = ofp.message.meter_mod(xid = 1, command = ofp.OFPMC_ADD, meter_id = 1, meters = [ dropMeterBand ]) |
| self.controller.message_send(meter_mod) |
| |
| time.sleep(1) |
| |
| verify_no_errors(self.controller) |
| |
| vlan_id = 201 |
| match = ofp.match() |
| match.oxm_list.append(ofp.oxm.in_port(onu_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.output(port=olt_port)] |
| ), |
| ofp.instruction.meter(meter_id = 1) |
| ], |
| buffer_id=ofp.OFP_NO_BUFFER, |
| priority=1000) |
| |
| self.controller.message_send(request) |
| time.sleep(1) |
| verify_no_errors(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=43, |
| match=match, |
| instructions=[ |
| ofp.instruction.apply_actions( |
| actions=[ofp.action.output(port=onu_port)] |
| ), |
| ofp.instruction.meter(meter_id = 1) |
| ], |
| buffer_id=ofp.OFP_NO_BUFFER, |
| priority=1000) |
| |
| self.controller.message_send(request) |
| time.sleep(1) |
| verify_no_errors(self.controller) |
| do_barrier(self.controller) |
| time.sleep(5) |
| |
| inPkt = simple_udp_packet(dl_vlan_enable=True, vlan_vid=vlan_id, vlan_pcp=0) |
| # downstream |
| self.dataplane.send(olt_port, str(inPkt)) |
| verify_packet(self, inPkt, onu_port) |
| # upstream |
| self.dataplane.send(onu_port, str(inPkt)) |
| verify_packet(self, inPkt, olt_port) |
| |
| # clean up the test |
| meter_mod = ofp.message.meter_mod(xid = 2, command = ofp.OFPMC_DELETE, meter_id = 1) |
| self.controller.message_send(meter_mod) |
| time.sleep(1) |
| delete_all_flows(self.controller) |
| verify_no_errors(self.controller) |
| |
| |
| class TestDuplicateMeter(base_tests.SimpleDataPlane): |
| |
| def runTest(self): |
| logging.info("Running Duplicate Meter Test") |
| dropMeterBand = ofp.meter_band.drop(rate = 500) |
| meter_mod = ofp.message.meter_mod(xid = 1, command = ofp.OFPMC_ADD, meter_id = 1, meters = [ dropMeterBand ]) |
| self.controller.message_send(meter_mod) |
| self.controller.message_send(meter_mod) |
| |
| time.sleep(1) |
| |
| try: |
| verify_no_errors(self.controller) |
| except AssertionError as e: |
| if (not e.message == "unexpected error type=12 code=1"): |
| raise AssertionError("Incorrect error type: %s" % e.message) |
| |
| |
| class VlanTest(base_tests.SimpleDataPlane): |
| |
| """Verify the switch can push/pop 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) |
| |
| #PUSH |
| match = ofp.match() |
| match.oxm_list.append(ofp.oxm.in_port(onu_port)) |
| match.oxm_list.append(ofp.oxm.vlan_vid_masked(value=ofp.OFPVID_PRESENT, value_mask=ofp.OFPVID_PRESENT)) |
| match.oxm_list.append(ofp.oxm.vlan_pcp(value = 0)) |
| |
| 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.set_field(ofp.oxm.vlan_pcp(0)), |
| ofp.action.output(port=olt_port)])], |
| buffer_id=ofp.OFP_NO_BUFFER, |
| priority=1000) |
| |
| logging.info("Inserting flow tagging upstream") |
| self.controller.message_send(request) |
| |
| #POP |
| 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=43, |
| match=match, |
| instructions=[ |
| ofp.instruction.apply_actions( |
| actions=[ |
| ofp.action.pop_vlan(), |
| ofp.action.output(port=onu_port)])], |
| buffer_id=ofp.OFP_NO_BUFFER, |
| priority=1000) |
| |
| logging.info("Inserting flow tagging downstream") |
| self.controller.message_send(request) |
| do_barrier(self.controller) |
| time.sleep(5) |
| |
| inPkt = simple_udp_packet(dl_vlan_enable=True, vlan_vid=0, vlan_pcp=0) |
| outPkt = simple_udp_packet(pktlen=100, 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, []) |
| |
| 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(pktlen=104, dl_vlan_enable=True, vlan_vid=0, vlan_pcp=0) |
| |
| # 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, []) |
| |
| def createAllGroupAdd(group_id, ports=[]): |
| buckets = [] |
| |
| for portNum in ports: |
| buckets.append(ofp.common.bucket(watch_port=ofp.OFPP_ANY, watch_group=ofp.OFPG_ANY, |
| actions=[ofp.action.output(port=portNum)])) |
| |
| group_add = ofp.message.group_add(group_type = ofp.OFPGT_ALL, group_id=group_id, buckets=buckets) |
| |
| return group_add |
| |
| def createAllGroupMod(group_id, ports=[]): |
| buckets = [] |
| |
| for portNum in ports: |
| buckets.append(ofp.common.bucket(watch_port=ofp.OFPP_ANY, watch_group=ofp.OFPG_ANY, |
| actions=[ofp.action.output(port=portNum)])) |
| |
| group_mod = ofp.message.group_mod(command=ofp.OFPGC_MODIFY, group_type = ofp.OFPGT_ALL, group_id=group_id, buckets=buckets) |
| |
| return group_mod |
| |
| |
| class TestGroupAdd(base_tests.SimpleDataPlane): |
| |
| def runTest(self): |
| logging.info("Running Group tests") |
| delete_all_flows(self.controller) |
| delete_all_groups(self.controller) |
| |
| test_group_id = 1 |
| |
| # output to two ONU |
| group_add = createAllGroupAdd(test_group_id, ports=[onu_port, onu_port2]) |
| |
| self.controller.message_send(group_add) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| # Remove the group and then readd it. |
| group_delete = ofp.message.group_delete(group_id = test_group_id) |
| self.controller.message_send(group_delete) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| group_add = createAllGroupAdd(test_group_id, [onu_port, onu_port2]) |
| self.controller.message_send(group_add) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| |
| # clean up the test |
| group_delete = ofp.message.group_delete(group_id = test_group_id) |
| self.controller.message_send(group_delete) |
| |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| class TestGroupMod(base_tests.SimpleDataPlane): |
| |
| def runTest(self): |
| logging.info("Running Group tests") |
| delete_all_flows(self.controller) |
| delete_all_groups(self.controller) |
| |
| test_group_id = 1 |
| |
| group_add = createAllGroupAdd(test_group_id, [onu_port, onu_port2]) |
| |
| self.controller.message_send(group_add) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| # Modifying the group |
| group_mod = createAllGroupMod(test_group_id, [onu_port2]) |
| |
| self.controller.message_send(group_mod) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| # Add a bucket into the group |
| group_mod = createAllGroupMod(test_group_id, [onu_port, onu_port2]) |
| self.controller.message_send(group_mod) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| # Modifying a non-existing group |
| group_mod = createAllGroupMod(777, [onu_port2]) |
| |
| self.controller.message_send(group_mod) |
| do_barrier(self.controller) |
| errorExperienced = 0 |
| try: |
| verify_no_errors(self.controller) |
| except AssertionError as e: |
| errorExperienced = 1 |
| if (not (e.message == "unexpected error type=6 code=8")): |
| raise AssertionError("Incorrect error type: %s" % e.message) |
| if not errorExperienced: |
| raise AssertionError("An error message is expected, but not shown.") |
| |
| |
| # clean up the test |
| group_delete = ofp.message.group_delete(xid = 2, group_id = test_group_id) |
| self.controller.message_send(group_delete) |
| |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| class TestDuplicateGroup(base_tests.SimpleDataPlane): |
| |
| def runTest(self): |
| logging.info("Running Group tests") |
| delete_all_flows(self.controller) |
| delete_all_groups(self.controller) |
| |
| test_group_id = 1 |
| group_add = createAllGroupAdd(test_group_id, ports=[onu_port]) |
| |
| self.controller.message_send(group_add) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| # Add the same group id |
| duplicate_group_fail = 0 |
| |
| self.controller.message_send(group_add) |
| do_barrier(self.controller) |
| try: |
| verify_no_errors(self.controller) |
| except AssertionError as e: |
| duplicate_group_fail = 1 |
| if (not e.message == "unexpected error type=6 code=0"): |
| raise AssertionError("Incorrect error type: %s" % e.message) |
| if not duplicate_group_fail: |
| raise AssertionError("Adding duplicate groups didn't raise an error.") |
| |
| # clean up the test |
| group_delete = ofp.message.group_delete(xid = 2, group_id = test_group_id) |
| self.controller.message_send(group_delete) |
| |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| class TestGroupAndFlow(base_tests.SimpleDataPlane): |
| |
| def runTest(self): |
| logging.info("Running Group tests") |
| delete_all_flows(self.controller) |
| delete_all_groups(self.controller) |
| |
| # Create a group |
| test_group_id = 1 |
| group_add = createAllGroupAdd(test_group_id, ports=[onu_port]) |
| |
| self.controller.message_send(group_add) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| # Create a flow rule matching olt port and vlan id |
| match = ofp.match() |
| match.oxm_list.append(ofp.oxm.in_port(olt_port)) |
| match.oxm_list.append(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | 201)) |
| |
| flow_pointing_to_group = ofp.message.flow_add( |
| table_id=test_param_get("table", 0), |
| cookie=43, |
| match=match, |
| instructions=[ |
| ofp.instruction.apply_actions( |
| actions=[ ofp.action.group( group_id = test_group_id ) ] ) ], |
| buffer_id=ofp.OFP_NO_BUFFER, priority=1000) |
| |
| self.controller.message_send(flow_pointing_to_group) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| # After letting a flow rule point to the group, test we can do group_mod |
| group_mod = createAllGroupMod(test_group_id, ports=[onu_port2]) |
| self.controller.message_send(group_mod) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| # Test we can remove flows and then remove group |
| flow_delete = ofp.message.flow_delete( table_id=test_param_get("table", 0)) |
| self.controller.message_send(flow_delete) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| group_delete = ofp.message.group_delete(xid = 3, group_id = test_group_id) |
| self.controller.message_send(group_delete) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| # Add the group and flow back, test it we can first remove group and then remove the flow. |
| group_add = createAllGroupAdd(test_group_id, ports=[onu_port]) |
| self.controller.message_send(group_add) |
| |
| self.controller.message_send(flow_pointing_to_group) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| group_delete = ofp.message.group_delete(xid = 4, group_id = test_group_id) |
| self.controller.message_send(group_delete) |
| |
| self.controller.message_send(flow_delete) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| |
| class TestGroupForwarding(base_tests.SimpleDataPlane): |
| |
| def runTest(self): |
| logging.info("Running Group datapath forwarding tests") |
| delete_all_flows(self.controller) |
| #delete_all_groups(self.controller) |
| |
| vlan_id = 201 |
| |
| # Create a group |
| test_group_id = 1 |
| group_add = createAllGroupAdd(test_group_id, [onu_port]) |
| |
| self.controller.message_send(group_add) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| # Create a flow rule matching olt port and vlan id |
| 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=43, |
| match=match, |
| instructions=[ |
| ofp.instruction.apply_actions( |
| actions=[ ofp.action.group( group_id = test_group_id ) ] ), |
| ], |
| buffer_id=ofp.OFP_NO_BUFFER, priority=1000) |
| |
| self.controller.message_send(request) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| # It takes some time for flows to propagate down to the data plane |
| time.sleep(2) |
| |
| inPkt = simple_udp_packet(pktlen=104,dl_vlan_enable=True, |
| vlan_vid=vlan_id, vlan_pcp=0, dl_vlan_cfi=0) |
| outPkt = inPkt |
| self.dataplane.send(olt_port, str(inPkt)) |
| verify_packet(self, outPkt, onu_port) |
| |
| # Now put 2 ONU ports in the group and test that the input packet is |
| # duplicated out both ports |
| group_mod = createAllGroupMod(test_group_id, ports=[onu_port, onu_port2]) |
| self.controller.message_send(group_mod) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| # It takes some time for flows to propagate down to the data plane |
| time.sleep(2) |
| |
| self.dataplane.send(olt_port, str(inPkt)) |
| verify_packet(self, outPkt, onu_port) |
| verify_packet(self, outPkt, onu_port2) |
| |
| |
| # clean up the test |
| request = ofp.message.flow_delete( table_id=test_param_get("table", 0)) |
| self.controller.message_send(request) |
| group_delete = ofp.message.group_delete(xid = 2, group_id = test_group_id) |
| self.controller.message_send(group_delete) |
| |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| class TransparentVlanTest(base_tests.SimpleDataPlane): |
| |
| def runTest(self): |
| logging.info("Running transparent vlan tests") |
| delete_all_flows(self.controller) |
| |
| vlan_id = 201 |
| match = ofp.match() |
| match.oxm_list.append(ofp.oxm.in_port(onu_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.output(port=olt_port)]), |
| ], |
| buffer_id=ofp.OFP_NO_BUFFER, |
| priority=1000) |
| |
| self.controller.message_send(request) |
| |
| 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=43, |
| match=match, |
| instructions=[ |
| ofp.instruction.apply_actions( |
| actions=[ |
| ofp.action.output(port=onu_port)]), |
| ], |
| buffer_id=ofp.OFP_NO_BUFFER, |
| priority=1000) |
| |
| self.controller.message_send(request) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| # It takes some time for flows to propagate down to the data plane |
| time.sleep(2) |
| |
| inPkt = simple_udp_packet(dl_vlan_enable=True, vlan_vid=vlan_id, vlan_pcp=0) |
| # downstream |
| self.dataplane.send(olt_port, str(inPkt)) |
| verify_packet(self, inPkt, onu_port) |
| # upstream |
| self.dataplane.send(onu_port, str(inPkt)) |
| verify_packet(self, inPkt, olt_port) |
| |
| |
| # clean up the test |
| delete_all_flows(self.controller) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| |