| ''' |
| OFTests for functionality needed from the OLT. |
| ''' |
| |
| import logging |
| from __builtin__ import xrange |
| from oftest import config |
| import oftest.base_tests as base_tests |
| import oftest.packet as scapy |
| |
| import ofp |
| import time |
| import copy |
| |
| from oftest.testutils import * |
| |
| from IGMP import IGMPv3 |
| |
| # These parameters can be altered from the command line using the -t or --test-params= options. |
| # Example: -t 'onu_port=129;olt_port=288;device_type=pmc' |
| # |
| onu_port = test_param_get("onu_port", 130) |
| onu_port2 = test_param_get("onu_port2", 131) |
| olt_port = test_param_get("olt_port", 258) |
| device_type = test_param_get("device_type", "normal") # options: "normal", "pmc", "cpqd" |
| logging.info("device_type: %s" % device_type) |
| |
| |
| def double_vlan_udp_packet(pktlen=100, |
| eth_dst='00:01:02:03:04:05', |
| eth_src='00:06:07:08:09:0a', |
| dl_vlan_enable=False, |
| c_vlan_vid=0, |
| c_vlan_pcp=0, |
| s_vlan_vid=0, |
| s_vlan_pcp=0, |
| ip_src='192.168.0.1', |
| ip_dst='192.168.0.2', |
| ip_tos=0, |
| ip_ttl=64, |
| udp_sport=1234, |
| udp_dport=80, |
| ip_ihl=None, |
| ip_options=False, |
| eth_type=0x8100 |
| ): |
| """ |
| Return a double vlan tagged dataplane UDP packet |
| Supports a few parameters: |
| @param len Length of packet in bytes w/o CRC |
| @param eth_dst Destination MAC |
| @param eth_src Source MAC |
| @param dl_vlan_enable True if the packet is with vlan, False otherwise |
| @param c_vlan_vid CVLAN ID |
| @param c_vlan_pcp CVLAN priority |
| @param s_vlan_vid SVLAN ID |
| @param s_vlan_pcp SVLAN priority |
| @param ip_src IP source |
| @param ip_dst IP destination |
| @param ip_tos IP ToS |
| @param ip_ttl IP TTL |
| @param udp_dport UDP destination port |
| @param udp_sport UDP source port |
| |
| Generates a simple UDP packet. Users shouldn't assume anything about |
| this packet other than that it is a valid ethernet/IP/UDP frame. |
| """ |
| |
| if MINSIZE > pktlen: |
| pktlen = MINSIZE |
| |
| # Note Dot1Q.id is really CFI |
| if (dl_vlan_enable): |
| pkt = scapy.Ether(dst=eth_dst, src=eth_src, type=eth_type) / \ |
| scapy.Dot1Q(prio=s_vlan_pcp, vlan=s_vlan_vid) / \ |
| scapy.Dot1Q(prio=c_vlan_pcp, vlan=c_vlan_vid) / \ |
| scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl) / \ |
| scapy.UDP(sport=udp_sport, dport=udp_dport) |
| else: |
| if not ip_options: |
| pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \ |
| scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \ |
| scapy.UDP(sport=udp_sport, dport=udp_dport) |
| |
| else: |
| pkt = scapy.Ether(dst=eth_dst, src=eth_src) / \ |
| scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options) / \ |
| scapy.UDP(sport=udp_sport, dport=udp_dport) |
| |
| pkt = pkt / ("D" * (pktlen - len(pkt))) |
| |
| return pkt |
| |
| def testPacketIn(self, match, parsed_pkt): |
| delete_all_flows(self.controller) |
| |
| pkt = str(parsed_pkt) |
| |
| for of_port in config["port_map"]: |
| m = copy.deepcopy(match) |
| m.oxm_list.append(ofp.oxm.in_port(of_port)) |
| request = ofp.message.flow_add( |
| table_id=test_param_get("table", 0), |
| cookie=42, |
| match=m, |
| 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, []) |
| |
| |
| def buildIgmp(payload): |
| pkt = pkt = IGMPv3.fixup(scapy.Ether() / scapy.IP() / payload) |
| if len(pkt) < 60: |
| pad_len = 60 - len(pkt) |
| pad = scapy.scapy.layers.l2.Padding() |
| pad.load = '\x00' * pad_len |
| pkt = pkt / pad |
| return 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 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 IGMPQueryPacketOut(base_tests.SimpleDataPlane): |
| """Verify sending multicast membership queries down to onu_ports""" |
| |
| def runTest(self): |
| logging.info("Running IGMP query packet out") |
| |
| igmp = IGMPv3() # by default this is a query |
| pkt = buildIgmp(igmp) |
| |
| msg = ofp.message.packet_out( |
| in_port=ofp.OFPP_CONTROLLER, |
| actions=[ofp.action.output(port=onu_port)], |
| buffer_id=ofp.OFP_NO_BUFFER, |
| data=str(pkt)) |
| |
| self.controller.message_send(msg) |
| |
| rv = self.controller.message_send(msg) |
| self.assertTrue(rv == 0, "Error sending put message") |
| verify_no_errors(self.controller) |
| |
| verify_packet(self, pkt, onu_port) |
| |
| |
| class TestMeter(base_tests.SimpleDataPlane): |
| |
| def runTest(self): |
| logging.info("Running Meter tests") |
| dropMeterBand = ofp.meter_band.drop(rate=640) |
| 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 |
| # for i in range(1,400): |
| # 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)) |
| if device_type == "cpqd": |
| match.oxm_list.append(ofp.oxm.vlan_vid(value=ofp.OFPVID_NONE)) |
| 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) |
| ] |
| else: # pmc, normal |
| 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)) |
| actions = [ |
| 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) |
| ] |
| |
| request = ofp.message.flow_add( |
| table_id=test_param_get("table", 0), |
| cookie=42, |
| match=match, |
| instructions=[ofp.instruction.apply_actions(actions=actions)], |
| buffer_id=ofp.OFP_NO_BUFFER, |
| priority=1000) |
| |
| logging.info("Inserting flow tagging upstream") |
| self.controller.message_send(request) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| # 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) |
| verify_no_errors(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) |
| if device_type == 'pmc': |
| outPkt = simple_udp_packet(pktlen=104, dl_vlan_enable=True, vlan_vid=0, vlan_pcp=0) |
| else: # "normal", "cpqd"" |
| outPkt = simple_udp_packet(pktlen=100) |
| |
| # 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.pop_vlan(), 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(10) |
| |
| inPkt = simple_udp_packet(pktlen=104, dl_vlan_enable=True, |
| vlan_vid=vlan_id, vlan_pcp=0, dl_vlan_cfi=0, eth_dst="01:01:11:12:11:12") |
| 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(10) |
| |
| self.dataplane.send(olt_port, str(inPkt)) |
| verify_packet(self, outPkt, onu_port2) |
| verify_packet(self, outPkt, onu_port) |
| # verify_packets(self, outPkt, [onu_port,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 TestGroupModForwarding(base_tests.SimpleDataPlane): |
| |
| def runTest(self): |
| logging.info("Running datapath forwarding tests for group mod") |
| 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, onu_port2]) |
| |
| 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(10) |
| |
| inPkt = simple_udp_packet(pktlen=104, dl_vlan_enable=True, |
| vlan_vid=vlan_id, vlan_pcp=0, dl_vlan_cfi=0, eth_dst="01:01:11:12:11:12") |
| outPkt = inPkt |
| self.dataplane.send(olt_port, str(inPkt)) |
| verify_packet(self, outPkt, onu_port) |
| verify_packet(self, outPkt, onu_port2) |
| |
| # Now remove onu port 1 from the group and test that the input packet is no longer forwarded to onu port 1 |
| group_mod = createAllGroupMod(test_group_id, ports=[onu_port2]) |
| self.controller.message_send(group_mod) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| time.sleep(10) |
| self.dataplane.send(olt_port, str(inPkt)) |
| verify_no_packet(self, outPkt, onu_port) |
| verify_packet(self, outPkt, onu_port2) |
| |
| # Now remove all ports in the group and test that the input packet is no longer forwarded to any port |
| group_mod = createAllGroupMod(test_group_id, ports=[]) |
| self.controller.message_send(group_mod) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| time.sleep(10) |
| self.dataplane.send(olt_port, str(inPkt)) |
| verify_packets(self, outPkt, []) |
| |
| |
| 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) |
| |
| # upstream |
| self.dataplane.send(onu_port, str(inPkt)) |
| verify_packet(self, inPkt, olt_port) |
| |
| # downstream |
| self.dataplane.send(olt_port, str(inPkt)) |
| verify_packet(self, inPkt, onu_port) |
| |
| # clean up the test |
| delete_all_flows(self.controller) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| class RemoveRuleTest(base_tests.SimpleDataPlane): |
| |
| def runTest(self): |
| logging.info("Testing Rule removal") |
| delete_all_flows(self.controller) |
| processEapolRule(self, onu_port) |
| |
| #wait for the rule to settle |
| time.sleep(3) |
| |
| installDoubleTaggingRules(1, 2, self.controller) |
| |
| #wait for the rules to settle |
| time.sleep(3) |
| |
| stats = get_flow_stats(self, ofp.match()) |
| |
| self.assertTrue(len(stats) == 5, \ |
| "Wrong number of rules reports; reported %s, expected 5\n\n %s" % (len(stats), stats)) |
| |
| processEapolRule(self, onu_port, install = False) |
| time.sleep(3) |
| |
| stats = get_flow_stats(self, ofp.match()) |
| |
| self.assertTrue(len(stats) == 4, \ |
| "Wrong number of rules reports; reported %s, expected 4\n\n %s" % (len(stats), stats)) |
| |
| logging.info(stats) |
| |
| |
| class MultipleDoubleTaggingForwarding(base_tests.SimpleDataPlane): |
| |
| def runTests(self): |
| logging.info("Testing multiple Q-in-Q rules") |
| pass |
| |
| |
| class DoubleVlanTest(base_tests.SimpleDataPlane): |
| |
| def runTest(self): |
| logging.info("Running double vlan tests") |
| delete_all_flows(self.controller) |
| |
| c_vlan_id = 100 |
| s_vlan_id = 102 |
| |
| installDoubleTaggingRules(s_vlan_id, c_vlan_id, self.controller) |
| |
| # It takes some time for flows to propagate down to the data plane |
| time.sleep(10) |
| |
| # Test packet flows |
| testPacketFlow(self, c_vlan_id, s_vlan_id) |
| |
| # clean up the test |
| delete_all_flows(self.controller) |
| do_barrier(self.controller) |
| verify_no_errors(self.controller) |
| |
| |
| class TestCyclingDoubleVlan(base_tests.SimpleDataPlane): |
| """Cycle through vlans and test traffic flow""" |
| |
| def runTest(self): |
| logging.info("Running cycling vlan test") |
| |
| for stag in xrange(2, 4000, 100): |
| for ctag in xrange(2, 4000, 100): |
| delete_all_flows(self.controller) |
| time.sleep(5) |
| installDoubleTaggingRules(stag, ctag, self.controller) |
| time.sleep(5) |
| testPacketFlow(self, ctag, stag) |
| |
| def processEapolRule(test, in_port, install = True): |
| match = ofp.match() |
| match.oxm_list.append(ofp.oxm.eth_type(0x888e)) |
| match.oxm_list.append(ofp.oxm.in_port(in_port)) |
| if install: |
| 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) |
| else: |
| request = ofp.message.flow_delete( |
| 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("%s flow sending matching packets to controller" % "Install" if install else "Remove") |
| test.controller.message_send(request) |
| do_barrier(test.controller) |
| |
| def testPacketFlow(test, c_vlan_id, s_vlan_id): |
| |
| incorrectTagPkt = simple_udp_packet(pktlen=100, dl_vlan_enable=True, vlan_vid=100, vlan_pcp=1) |
| zeroTaggedPkt = simple_udp_packet(pktlen=100, dl_vlan_enable=True, vlan_vid=0, vlan_pcp=0) |
| untaggedPkt = simple_udp_packet(pktlen=96) |
| |
| upstreamDoubleTaggedPkt = double_vlan_udp_packet(pktlen=104, dl_vlan_enable=True, |
| c_vlan_vid=c_vlan_id, |
| s_vlan_vid=s_vlan_id, |
| c_vlan_pcp=0, s_vlan_pcp=0) |
| |
| logging.info("Testing s-tag %d, c-tag %d" % (s_vlan_id, c_vlan_id)) |
| |
| # test upstream untagged packet got double tag at OLT |
| test.dataplane.send(onu_port, str(zeroTaggedPkt)) |
| verify_packet(test, upstreamDoubleTaggedPkt, olt_port) |
| |
| # test downstream doubletagged packet got untagged at ONU |
| test.dataplane.send(olt_port, str(upstreamDoubleTaggedPkt)) |
| if device_type == "pmc": |
| verify_packet(test, zeroTaggedPkt, onu_port) |
| else: |
| verify_packet(test, untaggedPkt, onu_port) |
| |
| # test upstream doubletagged packet got dropped |
| test.dataplane.send(onu_port, str(upstreamDoubleTaggedPkt)) |
| verify_no_packet(test, upstreamDoubleTaggedPkt, olt_port) |
| |
| # test downstream untagged packet got dropped at ONU |
| test.dataplane.send(olt_port, str(untaggedPkt)) |
| verify_no_packet(test, untaggedPkt, onu_port) |
| |
| # test upstream icorrectly tagged packet; should get dropped |
| test.dataplane.send(onu_port, str(incorrectTagPkt)) |
| verify_no_packet(test, upstreamDoubleTaggedPkt, olt_port) |
| |
| |
| def installDoubleTaggingRules(s_vlan_id, c_vlan_id, controller, cookie=42): |
| |
| # upstream flow rule |
| match = ofp.match() |
| match.oxm_list.append(ofp.oxm.in_port(onu_port)) |
| if device_type == "cpqd": |
| match.oxm_list.append(ofp.oxm.vlan_vid(value=ofp.OFPVID_NONE)) |
| actions = [ |
| ofp.action.push_vlan(ethertype=0x8100), |
| ofp.action.set_field(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | c_vlan_id)), |
| ofp.action.set_field(ofp.oxm.vlan_pcp(0)) |
| ] |
| else: # "pmc", "normal" |
| match.oxm_list.append(ofp.oxm.vlan_vid(value=ofp.OFPVID_PRESENT)) |
| match.oxm_list.append(ofp.oxm.vlan_pcp(value=0)) |
| actions = [ |
| ofp.action.set_field(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | c_vlan_id)) |
| ] |
| cookie += 1 |
| |
| # push inner vlan (c-vlan) for upstream |
| request = ofp.message.flow_add( |
| table_id=test_param_get("table", 0), |
| cookie=cookie, |
| match=match, |
| instructions=[ |
| ofp.instruction.apply_actions(actions=actions), |
| ofp.instruction.goto_table(1)], |
| buffer_id=ofp.OFP_NO_BUFFER, |
| priority=1000) |
| |
| controller.message_send(request) |
| do_barrier(controller) |
| verify_no_errors(controller) |
| |
| # push outer vlan (s-vlan) for upstream |
| match = ofp.match() |
| match.oxm_list.append(ofp.oxm.in_port(onu_port)) |
| match.oxm_list.append(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | c_vlan_id)) |
| match.oxm_list.append(ofp.oxm.vlan_pcp(0)) |
| cookie += 1 |
| |
| request = ofp.message.flow_add( |
| table_id=test_param_get("table", 1), |
| cookie=cookie, |
| 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 | s_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) |
| |
| controller.message_send(request) |
| do_barrier(controller) |
| verify_no_errors(controller) |
| cookie += 1 |
| |
| # strip outer vlan (s-vlan) for downstream |
| match = ofp.match() |
| match.oxm_list.append(ofp.oxm.in_port(olt_port)) |
| match.oxm_list.append(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | s_vlan_id)) |
| match.oxm_list.append(ofp.oxm.vlan_pcp(0)) |
| request = ofp.message.flow_add( |
| table_id=test_param_get("table", 0), |
| cookie=cookie, |
| match=match, |
| instructions=[ |
| ofp.instruction.apply_actions( |
| actions=[ofp.action.pop_vlan()]), |
| ofp.instruction.goto_table(1)], |
| buffer_id=ofp.OFP_NO_BUFFER, |
| priority=1000) |
| |
| controller.message_send(request) |
| do_barrier(controller) |
| verify_no_errors(controller) |
| |
| # rewrite inner vlan (c-vlan) to default (0) for downstream |
| match = ofp.match() |
| match.oxm_list.append(ofp.oxm.in_port(olt_port)) |
| match.oxm_list.append(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | c_vlan_id)) |
| match.oxm_list.append(ofp.oxm.vlan_pcp(0)) |
| cookie += 1 |
| |
| request = ofp.message.flow_add( |
| table_id=test_param_get("table", 1), |
| cookie=cookie, |
| 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) |
| |
| controller.message_send(request) |
| do_barrier(controller) |
| verify_no_errors(controller) |