def test_mask__mask_simple_packet(self, scapy_simple_tcp_packet): packet = scapy_simple_tcp_packet mask_packet = Mask(packet) assert mask_packet.pkt_match(packet) modified_packet = packet.copy() modified_packet[TCP].sport = 97 assert not mask_packet.pkt_match(modified_packet) # try to mask only sport (still packet will be different on chksum!) mask_packet.set_do_not_care_packet(TCP, "sport") assert not mask_packet.pkt_match(modified_packet) mask_packet.set_do_not_care_packet(TCP, "chksum") assert mask_packet.pkt_match(modified_packet)
def send_and_check_mirror_packets(self, setup, mirror_session, ptfadapter, duthost, mirror_packet, src_port=None, dest_ports=None, expect_recv=True): expected_mirror_packet = self._get_expected_mirror_packet( mirror_session, setup, duthost, mirror_packet) if not src_port: src_port = self._get_random_src_port(setup) if not dest_ports: dest_ports = [ self._get_monitor_port(setup, mirror_session, duthost) ] ptfadapter.dataplane.flush() testutils.send(ptfadapter, src_port, mirror_packet) if expect_recv: _, received_packet = testutils.verify_packet_any_port( ptfadapter, expected_mirror_packet, ports=dest_ports) logging.info("Received packet: %s", packet.Ether(received_packet).summary()) inner_packet = self._extract_mirror_payload( received_packet, len(mirror_packet)) logging.info("Received inner packet: %s", inner_packet.summary()) inner_packet = Mask(inner_packet) # For egress mirroring, we expect the DUT to have modified the packet # before forwarding it. Specifically: # # - In L2 the SMAC and DMAC will change. # - In L3 the TTL and checksum will change. # # We know what the TTL and SMAC should be after going through the pipeline, # but DMAC and checksum are trickier. For now, update the TTL and SMAC, and # mask off the DMAC and IP Checksum to verify the packet contents. if self.mirror_type() == "egress": mirror_packet[packet.IP].ttl -= 1 mirror_packet[packet.Ether].src = setup["router_mac"] inner_packet.set_do_not_care_scapy(packet.Ether, "dst") inner_packet.set_do_not_care_scapy(packet.IP, "chksum") logging.info("Expected inner packet: %s", mirror_packet.summary()) pytest_assert(inner_packet.pkt_match(mirror_packet), "Mirror payload does not match received packet") else: testutils.verify_no_packet_any(ptfadapter, expected_mirror_packet, dest_ports)
def test_mask__conditional_field__gpid_should_be_masked_correctly( self, scapy_simple_vxlan_packet): simple_vxlan = scapy_simple_vxlan_packet # type: Packet simple_vxlan[VXLAN].flags = "G" masked_simple_vxlan = Mask(simple_vxlan) # type: Mask masked_simple_vxlan.set_do_not_care_packet(VXLAN, "gpid") # UDP chksum will be different when we change VXLAN masked_simple_vxlan.set_do_not_care_packet(UDP, "chksum") packet_wth_custom_gpid = simple_vxlan.copy() # type: Packet packet_wth_custom_gpid[VXLAN].gpid = 0x15 # 21 assert masked_simple_vxlan.pkt_match( packet_wth_custom_gpid), "Packets should match"
def send_and_check_mirror_packets(self, setup, mirror_session, ptfadapter, duthost, mirror_packet, src_port=None, dest_ports=None, expect_recv=True, valid_across_namespace=True): expected_mirror_packet = self._get_expected_mirror_packet( mirror_session, setup, duthost, mirror_packet) if not src_port: src_port = self._get_random_src_port(setup) if not dest_ports: dest_ports = [ self._get_monitor_port(setup, mirror_session, duthost) ] # In Below logic idea is to send traffic in such a way so that mirror traffic # will need to go across namespaces and within namespace. If source and mirror destination # namespace are different then traffic mirror will go across namespace via (backend asic) # else via same namespace(asic) src_port_namespace = self._get_port_namespace(setup, int(src_port)) dest_ports_namespace = self._get_port_namespace( setup, int(dest_ports[0])) src_port_set = set() # Some of test scenario are not valid across namespaces so test will explicltly pass # valid_across_namespace as False (default is True) if valid_across_namespace == True or src_port_namespace == dest_ports_namespace: src_port_set.add(src_port) # To verify same namespace mirroring we will add destination port also to the Source Port Set if src_port_namespace != dest_ports_namespace: src_port_set.add(dest_ports[0]) # Loop through Source Port Set and send traffic on each source port of the set for src_port in src_port_set: ptfadapter.dataplane.flush() testutils.send(ptfadapter, src_port, mirror_packet) if expect_recv: _, received_packet = testutils.verify_packet_any_port( ptfadapter, expected_mirror_packet, ports=dest_ports) logging.info("Received packet: %s", packet.Ether(received_packet).summary()) inner_packet = self._extract_mirror_payload( received_packet, len(mirror_packet)) logging.info("Received inner packet: %s", inner_packet.summary()) inner_packet = Mask(inner_packet) # For egress mirroring, we expect the DUT to have modified the packet # before forwarding it. Specifically: # # - In L2 the SMAC and DMAC will change. # - In L3 the TTL and checksum will change. # # We know what the TTL and SMAC should be after going through the pipeline, # but DMAC and checksum are trickier. For now, update the TTL and SMAC, and # mask off the DMAC and IP Checksum to verify the packet contents. if self.mirror_type() == "egress": mirror_packet[packet.IP].ttl -= 1 mirror_packet[packet.Ether].src = setup["router_mac"] inner_packet.set_do_not_care_scapy(packet.Ether, "dst") inner_packet.set_do_not_care_scapy(packet.IP, "chksum") logging.info("Expected inner packet: %s", mirror_packet.summary()) pytest_assert(inner_packet.pkt_match(mirror_packet), "Mirror payload does not match received packet") else: testutils.verify_no_packet_any(ptfadapter, expected_mirror_packet, dest_ports)
def check_mirrored_packet(self, ipv6=False): """ Send an ARP or ND request and verify that it is mirrored. NOTE: This test only verifies that the payload is correct and that the outermost packet headers are correct (Ether / IP / GRE). Any extra info or headers that an ASIC chooses to include is ignored. Keyword arguments: ipv6 -- the IP version for this test run """ pkt = self.basev6_pkt if ipv6 else self.base_pkt payload = pkt.copy() if self.mirror_stage == "egress": payload['Ethernet'].src = self.router_mac payload['IP'].ttl -= 1 exp_pkt = testutils.simple_gre_packet( eth_src=self.router_mac, ip_src=self.MIRROR_SESSION_SRC_IP, ip_dst=self.MIRROR_SESSION_DST_IP, ip_dscp=self.MIRROR_SESSION_DSCP, ip_id=self.IP_ID, ip_ttl=self.MIRROR_SESSION_TTL, inner_frame=payload) if self.asic_type in ["mellanox"]: exp_pkt['GRE'].proto = self.GRE_PROTO_MLNX else: exp_pkt['GRE'].proto = self.GRE_PROTO_ERSPAN masked_exp_pkt = Mask(exp_pkt) masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "dst") masked_exp_pkt.set_do_not_care_scapy(scapy.IP, "ihl") masked_exp_pkt.set_do_not_care_scapy(scapy.IP, "len") masked_exp_pkt.set_do_not_care_scapy(scapy.IP, "flags") masked_exp_pkt.set_do_not_care_scapy(scapy.IP, "chksum") # NOTE: The fanout modifies the tos field, so it will always be 0 even # if we specify a particular value in the mirror session. masked_exp_pkt.set_do_not_care_scapy(scapy.IP, "tos") # NOTE: Later versions of PTF allow you to ignore extra bytes, which # would allow us to specify an expected packet to be received by # masking off everything but the outer headers (Ether / IP / GRE). # # For now we just trim away any extra headers and check that the packet # matches after it is received. self.dataplane.flush() testutils.send_packet(self, self.src_port, pkt) _, _, rcv_pkt, _ = testutils.dp_poll(self, timeout=0.1) rcv_pkt = self.trim_extra_asic_headers(rcv_pkt, len(payload)) if rcv_pkt and masked_exp_pkt.pkt_match(rcv_pkt): print("{} mirroring succesful".format("ND" if ipv6 else "ARP")) else: assert False
def test_mask__set_do_not_care(self): expected_packet = "\x01\x02\x03\x04\x05\x06" packet = "\x01\x00\x00\x04\x05\x06\x07\x08" mask = Mask(expected_packet.encode(), ignore_extra_bytes=True) mask.set_do_not_care(8, 16) assert mask.pkt_match(packet.encode())