def runTest(self): pkt = simple_ip_packet(ip_src="192.168.1.1", ip_tos=10) exp_pkt = simple_ip_packet(ip_src="192.168.1.1", ip_tos=255) mask = Mask(exp_pkt) mask.set_do_not_care_scapy(IP, 'chksum') send_packet(self, (0, 1), pkt) verify_packets(self, mask, device_number=0, ports=[2])
def _build_tunnel_packet(outer_src_ip, outer_dst_ip, inner_packet=None): """Build the expected tunnel packet.""" if inner_packet is None: exp_pkt = testutils.simple_ip_packet( ip_src=outer_src_ip, ip_dst=outer_dst_ip, pktlen=20 ) else: exp_pkt = testutils.simple_ipv4ip_packet( ip_src=outer_src_ip, ip_dst=outer_dst_ip, inner_frame=inner_packet ) exp_pkt = mask.Mask(exp_pkt) exp_pkt.set_do_not_care_scapy(Ether, "dst") exp_pkt.set_do_not_care_scapy(Ether, "src") exp_pkt.set_do_not_care_scapy(IP, "ihl") exp_pkt.set_do_not_care_scapy(IP, "tos") exp_pkt.set_do_not_care_scapy(IP, "len") exp_pkt.set_do_not_care_scapy(IP, "id") exp_pkt.set_do_not_care_scapy(IP, "flags") exp_pkt.set_do_not_care_scapy(IP, "frag") exp_pkt.set_do_not_care_scapy(IP, "ttl") exp_pkt.set_do_not_care_scapy(IP, "proto") exp_pkt.set_do_not_care_scapy(IP, "chksum") if inner_packet is None: exp_pkt.set_ignore_extra_bytes() return exp_pkt
def build_encapsulated_packet(rand_selected_interface, ptfadapter, rand_selected_dut, tunnel_traffic_monitor): """Build the encapsulated packet sent from T1 to ToR.""" tor = rand_selected_dut _, server_ips = rand_selected_interface server_ipv4 = server_ips["server_ipv4"].split("/")[0] config_facts = tor.get_running_config_facts() try: peer_ipv4_address = [_["address_ipv4"] for _ in config_facts["PEER_SWITCH"].values()][0] except IndexError: raise ValueError("Failed to get peer ToR address from CONFIG_DB") tor_ipv4_address = [_ for _ in config_facts["LOOPBACK_INTERFACE"]["Loopback0"] if is_ipv4_address(_.split("/")[0])][0] tor_ipv4_address = tor_ipv4_address.split("/")[0] inner_dscp = random.choice(range(0, 33)) inner_ttl = random.choice(range(3, 65)) inner_packet = testutils.simple_ip_packet( ip_src="1.1.1.1", ip_dst=server_ipv4, ip_dscp=inner_dscp, ip_ttl=inner_ttl )[IP] packet = testutils.simple_ipv4ip_packet( eth_dst=tor.facts["router_mac"], eth_src=ptfadapter.dataplane.get_mac(0, 0), ip_src=peer_ipv4_address, ip_dst=tor_ipv4_address, ip_dscp=inner_dscp, ip_ttl=255, inner_frame=inner_packet ) logging.info("the encapsulated packet to send:\n%s", tunnel_traffic_monitor._dump_show_str(packet)) return packet
def test_drop_ip_packet_with_wrong_0xffff_chksum(self, duthost, ptfadapter, common_param): # GIVEN a random normal ip packet, and manually modify checksum to 0xffff # WHEN send the packet to DUT # THEN DUT should drop it and add drop count (peer_ip_ifaces_pair, ptf_port_idx, pc_ports_map, ptf_indices) = common_param pkt = testutils.simple_ip_packet( eth_dst=duthost.facts["router_mac"], eth_src=ptfadapter.dataplane.get_mac(0, ptf_port_idx), ip_src=peer_ip_ifaces_pair[0][0], ip_dst=peer_ip_ifaces_pair[1][0]) pkt.payload.chksum = 0xffff out_ifaces = TestIPPacket.parse_interfaces( duthost.command("show ip route %s" % peer_ip_ifaces_pair[1][0])["stdout_lines"], pc_ports_map) duthost.command("portstat -c") ptfadapter.dataplane.flush() testutils.send(ptfadapter, ptf_port_idx, pkt, self.PKT_NUM) time.sleep(5) portstat_out = parse_portstat(duthost.command("portstat")["stdout_lines"]) rx_ok = int(portstat_out[peer_ip_ifaces_pair[0][1][0]]["rx_ok"].replace(",", "")) rx_drp = int(portstat_out[peer_ip_ifaces_pair[0][1][0]]["rx_drp"].replace(",", "")) tx_ok = TestIPPacket.sum_portstat_ifaces_counts(portstat_out, out_ifaces, "tx_ok") tx_drp = TestIPPacket.sum_portstat_ifaces_counts(portstat_out, out_ifaces, "tx_drp") pytest_assert(self.PKT_NUM_MIN <= rx_ok <= self.PKT_NUM_MAX, "rx_ok unexpected") pytest_assert(self.PKT_NUM_MIN <= rx_drp <= self.PKT_NUM_MAX, "rx_drp unexpected") pytest_assert(tx_ok <= self.PKT_NUM_ZERO, "tx_ok unexpected") pytest_assert(tx_drp <= self.PKT_NUM_ZERO, "tx_drp unexpected")
def test_non_routable_igmp_pkts(ptfadapter, duthost, setup, tx_dut_ports, pkt_fields, igmp_version, msg_type, ports_info): """ @summary: Verify IGMP non-routable packets dropped by DUT and L3 drop counter incremented """ # IGMP Types: # 0x11 = Membership Query # 0x12 = Version 1 Membership Report # 0x16 = Version 2 Membership Report # 0x17 = Leave Group # IP destination address according to the RFC 2236: # Message Type Destination Group # ------------ ----------------- # General Query ALL-SYSTEMS (224.0.0.1) # Group-Specific Query The group being queried # Membership Report The group being reported # Leave Message ALL-ROUTERS (224.0.0.2) # TODO: fix this workaround as of now current PTF and Scapy versions do not support creation of IGMP packets # Temporaly created hex of IGMP packet layer # Example how to get HEX of specific IGMP packets: # v3_membership_query = IGMPv3(type=0x11, mrcode=0, chksum=None)/scapy.contrib.igmpv3.IGMPv3mq(gaddr="224.0.0.1", # srcaddrs=["172.16.11.1", "10.0.0.59"], qrv=1, qqic=125, numsrc=2) # gr_obj = scapy.contrib.igmpv3.IGMPv3gr(rtype=1, auxdlen=0, maddr="224.2.2.4", numsrc=2, srcaddrs=["172.16.11.1", # "10.0.0.59"]).build() # v3_membership_report = IGMPv3(type=0x22, mrcode=0, chksum=None)/scapy.contrib.igmpv3.IGMPv3mr(res2=0x00, numgrp=1, # records=[gr_obj]).build() # The rest packets are build like "simple_igmp_packet" function from PTF testutils.py ethernet_dst = {"membership_query": "01:00:5e:00:00:01", "membership_report": "01:00:5e:02:02:04", "leave_group": "01:00:5e:00:00:02"} ip_dst = {"membership_query": "224.0.0.1", "membership_report": "224.2.2.4", "leave_group": "224.0.0.2"} igmp_types = {"v1": {"membership_query": "\x11\x00\x0e\xfe\xe0\x00\x00\x01", "membership_report": "\x12\x00\x0b\xf9\xe0\x02\x02\x04"}, "v2": {"membership_report": "\x16\x00\x07\xf9\xe0\x02\x02\x04", "leave_group": "\x17\x00\x08\xfd\xe0\x00\x00\x02"}, "v3": {"membership_query": "\x11\x00L2\xe0\x00\x00\x01\x01}\x00\x02\xac\x10\x0b\x01\n\x00\x00;", "membership_report": "\"\x009\xa9\x00\x00\x00\x01\x01\x00\x00\x02\xe0\x02\x02\x04\xac\x10\x0b\x01\n\x00\x00;"} } log_pkt_params(ports_info["dut_iface"], ethernet_dst[msg_type], ports_info["src_mac"], ip_dst[msg_type], pkt_fields["ipv4_src"]) pkt = testutils.simple_ip_packet( eth_dst=ethernet_dst[msg_type], # DUT port eth_src=ports_info["src_mac"], # PTF port ip_src=pkt_fields["ipv4_src"], # PTF source ip_dst=ip_dst[msg_type], ip_ttl=1, ) del pkt[testutils.scapy.scapy.all.Raw] pkt = pkt / igmp_types[igmp_version][msg_type] do_test("L3", pkt, ptfadapter, duthost, ports_info, setup["dut_to_ptf_port_map"].values(), tx_dut_ports)
def _get_simple_ip_packet(src_mac, dst_mac, src_ip, dst_ip): pkt = testutils.simple_ip_packet(eth_src=src_mac, eth_dst=dst_mac, ip_src=src_ip, ip_dst=dst_ip) logging.info( "Generated simple IP packet (SMAC=%s, DMAC=%s, SIP=%s, DIP=%s)", src_mac, dst_mac, src_ip, dst_ip) return pkt
def runTest(self): target = gc.Target(device_id=dev_id, pipe_id=0xffff) port_meta = self.bfrt_info.table_get("$PORT_METADATA") pass_one = self.bfrt_info.table_get("pass_one") port = random.choice(swports) port_meta_values = [random.getrandbits(32), random.getrandbits(32)] try: # Write values into the Port Metadata table which will be assigned # to the packet. k = port_meta.make_key( [gc.KeyTuple('ig_intr_md.ingress_port', port)]) d = port_meta.make_data([ gc.DataTuple('f1', port_meta_values[0]), gc.DataTuple('f2', port_meta_values[1]) ]) port_meta.entry_add(target, [k], [d]) # Install an entry to match those metadata values in the "pass_one" # table with an action that will NOT perform a resubmit. k = pass_one.make_key([ gc.KeyTuple("port", port), gc.KeyTuple("f1", port_meta_values[0]), gc.KeyTuple("f2", port_meta_values[1]) ]) d = pass_one.make_data([], "SwitchIngress.no_resub") pass_one.entry_add(target, [k], [d]) # Since the packet will not perform a resubmit operation the header # modifications on the first (and only) pass of the packet through # the ingress pipe will be kept, so expect the MAC addresses to be # modified. pkt_in = testutils.simple_ip_packet() pkt_out = testutils.simple_ip_packet(eth_dst='00:00:00:00:00:01', eth_src='00:00:00:00:00:00') testutils.send_packet(self, port, pkt_in) testutils.verify_packet(self, pkt_out, port) finally: port_meta.entry_del(target) pass_one.entry_del(target)
def test_forward_ip_packet_recomputed_0xffff_chksum(self, duthost, ptfadapter, common_param): # GIVEN a ip packet, after forwarded(ttl-1) by DUT, # it's checksum will be 0xffff after wrongly incrementally recomputed # ref to https://datatracker.ietf.org/doc/html/rfc1624 # HC' = HC(0xff00) + m(0x7a2f) + ~m'(~0x792f)= 0xffff # WHEN send the packet to DUT # THEN DUT recompute new checksum correctly and forward packet as expected. (peer_ip_ifaces_pair, ptf_port_idx, pc_ports_map, ptf_indices) = common_param pkt = testutils.simple_ip_packet( eth_dst=duthost.facts["router_mac"], eth_src=ptfadapter.dataplane.get_mac(0, ptf_port_idx), pktlen=1246, ip_src="10.250.40.40", ip_dst="10.156.190.188", ip_proto=47, ip_tos=0x84, ip_id=0, ip_ihl=5, ip_ttl=122, ) pkt.payload.flags = 2 exp_pkt = pkt.copy() exp_pkt.payload.ttl = 121 exp_pkt.payload.chksum = 0x0001 exp_pkt = mask.Mask(exp_pkt) exp_pkt.set_do_not_care_scapy(packet.Ether, 'dst') exp_pkt.set_do_not_care_scapy(packet.Ether, 'src') out_ifaces = TestIPPacket.parse_interfaces(duthost.command("show ip route 10.156.190.188")["stdout_lines"], pc_ports_map) out_ptf_indices = map(lambda iface: ptf_indices[iface], out_ifaces) duthost.command("portstat -c") ptfadapter.dataplane.flush() testutils.send(ptfadapter, ptf_port_idx, pkt, self.PKT_NUM) time.sleep(5) match_cnt = testutils.count_matched_packets_all_ports(ptfadapter, exp_pkt, ports=out_ptf_indices) portstat_out = parse_portstat(duthost.command("portstat")["stdout_lines"]) rx_ok = int(portstat_out[peer_ip_ifaces_pair[0][1][0]]["rx_ok"].replace(",", "")) rx_drp = int(portstat_out[peer_ip_ifaces_pair[0][1][0]]["rx_drp"].replace(",", "")) tx_ok = TestIPPacket.sum_portstat_ifaces_counts(portstat_out, out_ifaces, "tx_ok") tx_drp = TestIPPacket.sum_portstat_ifaces_counts(portstat_out, out_ifaces, "tx_drp") pytest_assert(match_cnt == self.PKT_NUM, "Packet lost") pytest_assert(self.PKT_NUM_MIN <= rx_ok <= self.PKT_NUM_MAX, "rx_ok unexpected") pytest_assert(self.PKT_NUM_MIN <= tx_ok <= self.PKT_NUM_MAX, "tx_ok unexpected") pytest_assert(rx_drp <= self.PKT_NUM_ZERO, "rx_drp unexpected") pytest_assert(tx_drp <= self.PKT_NUM_ZERO, "tx_drp unexpected")
def test_forward_ip_packet_with_0xffff_chksum_drop(self, duthost, ptfadapter, common_param): # GIVEN a ip packet with checksum 0x0000(compute from scratch) # WHEN manually set checksum as 0xffff and send the packet to DUT # THEN DUT should drop packet with 0xffff and add drop count (peer_ip_ifaces_pair, ptf_port_idx, pc_ports_map, ptf_indices) = common_param pkt = testutils.simple_ip_packet( eth_dst=duthost.facts["router_mac"], eth_src=ptfadapter.dataplane.get_mac(0, ptf_port_idx), pktlen=1246, ip_src="10.250.136.195", ip_dst="10.156.94.34", ip_proto=47, ip_tos=0x84, ip_id=0, ip_ihl=5, ip_ttl=121, ) pkt.payload.flags = 2 pkt.payload.chksum = 0xffff exp_pkt = pkt.copy() exp_pkt.payload.ttl = 120 exp_pkt.payload.chksum = 0x0100 exp_pkt = mask.Mask(exp_pkt) exp_pkt.set_do_not_care_scapy(packet.Ether, 'dst') exp_pkt.set_do_not_care_scapy(packet.Ether, 'src') out_ifaces = TestIPPacket.parse_interfaces(duthost.command("show ip route 10.156.94.34")["stdout_lines"], pc_ports_map) out_ptf_indices = map(lambda iface: ptf_indices[iface], out_ifaces) duthost.command("portstat -c") ptfadapter.dataplane.flush() testutils.send(ptfadapter, ptf_port_idx, pkt, self.PKT_NUM) time.sleep(5) match_cnt = testutils.count_matched_packets_all_ports(ptfadapter, exp_pkt, ports=out_ptf_indices) portstat_out = parse_portstat(duthost.command("portstat")["stdout_lines"]) rx_ok = int(portstat_out[peer_ip_ifaces_pair[0][1][0]]["rx_ok"].replace(",", "")) rx_drp = int(portstat_out[peer_ip_ifaces_pair[0][1][0]]["rx_drp"].replace(",", "")) tx_ok = TestIPPacket.sum_portstat_ifaces_counts(portstat_out, out_ifaces, "tx_ok") tx_drp = TestIPPacket.sum_portstat_ifaces_counts(portstat_out, out_ifaces, "tx_drp") pytest_assert(match_cnt == 0, "Packet not dropped") pytest_assert(self.PKT_NUM_MIN <= rx_ok <= self.PKT_NUM_MAX, "rx_ok unexpected") pytest_assert(self.PKT_NUM_MIN <= rx_drp <= self.PKT_NUM_MAX, "rx_drp unexpected") pytest_assert(tx_drp <= self.PKT_NUM_ZERO, "tx_drp unexpected") pytest_assert(tx_ok <= self.PKT_NUM_ZERO, "tx_ok unexpected")
def build_packet_to_server(duthost, ptfadapter, target_server_ip): """Build packet and expected mask packet destinated to server.""" pkt_dscp = random.choice(range(0, 33)) pkt_ttl = random.choice(range(3, 65)) pkt = testutils.simple_ip_packet(eth_dst=duthost.facts["router_mac"], eth_src=ptfadapter.dataplane.get_mac( 0, 0), ip_src="1.1.1.1", ip_dst=target_server_ip, ip_dscp=pkt_dscp, ip_ttl=pkt_ttl) logging.info("the packet destinated to server %s:\n%s", target_server_ip, dump_scapy_packet_show_output(pkt)) exp_pkt = mask.Mask(pkt) exp_pkt.set_do_not_care_scapy(scapyall.Ether, "dst") exp_pkt.set_do_not_care_scapy(scapyall.Ether, "src") exp_pkt.set_do_not_care_scapy(scapyall.IP, "tos") exp_pkt.set_do_not_care_scapy(scapyall.IP, "ttl") exp_pkt.set_do_not_care_scapy(scapyall.IP, "chksum") return pkt, exp_pkt
def test_forward_normal_ip_packet(self, duthost, ptfadapter, common_param): # GIVEN a random normal ip packet # WHEN send the packet to DUT # THEN DUT should forward it as normal ip packet, nothing change but ttl-1 (peer_ip_ifaces_pair, ptf_port_idx, pc_ports_map, ptf_indices) = common_param pkt = testutils.simple_ip_packet( eth_dst=duthost.facts["router_mac"], eth_src=ptfadapter.dataplane.get_mac(0, ptf_port_idx), ip_src=peer_ip_ifaces_pair[0][0], ip_dst=peer_ip_ifaces_pair[1][0]) exp_pkt = pkt.copy() exp_pkt.payload.ttl = pkt.payload.ttl - 1 exp_pkt = mask.Mask(exp_pkt) exp_pkt.set_do_not_care_scapy(packet.Ether, 'dst') exp_pkt.set_do_not_care_scapy(packet.Ether, 'src') out_ifaces = TestIPPacket.parse_interfaces( duthost.command("show ip route %s" % peer_ip_ifaces_pair[1][0])["stdout_lines"], pc_ports_map) out_ptf_indices = map(lambda iface: ptf_indices[iface], out_ifaces) duthost.command("portstat -c") ptfadapter.dataplane.flush() testutils.send(ptfadapter, ptf_port_idx, pkt, self.PKT_NUM) time.sleep(5) match_cnt = testutils.count_matched_packets_all_ports(ptfadapter, exp_pkt, ports=out_ptf_indices) portstat_out = parse_portstat(duthost.command("portstat")["stdout_lines"]) rx_ok = int(portstat_out[peer_ip_ifaces_pair[0][1][0]]["rx_ok"].replace(",", "")) rx_drp = int(portstat_out[peer_ip_ifaces_pair[0][1][0]]["rx_drp"].replace(",", "")) tx_ok = TestIPPacket.sum_portstat_ifaces_counts(portstat_out, out_ifaces, "tx_ok") tx_drp = TestIPPacket.sum_portstat_ifaces_counts(portstat_out, out_ifaces, "tx_drp") pytest_assert(match_cnt == self.PKT_NUM, "Packet lost") pytest_assert(self.PKT_NUM_MIN <= rx_ok <= self.PKT_NUM_MAX, "rx_ok unexpected") pytest_assert(self.PKT_NUM_MIN <= tx_ok <= self.PKT_NUM_MAX, "tx_ok unexpected") pytest_assert(rx_drp <= self.PKT_NUM_ZERO, "rx_drp unexpected") pytest_assert(tx_drp <= self.PKT_NUM_ZERO, "tx_drp unexpected")
def build_non_encapsulated_ip_packet(rand_selected_interface, ptfadapter, rand_selected_dut, tunnel_traffic_monitor): """ Build the regular (non encapsulated) packet to be sent from T1 to ToR. """ tor = rand_selected_dut _, server_ips = rand_selected_interface server_ipv4 = server_ips["server_ipv4"].split("/")[0] config_facts = tor.get_running_config_facts() try: peer_ipv4_address = [ dut_name["address_ipv4"] for dut_name in config_facts["PEER_SWITCH"].values() ][0] except IndexError: raise ValueError("Failed to get peer ToR address from CONFIG_DB") tor_ipv4_address = [ addr for addr in config_facts["LOOPBACK_INTERFACE"]["Loopback0"] if is_ipv4_address(addr.split("/")[0]) ][0] tor_ipv4_address = tor_ipv4_address.split("/")[0] dscp = random.choice(range(0, 33)) ttl = random.choice(range(3, 65)) ecn = random.choice(range(0, 3)) packet = testutils.simple_ip_packet(eth_dst=tor.facts["router_mac"], eth_src=ptfadapter.dataplane.get_mac( 0, 0), ip_src="1.1.1.1", ip_dst=server_ipv4, ip_dscp=dscp, ip_ecn=ecn, ip_ttl=ttl) logging.info("the regular IP packet to send:\n%s", dump_scapy_packet_show_output(packet)) return packet
def generate_packet(src_ip, dst_ip, dst_mac): """ Build ipv4 and ipv6 packets/expected_packets for testing. """ if ipaddress.ip_network(unicode(src_ip), False).version == 4: pkt = testutils.simple_ip_packet(eth_dst=dst_mac, ip_src=src_ip, ip_dst=dst_ip) exp_pkt = Mask(pkt) exp_pkt.set_do_not_care_scapy(scapy.Ether, "dst") exp_pkt.set_do_not_care_scapy(scapy.Ether, "src") exp_pkt.set_do_not_care_scapy(scapy.IP, "ttl") exp_pkt.set_do_not_care_scapy(scapy.IP, "chksum") else: pkt = testutils.simple_tcpv6_packet(eth_dst=dst_mac, ipv6_src=src_ip, ipv6_dst=dst_ip) exp_pkt = Mask(pkt) exp_pkt.set_do_not_care_scapy(scapy.Ether, "dst") exp_pkt.set_do_not_care_scapy(scapy.Ether, "src") exp_pkt.set_do_not_care_scapy(scapy.IPv6, "hlim") return pkt, exp_pkt
def _get_simple_ip_packet(rx_port, src_ip, dst_ip): dst_mac = duthost.get_dut_iface_mac( testbed_params["physical_port_map"][rx_port]) src_mac = "DE:AD:BE:EF:12:34" # send tagged packet for t0-backend whose vlan mode is tagged enable_vlan = rx_port in testbed_params[ "vlan_ports"] and testbed_params["vlan_interface"][ "type"] == "tagged" packet_params = dict(eth_src=src_mac, eth_dst=dst_mac, ip_src=src_ip, ip_dst=dst_ip) if enable_vlan: packet_params["dl_vlan_enable"] = enable_vlan packet_params["vlan_vid"] = int( testbed_params["vlan_interface"]["attachto"].lstrip("Vlan")) pkt = testutils.simple_ip_packet(**packet_params) logging.info( "Generated simple IP packet (SMAC=%s, DMAC=%s, SIP=%s, DIP=%s)", src_mac, dst_mac, src_ip, dst_ip) return pkt
def test_non_routable_igmp_pkts(do_test, ptfadapter, duthost, setup, fanouthost, tx_dut_ports, pkt_fields, igmp_version, msg_type, ports_info): """ @summary: Create an IGMP non-routable packets. """ # IGMP Types: # 0x11 = Membership Query # 0x12 = Version 1 Membership Report # 0x16 = Version 2 Membership Report # 0x17 = Leave Group # IP destination address according to the RFC 2236: # Message Type Destination Group # ------------ ----------------- # General Query ALL-SYSTEMS (224.0.0.1) # Group-Specific Query The group being queried # Membership Report The group being reported # Leave Message ALL-ROUTERS (224.0.0.2) # TODO: fix this workaround as of now current PTF and Scapy versions do not support creation of IGMP packets # Temporaly created hex of IGMP packet layer by using scapy version 2.4.3. # Example how to get HEX of specific IGMP packets: # v3_membership_query = IGMPv3(type=0x11, mrcode=0, chksum=None)/scapy.contrib.igmpv3.IGMPv3mq(gaddr="224.0.0.1", # srcaddrs=["172.16.11.1", "10.0.0.59"], qrv=1, qqic=125, numsrc=2) # gr_obj = scapy.contrib.igmpv3.IGMPv3gr(rtype=1, auxdlen=0, maddr="224.2.2.4", numsrc=2, srcaddrs=["172.16.11.1", # "10.0.0.59"]).build() # v3_membership_report = IGMPv3(type=0x22, mrcode=0, chksum=None)/scapy.contrib.igmpv3.IGMPv3mr(res2=0x00, numgrp=1, # records=[gr_obj]).build() # The rest packets are build like "simple_igmp_packet" function from PTF testutils.py # FIXME: Need some sort of configuration for EOS and SONiC fanout hosts to # not drop IGMP packets before they reach the DUT if not fanouthost: pytest.skip("Test case requires explicit fanout support") from scapy.contrib.igmp import IGMP Ether = testutils.scapy.Ether IP = testutils.scapy.IP if "vlan" in tx_dut_ports[ports_info["dut_iface"]].lower( ) and msg_type == "membership_report": pytest.skip("Test case is not supported on VLAN interface") igmp_proto = 0x02 multicast_group_addr = "224.1.1.1" ethernet_dst = "01:00:5e:01:01:01" ip_dst = { "general_query": "224.0.0.1", "membership_report": multicast_group_addr } igmp_types = { "v1": { "general_query": IGMP(type=0x11, gaddr="224.0.0.1"), "membership_report": IGMP(type=0x12, gaddr=multicast_group_addr) }, "v2": { "membership_report": IGMP(type=0x16, gaddr=multicast_group_addr), "leave_group": IGMP(type=0x17, gaddr=multicast_group_addr) }, "v3": { "general_query": "\x11\x00L2\xe0\x00\x00\x01\x01}\x00\x02\xac\x10\x0b\x01\n\x00\x00;", "membership_report": "\"\x009\xa9\x00\x00\x00\x01\x01\x00\x00\x02\xe0\x02\x02\x04\xac\x10\x0b\x01\n\x00\x00;" } } if igmp_version == "v3": pkt = testutils.simple_ip_packet(eth_dst=ethernet_dst, eth_src=ports_info["src_mac"], ip_src=pkt_fields["ipv4_src"], ip_dst=ip_dst[msg_type], ip_ttl=1, ip_proto=igmp_proto) del pkt["Raw"] pkt = pkt / igmp_types[igmp_version][msg_type] else: eth_layer = Ether(src=ports_info["src_mac"], dst=ethernet_dst) ip_layer = IP(src=pkt_fields["ipv4_src"], ) igmp_layer = igmp_types[igmp_version][msg_type] assert igmp_layer.igmpize(ip=ip_layer, ether=eth_layer), "Can't create IGMP packet" pkt = eth_layer / ip_layer / igmp_layer log_pkt_params(ports_info["dut_iface"], ethernet_dst, ports_info["src_mac"], pkt.getlayer("IP").dst, pkt_fields["ipv4_src"]) do_test("L3", pkt, ptfadapter, duthost, ports_info, setup["dut_to_ptf_port_map"].values(), tx_dut_ports)
def runTest(self): target = gc.Target(device_id=dev_id, pipe_id=0xffff) port_meta = self.bfrt_info.table_get("$PORT_METADATA") pass_one = self.bfrt_info.table_get("pass_one") pass_two_a = self.bfrt_info.table_get("pass_two_type_a") pass_two_b = self.bfrt_info.table_get("pass_two_type_b") pass_two_c = self.bfrt_info.table_get("pass_two_type_c") port = random.choice(swports) port_meta_values = [random.getrandbits(32), random.getrandbits(32)] a_f1 = random.getrandbits(8) a_f2 = random.getrandbits(16) a_f3 = random.getrandbits(32) a_md = random.getrandbits(64) b_f1 = random.getrandbits(8) b_md = random.getrandbits(64) c_f1 = random.getrandbits(16) c_f2 = random.getrandbits(16) c_f3 = random.getrandbits(16) c_md = random.getrandbits(64) pkt = testutils.simple_ip_packet() tof1 = testutils.test_param_get('arch') == 'tofino' try: # Add a port metadata entry to assign the metadata used in the table # key for the pass_one table. k = port_meta.make_key( [gc.KeyTuple('ig_intr_md.ingress_port', port)]) d = port_meta.make_data([ gc.DataTuple('f1', port_meta_values[0]), gc.DataTuple('f2', port_meta_values[1]) ]) port_meta.entry_add(target, [k], [d]) # Add an entry to each of the pass two tables which validates the # metadata passed through the resubmit path. key_fields = [ gc.KeyTuple('md.a.f1', a_f1), gc.KeyTuple('md.a.f2', a_f2), gc.KeyTuple('md.a.f3', a_f3) ] if not tof1: key_fields.append(gc.KeyTuple('md.a.additional', a_md)) d = pass_two_a.make_data([], 'SwitchIngress.okay_a') pass_two_a.entry_add(target, [pass_two_a.make_key(key_fields)], [d]) key_fields = [gc.KeyTuple('md.b.f1', b_f1)] if not tof1: key_fields.append(gc.KeyTuple('md.b.additional', b_md)) d = pass_two_b.make_data([], 'SwitchIngress.okay_b') pass_two_b.entry_add(target, [pass_two_b.make_key(key_fields)], [d]) key_fields = [ gc.KeyTuple('md.c.f1', c_f1), gc.KeyTuple('md.c.f2', c_f2), gc.KeyTuple('md.c.f3', c_f3) ] if not tof1: key_fields.append(gc.KeyTuple('md.c.additional', c_md)) d = pass_two_c.make_data([], 'SwitchIngress.okay_c') pass_two_c.entry_add(target, [pass_two_c.make_key(key_fields)], [d]) # Clear the counters to ensure we are starting in a known state # since other tests may have sent traffic which incremented them. self.clrCntrs() # Add an entry to the pass_one table to cause the packet to resubmit # with the first resubmit type. k = pass_one.make_key([ gc.KeyTuple("port", port), gc.KeyTuple("f1", port_meta_values[0]), gc.KeyTuple("f2", port_meta_values[1]) ]) d = pass_one.make_data([ gc.DataTuple('f1', a_f1), gc.DataTuple('f2', a_f2), gc.DataTuple('f3', a_f3), gc.DataTuple('more_data', a_md) ], "SwitchIngress.resub_a") pass_one.entry_add(target, [k], [d]) # Verify it works as expected. There should be one count at index 0 # from the first pass and one count at index 1 for a resubmit type A. testutils.send_packet(self, port, pkt) testutils.verify_packet(self, pkt, port) c1 = self.getCntr(0) c2 = self.getCntr(1) self.assertEqual(c1, 1) self.assertEqual(c2, 1) # Now modify the entry to use the next resubmit type and verify it # also works. d = pass_one.make_data( [gc.DataTuple('f1', b_f1), gc.DataTuple('more_data', b_md)], "SwitchIngress.resub_b") pass_one.entry_mod(target, [k], [d]) testutils.send_packet(self, port, pkt) testutils.verify_packet(self, pkt, port) c1 = self.getCntr(0) c2 = self.getCntr(2) self.assertEqual(c1, 2) self.assertEqual(c2, 1) # Modify it again to use the third resubmit type and verify. d = pass_one.make_data([ gc.DataTuple('f1', c_f1), gc.DataTuple('f2', c_f2), gc.DataTuple('f3', c_f3), gc.DataTuple('more_data', c_md) ], "SwitchIngress.resub_c") pass_one.entry_mod(target, [k], [d]) testutils.send_packet(self, port, pkt) testutils.verify_packet(self, pkt, port) c1 = self.getCntr(0) c2 = self.getCntr(3) self.assertEqual(c1, 3) self.assertEqual(c2, 1) finally: port_meta.entry_del(target) pass_one.entry_del(target) pass_two_a.entry_del(target) pass_two_b.entry_del(target) pass_two_c.entry_del(target)
def verify_upstream_traffic(host, ptfadapter, tbinfo, itfs, server_ip, pkt_num=100, drop=False): """ @summary: Helper function for verifying upstream packets @param host: The dut host @param ptfadapter: The ptfadapter fixture @param tbinfo: The tbinfo fixture @param ifts: The interface name on DUT @param server_ip: The IP address of server @param pkt_num: The number of packets to generete and tx @param drop: Packets are expected to be dropped if drop is True, and vice versa @return: No return value. An exception will be raised if verify fails. """ random_ip = generate_ip_through_default_route(host).split('/')[0] vlan_table = host.get_running_config_facts()['VLAN'] vlan_name = list(vlan_table.keys())[0] vlan_mac = host.get_dut_iface_mac(vlan_name) router_mac = host.facts['router_mac'] # Generate packets from server to a random IP address, which goes default routes pkt = testutils.simple_ip_packet(eth_dst=vlan_mac, ip_src=server_ip, ip_dst=random_ip) # Generate packet forwarded to portchannels pkt_copy = pkt.copy() pkt_copy[Ether].src = router_mac exp_pkt = mask.Mask(pkt_copy) exp_pkt.set_do_not_care_scapy(Ether, "dst") exp_pkt.set_do_not_care_scapy(IP, "dst") exp_pkt.set_do_not_care_scapy(IP, "ihl") exp_pkt.set_do_not_care_scapy(IP, "tos") exp_pkt.set_do_not_care_scapy(IP, "len") exp_pkt.set_do_not_care_scapy(IP, "id") exp_pkt.set_do_not_care_scapy(IP, "flags") exp_pkt.set_do_not_care_scapy(IP, "frag") exp_pkt.set_do_not_care_scapy(IP, "ttl") exp_pkt.set_do_not_care_scapy(IP, "proto") exp_pkt.set_do_not_care_scapy(IP, "chksum") exp_pkt.set_ignore_extra_bytes() port_channels = get_t1_ptf_pc_ports(host, tbinfo) rx_ports = [] for v in port_channels.values(): rx_ports += v rx_ports = [int(x.strip('eth')) for x in rx_ports] mg_facts = host.get_extended_minigraph_facts(tbinfo) tx_port = mg_facts['minigraph_ptf_indices'][itfs] logger.info( "Verifying upstream traffic. packet number = {} interface = {} server_ip = {} expect_drop = {}" .format(pkt_num, itfs, server_ip, drop)) for i in range(0, pkt_num): ptfadapter.dataplane.flush() testutils.send(ptfadapter, tx_port, pkt, count=1) if drop: testutils.verify_no_packet_any(ptfadapter, exp_pkt, rx_ports) else: testutils.verify_packet_any_port(ptfadapter, exp_pkt, rx_ports)
def test_po_update_io_no_loss(duthosts, enum_rand_one_per_hwsku_frontend_hostname, enum_frontend_asic_index, tbinfo, reload_testbed, ptfadapter): # GIVEN a lag topology, keep sending packets between 2 port channels # WHEN delete/add different members of a port channel # THEN no packets shall loss duthost = duthosts[enum_rand_one_per_hwsku_frontend_hostname] asichost = duthost.asic_instance(enum_frontend_asic_index) mg_facts = duthost.get_extended_minigraph_facts(tbinfo) if len(mg_facts["minigraph_portchannel_interfaces"]) < 2: pytest.skip( "Skip test due to there isn't enough port channel exists in current topology." ) # generate ip-pc pairs, be like:[("10.0.0.56", "10.0.0.57", "PortChannel0001")] peer_ip_pc_pair = [(pc["addr"], pc["peer_addr"], pc["attachto"]) for pc in mg_facts["minigraph_portchannel_interfaces"] if ipaddress.ip_address(pc['peer_addr']).version == 4] # generate pc tuples, fill in members, # be like:[("10.0.0.56", "10.0.0.57", "PortChannel0001", ["Ethernet48", "Ethernet52"])] pcs = [(pair[0], pair[1], pair[2], mg_facts["minigraph_portchannels"][pair[2]]["members"]) for pair in peer_ip_pc_pair if len(mg_facts["minigraph_portchannels"][pair[2]]["members"]) >= 2] if len(pcs) < 2: pytest.skip( "Skip test due to there is no enough port channel with at least 2 members exists in current topology." ) selected_pcs = random.sample(pcs, k=2) in_pc = selected_pcs[0] out_pc = selected_pcs[1] # use first port of in_pc as input port # all ports in out_pc will be output/forward ports pc, pc_members = out_pc[2], out_pc[3] in_ptf_index = mg_facts["minigraph_ptf_indices"][in_pc[3][0]] out_ptf_indices = map(lambda port: mg_facts["minigraph_ptf_indices"][port], out_pc[3]) logging.info( "selected_pcs is: %s, in_ptf_index is %s, out_ptf_indices is %s" % (selected_pcs, in_ptf_index, out_ptf_indices)) tmp_pc = "PortChannel999" pc_ip = out_pc[0] in_peer_ip = in_pc[1] out_peer_ip = out_pc[1] # Step 1: Remove port channel members from port channel for member in pc_members: asichost.config_portchannel_member(pc, member, "del") # Step 2: Remove port channel ip from port channel asichost.config_ip_intf(pc, pc_ip + "/31", "remove") time.sleep(30) int_facts = asichost.interface_facts()['ansible_facts'] pytest_assert(not int_facts['ansible_interface_facts'][pc]['link']) pytest_assert( wait_until(120, 10, 0, asichost.check_bgp_statistic, 'ipv4_idle', 1)) # Step 3: Create tmp port channel with default min-links(1) asichost.config_portchannel(tmp_pc, "add") # Step 4: Add port channel members to tmp port channel for member in pc_members: asichost.config_portchannel_member(tmp_pc, member, "add") # Step 5: Add port channel ip to tmp port channel asichost.config_ip_intf(tmp_pc, pc_ip + "/31", "add") int_facts = asichost.interface_facts()['ansible_facts'] pytest_assert(int_facts['ansible_interface_facts'][tmp_pc]['ipv4'] ['address'] == pc_ip) time.sleep(30) int_facts = asichost.interface_facts()['ansible_facts'] pytest_assert(int_facts['ansible_interface_facts'][tmp_pc]['link']) pytest_assert( wait_until(120, 10, 0, asichost.check_bgp_statistic, 'ipv4_idle', 0)) # Keep sending packets, and add/del different members during that time, observe whether packets lose pkt = testutils.simple_ip_packet(eth_dst=duthost.facts["router_mac"], eth_src=ptfadapter.dataplane.get_mac( 0, in_ptf_index), ip_src=in_peer_ip, ip_dst=out_peer_ip) exp_pkt = pkt.copy() exp_pkt = mask.Mask(exp_pkt) exp_pkt.set_do_not_care_scapy(packet.Ether, 'dst') exp_pkt.set_do_not_care_scapy(packet.Ether, 'src') exp_pkt.set_do_not_care_scapy(packet.IP, 'chksum') exp_pkt.set_do_not_care_scapy(packet.IP, 'ttl') ptfadapter.dataplane.flush() member_update_finished_flag = Queue(1) packet_sending_flag = Queue(1) def del_add_members(): # wait for packets sending started, then starts to update pc members while packet_sending_flag.empty() or (not packet_sending_flag.get()): time.sleep(0.5) asichost.config_portchannel_member(tmp_pc, pc_members[0], "del") time.sleep(2) asichost.config_portchannel_member(tmp_pc, pc_members[0], "add") time.sleep(2) asichost.config_portchannel_member(tmp_pc, pc_members[1], "del") time.sleep(2) asichost.config_portchannel_member(tmp_pc, pc_members[1], "add") time.sleep(5) member_update_finished_flag.put(True) t = threading.Thread(target=del_add_members, name="del_add_members_thread") t.start() t_max = time.time() + 60 send_count = 0 stop_sending = False while not stop_sending: # After 100 packets send, awake del_add_members thread, it happens only once. if send_count == 100: packet_sending_flag.put(True) testutils.send(ptfadapter, in_ptf_index, pkt) send_count += 1 member_update_thread_finished = (not member_update_finished_flag.empty( )) and member_update_finished_flag.get() reach_max_time = time.time() > t_max stop_sending = reach_max_time or member_update_thread_finished t.join(20) match_cnt = testutils.count_matched_packets_all_ports( ptfadapter, exp_pkt, ports=out_ptf_indices) pytest_assert(match_cnt > 0, "Packets not send") pytest_assert(match_cnt == send_count, "Packets lost during pc members add/removal")
def runTest(self): pkt = testutils.simple_ip_packet(pktlen=80) self.runPacketInTest(pkt)