def verify_packets_with_portchannel(test, pkt, ports=[], portchannel_ports=[], device_number=0, timeout=1): for port in ports: result = testutils.dp_poll(test, device_number=device_number, port_number=port, timeout=timeout, exp_pkt=pkt) if isinstance(result, test.dataplane.PollFailure): test.fail( "Expected packet was not received on device %d, port %r.\n%s" % (device_number, port, result.format())) for port_group in portchannel_ports: for port in port_group: result = testutils.dp_poll(test, device_number=device_number, port_number=port, timeout=timeout, exp_pkt=pkt) if isinstance(result, test.dataplane.PollSuccess): break else: test.fail( "Expected packet was not received on device %d, ports %s.\n" % (device_number, str(port_group)))
def test_vlan_tc5_untagged_non_broadcast(ptfadapter, vlan_ports_list, duthost): """ Test case #5 Send packets w/ src and dst specified over untagged ports in vlan Verify that bidirectional communication between two untagged ports work """ vlan_ids = vlan_ports_list[0]['permit_vlanid'].keys() tagged_test_vlan = vlan_ids[0] untagged_test_vlan = vlan_ids[1] ports_for_test = [] for vlan_port in vlan_ports_list: if vlan_port['pvid'] != tagged_test_vlan: ports_for_test.append(vlan_port['port_index'][0]) #take two tagged ports for test src_port = ports_for_test[0] dst_port = ports_for_test[-1] src_mac = ptfadapter.dataplane.get_mac(0, src_port) dst_mac = ptfadapter.dataplane.get_mac(0, dst_port) transmit_untagged_pkt = build_icmp_packet(vlan_id=0, src_mac=src_mac, dst_mac=dst_mac) return_transmit_untagged_pkt = build_icmp_packet(vlan_id=0, src_mac=dst_mac, dst_mac=src_mac) logger.info ("Untagged packet to be sent from port {} to port {}".format(src_port, dst_port)) testutils.send(ptfadapter, src_port, transmit_untagged_pkt) result_dst_if = testutils.dp_poll(ptfadapter, device_number=0, port_number=dst_port, timeout=1, exp_pkt=transmit_untagged_pkt) if isinstance(result_dst_if, ptfadapter.dataplane.PollSuccess): logger.info ("One Way Untagged Packet Transmission Works") logger.info ("Untagged packet successfully sent from port {} to port {}".format(src_port, dst_port)) else: pytest.fail("Expected packet was not received") logger.info ("Untagged packet to be sent from port {} to port {}".format(dst_port, src_port)) testutils.send(ptfadapter, dst_port, return_transmit_untagged_pkt) result_src_if = testutils.dp_poll(ptfadapter, device_number=0, port_number=src_port, timeout=1, exp_pkt=return_transmit_untagged_pkt) if isinstance(result_src_if, ptfadapter.dataplane.PollSuccess): logger.info ("Two Way Untagged Packet Transmission Works") logger.info ("Untagged packet successfully sent from port {} to port {}".format(dst_port, src_port)) else: pytest.fail("Expected packet was not received")
def check_macsec_pkt(macsec_attr, test, ptf_port_id, exp_pkt, timeout=3): device, ptf_port = testutils.port_to_tuple(ptf_port_id) received_packets = [] encrypt, send_sci, xpn_en, sci, an, sak, ssci, salt = macsec_attr end_time = time.time() + timeout while True: cur_time = time.time() if cur_time > end_time: break ret = testutils.dp_poll( test, device_number=device, port_number=ptf_port, timeout=end_time - cur_time, exp_pkt=None) if isinstance(ret, test.dataplane.PollFailure): break # If the packet isn't MACsec type pkt = scapy.Ether(ret.packet) if pkt[scapy.Ether].type != 0x88e5: continue received_packets.append(pkt) for i in range(len(received_packets)): pkt = received_packets[i] pn = 0 pkt = decap_macsec_pkt(pkt, sci, an, sak, encrypt, send_sci, pn, xpn_en, ssci, salt) if not pkt: continue received_packets[i] = pkt if exp_pkt.pkt_match(pkt): return fail_message = "Expect pkt \n{}\n{}\nBut received \n".format( exp_pkt, exp_pkt.exp_pkt.show(dump=True)) for packet in received_packets: fail_message += "\n{}\n".format(packet.show(dump=True)) return fail_message
def count_matched_packets_all_ports_helper(test, exp_packet, exp_packet_number, ports=[], device_number=0, timeout=1): """ Add exp_packet_number to original ptf interface in order to stop waiting when expected number of packets is received """ if timeout <= 0: raise Exception("%s() requires positive timeout value." % sys._getframe().f_code.co_name) last_matched_packet_time = time.time() total_rcv_pkt_cnt = 0 while True: if (time.time() - last_matched_packet_time) > timeout: break result = dp_poll(test, device_number=device_number, timeout=timeout) if isinstance(result, test.dataplane.PollSuccess): if (result.port in ports and ptf.dataplane.match_exp_pkt( exp_packet, result.packet)): total_rcv_pkt_cnt += 1 if total_rcv_pkt_cnt == exp_packet_number: break last_matched_packet_time = time.time() else: break return total_rcv_pkt_cnt
def capture_matched_packets(test, exp_packet, port, device_number=0, timeout=1): """ Receive all packets on the port and return all the received packets. As soon as the packets stop arriving, the function waits for the timeout value and returns the received packets. Therefore, this function requires a positive timeout value. """ if timeout <= 0: raise Exception("%s() requires positive timeout value." % sys._getframe().f_code.co_name) pkts = list() while True: result = dp_poll(test, device_number=device_number, port_number=port, timeout=timeout) if isinstance(result, test.dataplane.PollSuccess): if ptf.dataplane.match_exp_pkt(exp_packet, result.packet): pkts.append(result.packet) else: break return pkts
def count_matched_packets_helper(test, exp_packet, exp_packet_number, port, device_number=0, timeout=1): """ Add exp_packet_number to original ptf interface in order to stop waiting when expected number of packets is received """ if timeout <= 0: raise Exception("%s() requires positive timeout value." % sys._getframe().f_code.co_name) total_rcv_pkt_cnt = 0 end_time = time.time() + timeout while time.time() < end_time: result = dp_poll(test, device_number=device_number, port_number=port, timeout=timeout, exp_pkt=exp_packet) if isinstance(result, test.dataplane.PollSuccess): total_rcv_pkt_cnt += 1 if total_rcv_pkt_cnt == exp_packet_number: break else: break return total_rcv_pkt_cnt
def checkOriginalFlow(self): """ @summary: Send traffic & check how many original packets are received @return: count: number of original packets received """ exp_pkt = self.base_pkt.copy() exp_pkt['Ethernet'].src = self.router_mac exp_pkt['IP'].ttl = self.base_pkt['IP'].ttl - 1 masked_exp_pkt = Mask(exp_pkt) masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "dst") 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 original packet is not recieved" assert False # Fast failure without waiting for full iteration print "Recieved " + str(count) + " original packets" return count
def checkOriginalFlow(self): """ @summary: Send traffic & check how many original packets are received @return: count: number of original packets received """ exp_pkt = self.base_pkt.copy() exp_pkt['Ethernet'].src = self.router_mac exp_pkt['IP'].ttl = self.base_pkt['IP'].ttl - 1 masked_exp_pkt = Mask(exp_pkt) masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "dst") self.dataplane.flush() count = 0 testutils.send_packet(self, self.src_port, str(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: count += 1 elif count == 0: assert_str = "The first original packet is not recieved" assert count > 0, assert_str # Fast failure without waiting for full iteration else: break # No more packets available logger.info("Recieved {} original packets".format(count)) 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 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 check_macsec_pkt(test, ptf_port_id, exp_pkt, timeout=3): device, ptf_port = testutils.port_to_tuple(ptf_port_id) ret = testutils.dp_poll(test, device_number=device, port_number=ptf_port, timeout=timeout, exp_pkt=exp_pkt) if isinstance(ret, test.dataplane.PollSuccess): return else: return ret.format()
def receivePacketOnPorts(self, ports=[], device_number=0): ''' @summary Receive packet on any of specified ports ''' received = False match_index = 0 (rcv_device, rcv_port, rcv_pkt, pkt_time) = testutils.dp_poll(self, device_number=device_number, timeout=1) if rcv_port in ports: match_index = ports.index(rcv_port) received = True return (match_index, rcv_pkt, received)
def verify_packet_count(self, pkt, port_id): test = self.outer.ptfadapter device, port = testutils.port_to_tuple(port_id) logging.debug("Checking for pkt on device %d, port %d", device, port) result = testutils.dp_poll(test, device_number=device, port_number=port, exp_pkt=pkt) if isinstance(result, test.dataplane.PollSuccess): return (1, result.packet) return (0, None)
def runTest(self): try: # expected mean and stdev from 32b unsigned uniform random exp_mean = (pow(2, 32) - 1) / 2.0 exp_std = (pow(2, 32) - 1) / math.sqrt(12) # compute mean and std from samples num_samples = 1000 rand_vals = [] print("\nInject %s packets and get random value in srcip field." % num_samples) print("It may take time with model.\n") for i in range(num_samples): ipkt = testutils.simple_udp_packet(eth_dst='11:11:11:11:11:11', eth_src='22:33:44:55:66:77', ip_src='1.2.3.4', ip_dst='100.99.98.97', ip_id=101, ip_ttl=64, udp_sport=0x1234, udp_dport=0xabcd) testutils.send_packet(self, swports[0], ipkt) (rcv_dev, rcv_port, rcv_pkt, pkt_time) = \ testutils.dp_poll(self, dev_id, swports[0], timeout=2) nrcv = ipkt.__class__(rcv_pkt) # print ("\n### Received pkt :\n") # nrcv.show2() # hexdump(nrcv) rand_val = ip2int(nrcv[IP].src) rand_vals.append(rand_val) # print("32b Random value written in ipv4 src ip : " + str(rand_val)) # compare mean and std mean = sum(rand_vals) / float(len(rand_vals)) std = stdev(rand_vals) print(("Expected Mean : " + str(exp_mean))) print(("Observed Mean : " + str(mean))) print(("Expected Stdev : " + str(exp_std))) print(("Observed Stdev : " + str(std))) assert abs(mean - exp_mean) / float(exp_mean) < 0.1 assert abs(std - exp_std) / float(exp_std) < 0.1 finally: pass
def count_matched_packets_all_ports(ptfadapter, exp_packet, exp_tunnel_pkt, ports=[], device_number=0, timeout=None, count=1): """ Receive all packets on all specified ports and count how many expected packets were received. """ if timeout is None: timeout = ptf.ptfutils.default_timeout if timeout <= 0: raise Exception("%s() requires positive timeout value." % sys._getframe().f_code.co_name) start_time = time.time() port_packet_count = dict() packet_count = 0 while True: if (time.time() - start_time) > timeout: break result = testutils.dp_poll(ptfadapter, device_number=device_number, timeout=timeout) if isinstance(result, ptfadapter.dataplane.PollSuccess): if ((result.port in ports) and (ptf.dataplane.match_exp_pkt(exp_packet, result.packet) or ptf.dataplane.match_exp_pkt(exp_tunnel_pkt, result.packet))): port_packet_count[result.port] = port_packet_count.get( result.port, 0) + 1 packet_count += 1 if packet_count == count: return port_packet_count else: break return port_packet_count
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 runTest(self): target = gc.Target(device_id=0, pipe_id=0xffff) # Get bfrt_info and set it as part of the test bfrt_info = self.interface.bfrt_info_get(p4_program_name) # Set default output port table_output_port = bfrt_info.table_get("SwitchIngress.output_port") action_data = table_output_port.make_data( action_name="SwitchIngress.set_output_port", data_field_list_in=[gc.DataTuple(name="port_id", val=swports[1])] ) table_output_port.default_entry_set( target=target, data=action_data) try: random.seed(1) num_trials = 20 logger.info(("\nInject {} packets with random values provided in the eth" + " dst field.").format(num_trials)) logger.info("Tofino computes the crc32 and crc-bzip2 hashes of the " + "random value and stores them in the dst and src mac " + "fields. We verify the hash value each packet.") # crc32 function for verification hash1_func = zlib.crc32 # crc32-bzip2 function for verification hash2_func = crcmod.predefined.mkCrcFun('crc-32-bzip2') for i in range(num_trials): # random_value = random.randint(0, 2^32-1) random_value = random.randint(0, 2 ** 32 - 1) random_hex = "{:012x}".format(random_value) random_mac = ":".join(random_hex[t:t + 2] for t in range(0, 12, 2)) ipkt = testutils.simple_udp_packet(eth_dst=str(random_mac), eth_src=str(random_mac), ip_src='1.2.3.4', ip_dst='100.99.98.97', ip_id=101, ip_ttl=64, udp_sport=0x1234, udp_dport=0xabcd) testutils.send_packet(self, swports[0], ipkt) (rcv_dev, rcv_port, rcv_pkt, pkt_time) = \ testutils.dp_poll(self, dev_id, swports[1], timeout=2) nrcv = ipkt.__class__(rcv_pkt) hash1_p4_value = int(str(nrcv[Ether].dst).replace(":", ""), 16) hash2_p4_value = int(str(nrcv[Ether].src).replace(":", ""), 16) hash1_exp_value = hash1_func(struct.pack("!I", random_value)) & 0xffffffff hash2_exp_value = hash2_func(struct.pack("!I", random_value)) & 0xffffffff # verify the hash logger.info("Random value : {:x}".format(random_value)) logger.info("Random value mac : {}".format(random_mac)) logger.info("Hash1 P4 value : {:x}".format(hash1_p4_value)) logger.info("Hash1 expected value : {:x}".format(hash1_exp_value)) logger.info("Hash2 P4 value : {:x}".format(hash2_p4_value)) logger.info("Hash2 expected value : {:x}".format(hash2_exp_value)) assert hash1_p4_value == hash1_exp_value assert hash2_p4_value == hash2_exp_value finally: table_output_port.default_entry_reset(target)
def runTest(self): target = gc.Target(device_id=0, pipe_id=0xffff) # Get bfrt_info and set it as part of the test bfrt_info = self.interface.bfrt_info_get(p4_program_name) # Set default output port table_output_port = bfrt_info.table_get("SwitchIngress.output_port") action_data = table_output_port.make_data( action_name="SwitchIngress.set_output_port", data_field_list_in=[gc.DataTuple(name="port_id", val=swports[1])] ) table_output_port.default_entry_set( target=target, data=action_data) try: random.seed(1) num_trials = 20 for i in range(num_trials): ip_src = int2ip(random.randint(0, 2 ** 32 - 1)) ip_dst = int2ip(random.randint(0, 2 ** 32 - 1)) udp_sport = random.randint(0, 2 ** 16 - 1) udp_dport = random.randint(0, 2 ** 16 - 1) print((" Testing IPv4 and UDP port values: {}, {}, {}, {}". format(ip_src, ip_dst, udp_sport, udp_dport))) ipkt_1 = testutils.simple_udp_packet(eth_dst="22:22:22:22:22:22", eth_src='00:00:00:00:00:00', ip_src=ip_src, ip_dst=ip_dst, ip_id=101, ip_ttl=64, udp_sport=udp_sport, udp_dport=udp_dport) testutils.send_packet(self, swports[0], ipkt_1) (rcv_dev, rcv_port, rcv_pkt, pkt_time) = \ testutils.dp_poll(self, dev_id, swports[1], timeout=2) rpkt_1 = ipkt_1.__class__(rcv_pkt) ipkt_2 = testutils.simple_udp_packet(eth_dst="22:22:22:22:22:22", eth_src='00:00:00:00:00:00', ip_src=ip_dst, ip_dst=ip_src, ip_id=101, ip_ttl=64, udp_sport=udp_dport, udp_dport=udp_sport) testutils.send_packet(self, swports[0], ipkt_2) (rcv_dev, rcv_port, rcv_pkt, pkt_time) = \ testutils.dp_poll(self, dev_id, swports[1], timeout=2) rpkt_2 = ipkt_2.__class__(rcv_pkt) ipkt_3 = testutils.simple_udp_packet(eth_dst="22:22:22:22:22:22", eth_src='00:00:00:00:00:00', ip_src=ip_src, ip_dst=ip_dst, ip_id=101, ip_ttl=64, udp_sport=udp_dport, udp_dport=udp_sport) testutils.send_packet(self, swports[0], ipkt_3) (rcv_dev, rcv_port, rcv_pkt, pkt_time) = \ testutils.dp_poll(self, dev_id, swports[1], timeout=2) rpkt_3 = ipkt_3.__class__(rcv_pkt) ipkt_4 = testutils.simple_udp_packet(eth_dst="22:22:22:22:22:22", eth_src='00:00:00:00:00:00', ip_src=ip_src, ip_dst=ip_dst, ip_id=101, ip_ttl=64, udp_sport=udp_dport, udp_dport=udp_sport) testutils.send_packet(self, swports[0], ipkt_4) (rcv_dev, rcv_port, rcv_pkt, pkt_time) = \ testutils.dp_poll(self, dev_id, swports[1], timeout=2) rpkt_4 = ipkt_4.__class__(rcv_pkt) assert rpkt_1[Ether].src != "00:00:00:00:00:00" assert rpkt_1[Ether].src == rpkt_2[Ether].src == rpkt_3[Ether].src == rpkt_4[Ether].src finally: table_output_port.default_entry_reset(target)
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
def runTest(self): target = gc.Target(device_id=0, pipe_id=0xffff) # Get bfrt_info and set it as part of the test bfrt_info = self.interface.bfrt_info_get(p4_program_name) # Set default output port table_output_port = bfrt_info.table_get("SwitchIngress.output_port") action_data = table_output_port.make_data( action_name="SwitchIngress.set_output_port", data_field_list_in=[gc.DataTuple(name="port_id", val=swports[1])]) table_output_port.default_entry_set(target=target, data=action_data) try: ipkt_payload = struct.pack("I", 0) * 10 ipkt = testutils.simple_udp_packet(eth_dst='11:11:11:11:11:11', eth_src='22:22:22:22:22:22', ip_src='1.2.3.4', ip_dst='100.99.98.97', ip_id=101, ip_ttl=64, udp_sport=0x1234, udp_dport=0xabcd, with_udp_chksum=False, udp_payload=ipkt_payload) testutils.send_packet(self, swports[0], ipkt) (rcv_dev, rcv_port, rcv_pkt, pkt_time) = \ testutils.dp_poll(self, 0, swports[1], timeout=2) nrcv = ipkt.__class__(rcv_pkt) # Parse the payload and extract the timestamps # import pdb; pdb.set_trace() ts_ingress_mac, ts_ingress_global, \ ts_enqueue, ts_dequeue_delta, \ ts_egress_global, ts_egress_tx = \ struct.unpack("!QQIIQQxxxxxxxxxxxxxxxxxx", nrcv.load) ns = 1000000000.0 logger.info("Timestamps") logger.info(" raw values in ns:") logger.info(" ingress mac : {:>15}".format( ts_ingress_mac)) logger.info(" ingress global : {:>15}".format( ts_ingress_global)) logger.info(" traffic manager enqueue : {:>15}".format( ts_enqueue)) logger.info(" traffic manager dequeue delta : {:>15}".format( ts_dequeue_delta)) logger.info(" egress global : {:>15}".format( ts_egress_global)) logger.info(" egress tx (no value in model) : {:>15}".format( ts_egress_tx)) logger.info(" values in s:") logger.info(" ingress mac : {:>15.9f}".format( ts_ingress_mac / ns)) logger.info(" ingress global : {:>15.9f}".format( ts_ingress_global / ns)) logger.info(" traffic manager enqueue : {:>15.9f}".format( ts_enqueue / ns)) logger.info(" traffic manager dequeue delta : {:>15.9f}".format( ts_dequeue_delta / ns)) logger.info(" egress global : {:>15.9f}".format( ts_egress_global / ns)) logger.info(" egress tx (no value in model) : {:>15.9f}".format( ts_egress_tx)) logger.info( "Please note that the timestamps are using the internal time " + "of the model/chip. They are not synchronized with the global time. " "Furthermore, the traffic manager timestamps in the model do not " + "accurately reflect the packet processing. Correct values are shown " + "by the hardware implementation.") finally: table_output_port.default_entry_reset(target)
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