def checkMirroredFlow(self): """ @summary: Send traffic & check how many mirrored packets are received @return: count: number of mirrored packets received Note: Mellanox crafts the GRE packets with extra information: That is: 22 bytes extra information after the GRE header """ payload = self.base_pkt if self.asic_type in ["mellanox"]: import binascii payload = binascii.unhexlify("0" * 44) + str( payload) # Add the padding exp_pkt = testutils.simple_gre_packet( eth_src=self.router_mac, ip_src=self.session_src_ip, ip_dst=self.session_dst_ip, ip_dscp=self.session_dscp, ip_id=0, #ip_flags = 0x10, # need to upgrade ptf version to support it ip_ttl=self.session_ttl, inner_frame=payload) if self.asic_type in ["mellanox"]: exp_pkt['GRE'].proto = 0x8949 # Mellanox specific else: exp_pkt['GRE'].proto = 0x88be 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, "flags") masked_exp_pkt.set_do_not_care_scapy(scapy.IP, "chksum") if self.asic_type in ["mellanox"]: masked_exp_pkt.set_do_not_care( 304, 176) # Mask the Mellanox specific inner header self.dataplane.flush() count = 0 for i in range(0, self.NUM_OF_TOTAL_PACKETS): testutils.send_packet(self, self.src_port, self.base_pkt) (rcv_device, rcv_port, rcv_pkt, pkt_time) = testutils.dp_poll(self, timeout=0.1, exp_pkt=masked_exp_pkt) if rcv_pkt is not None: count += 1 elif count == 0: print "The first mirrored packet is not recieved" assert False # Fast failure without waiting for full iteration print "Received " + str( count) + " mirrored packets after rate limiting" return count
def get_expected_mirror_packet(mirror_session, setup, duthost, mirror_packet, check_ttl): payload = mirror_packet.copy() # Add vendor specific padding to the packet if duthost.facts["asic_type"] in ["mellanox"]: payload = binascii.unhexlify("0" * 44) + str(payload) if duthost.facts["asic_type"] in ["barefoot", "cisco-8000"]: payload = binascii.unhexlify("0" * 24) + str(payload) expected_packet = testutils.simple_gre_packet( eth_src=setup["router_mac"], ip_src=mirror_session["session_src_ip"], ip_dst=mirror_session["session_dst_ip"], ip_dscp=int(mirror_session["session_dscp"]), ip_id=0, ip_ttl=int(mirror_session["session_ttl"]), inner_frame=payload) expected_packet["GRE"].proto = mirror_session["session_gre"] expected_packet = Mask(expected_packet) expected_packet.set_do_not_care_scapy(packet.Ether, "dst") expected_packet.set_do_not_care_scapy(packet.IP, "ihl") expected_packet.set_do_not_care_scapy(packet.IP, "len") expected_packet.set_do_not_care_scapy(packet.IP, "flags") expected_packet.set_do_not_care_scapy(packet.IP, "chksum") if duthost.facts["asic_type"] in ["cisco-8000"]: expected_packet.set_do_not_care_scapy(packet.GRE, "seqnum_present") if not check_ttl: expected_packet.set_do_not_care_scapy(packet.IP, "ttl") # The fanout switch may modify this value en route to the PTF so we should ignore it, even # though the session does have a DSCP specified. expected_packet.set_do_not_care_scapy(packet.IP, "tos") # Mask off the payload (we check it later) expected_packet.set_do_not_care(OUTER_HEADER_SIZE * 8, len(payload) * 8) return expected_packet
def checkMirroredFlow(self): """ @summary: Send traffic & check how many mirrored packets are received @return: count: number of mirrored packets received """ exp_pkt = testutils.simple_gre_packet( eth_src=self.router_mac, ip_src=self.session_src_ip, ip_dst=self.session_dst_ip, ip_dscp=self.session_dscp, ip_id=0, #ip_flags = 0x10, # need to upgrade ptf version to support it ip_ttl=self.session_ttl, inner_frame=self.base_pkt) exp_pkt['GRE'].proto = 0x88be 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, "flags") masked_exp_pkt.set_do_not_care_scapy(scapy.IP, "chksum") self.dataplane.flush() count = 0 for i in range(0, self.NUM_OF_TOTAL_PACKETS): testutils.send_packet(self, self.src_port, self.base_pkt) (rcv_device, rcv_port, rcv_pkt, pkt_time) = testutils.dp_poll(self, timeout=0.1, exp_pkt=masked_exp_pkt) if rcv_pkt is not None: count += 1 elif count == 0: print "The first mirrored packet is not recieved" assert False # Fast failure without waiting for full iteration print "Received " + str( count) + " mirrored packets after rate limiting" return count
def checkMirroredFlow(self): """ @summary: Send traffic & check how many mirrored packets are received @return: count: number of mirrored packets received Note: Mellanox crafts the GRE packets with extra information: That is: 22 bytes extra information after the GRE header """ payload = self.base_pkt.copy() payload_mask = Mask(payload) if self.mirror_stage == "egress": payload['Ethernet'].src = self.router_mac payload['IP'].ttl -= 1 payload_mask.set_do_not_care_scapy(scapy.Ether, "dst") payload_mask.set_do_not_care_scapy(scapy.IP, "chksum") if self.asic_type in ["mellanox"]: import binascii payload = binascii.unhexlify("0" * 44) + str( payload) # Add the padding exp_pkt = testutils.simple_gre_packet( eth_src=self.router_mac, ip_src=self.session_src_ip, ip_dst=self.session_dst_ip, ip_dscp=self.session_dscp, ip_id=0, #ip_flags = 0x10, # need to upgrade ptf version to support it ip_ttl=self.session_ttl, inner_frame=payload) if self.asic_type in ["mellanox"]: exp_pkt['GRE'].proto = 0x8949 # Mellanox specific else: exp_pkt['GRE'].proto = 0x88be 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, "flags") masked_exp_pkt.set_do_not_care_scapy(scapy.IP, "chksum") masked_exp_pkt.set_do_not_care( 38 * 8, len(payload) * 8 ) # don't match payload, payload will be matched by match_payload(pkt) def match_payload(pkt): pkt = scapy.Ether(pkt).load if self.asic_type in ["mellanox"]: pkt = pkt[22:] # Mask the Mellanox specific inner header pkt = scapy.Ether(pkt) return dataplane.match_exp_pkt(payload_mask, pkt) self.dataplane.flush() count = 0 testutils.send_packet(self, self.src_port, self.base_pkt, count=self.NUM_OF_TOTAL_PACKETS) for i in range(0, self.NUM_OF_TOTAL_PACKETS): (rcv_device, rcv_port, rcv_pkt, pkt_time) = testutils.dp_poll(self, timeout=0.1, exp_pkt=masked_exp_pkt) if rcv_pkt is not None and match_payload(rcv_pkt): count += 1 elif count == 0: assert_str = "The first mirrored packet is not recieved" assert count > 0, assert_str # Fast failure without waiting for full iteration else: break # No more packets available logger.info( "Received {} mirrored packets after rate limiting".format(count)) return count
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 checkMirroredFlow(self): """ @summary: Send traffic & check how many mirrored packets are received @return: count: number of mirrored packets received Note: Mellanox crafts the GRE packets with extra information: That is: 22 bytes extra information after the GRE header """ payload = self.base_pkt.copy() payload_mask = Mask(payload) if self.mirror_stage == "egress": payload['Ethernet'].src = self.router_mac payload['IP'].ttl -= 1 payload_mask.set_do_not_care_scapy(scapy.Ether, "dst") payload_mask.set_do_not_care_scapy(scapy.IP, "chksum") if self.asic_type in ["mellanox"]: import binascii payload = binascii.unhexlify("0"*44) + str(payload) # Add the padding if self.asic_type in ["barefoot"]: import binascii payload = binascii.unhexlify("0"*24) + str(payload) # Add the padding exp_pkt = testutils.simple_gre_packet( eth_src = self.router_mac, ip_src = self.session_src_ip, ip_dst = self.session_dst_ip, ip_dscp = self.session_dscp, ip_id = 0, #ip_flags = 0x10, # need to upgrade ptf version to support it ip_ttl = self.session_ttl, inner_frame = payload) if self.asic_type in ["mellanox"]: exp_pkt['GRE'].proto = 0x8949 # Mellanox specific elif self.asic_type in ["barefoot"]: exp_pkt['GRE'].proto = 0x22eb # Barefoot specific else: exp_pkt['GRE'].proto = 0x88be 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, "flags") masked_exp_pkt.set_do_not_care_scapy(scapy.IP, "chksum") masked_exp_pkt.set_do_not_care(38*8, len(payload)*8) # don't match payload, payload will be matched by match_payload(pkt) if self.check_ttl == 'False': masked_exp_pkt.set_do_not_care_scapy(scapy.IP, "ttl") def match_payload(pkt): if self.asic_type in ["mellanox"]: pkt = scapy.Ether(pkt).load pkt = pkt[22:] # Mask the Mellanox specific inner header pkt = scapy.Ether(pkt) else: pkt = scapy.Ether(pkt)[scapy.GRE].payload return dataplane.match_exp_pkt(payload_mask, pkt) # send some amount to absorb CBS capacity testutils.send_packet(self, self.src_port, str(self.base_pkt), count=self.NUM_OF_TOTAL_PACKETS) self.dataplane.flush() end_time = datetime.datetime.now() + datetime.timedelta(seconds=self.send_time) tx_pkts = 0 while datetime.datetime.now() < end_time: testutils.send_packet(self, self.src_port, str(self.base_pkt)) tx_pkts += 1 rx_pkts = 0 while True: (rcv_device, rcv_port, rcv_pkt, pkt_time) = testutils.dp_poll(self, timeout=0.1, exp_pkt=masked_exp_pkt) if rcv_pkt is not None and match_payload(rcv_pkt): rx_pkts += 1 else: break # No more packets available tx_pps = tx_pkts / self.send_time rx_pps = rx_pkts / self.send_time logger.info("Sent {} packets".format(tx_pkts)) logger.info("Received {} mirrored packets after rate limiting".format(rx_pkts)) logger.info("TX PPS {}".format(tx_pps)) logger.info("RX PPS {}".format(rx_pps)) return rx_pkts, tx_pps, rx_pps