def runTest(self): in_dmac = 'ee:30:ca:9d:1e:00' in_smac = 'ee:cd:00:7e:70:00' ip_dst_addr = '10.1.0.1' ig_port = 1 eg_port = 2 l2ptr = 58 bd = 9 out_dmac = '02:13:57:ab:cd:ef' out_smac = '00:11:22:33:44:55' # Before adding any table entries, the default behavior for # sending in an IPv4 packet is to drop it. pkt = tu.simple_tcp_packet(eth_src=in_smac, eth_dst=in_dmac, ip_dst=ip_dst_addr, ip_ttl=64) tu.send_packet(self, ig_port, pkt) tu.verify_no_other_packets(self) # Add a set of table entries that the packet should match, and # be forwarded out with the desired dest and source MAC # addresses. self.table_add(self.key_ipv4_da_lpm(ip_dst_addr, 32), self.act_set_l2ptr(l2ptr)) self.table_add(self.key_mac_da(l2ptr), self.act_set_bd_dmac_intf(bd, out_dmac, eg_port)) self.table_add(self.key_send_frame(bd), self.act_rewrite_mac(out_smac)) # Check that the entry is hit, expected source and dest MAC # have been written into output packet, TTL has been # decremented, and that no other packets are received. exp_pkt = tu.simple_tcp_packet(eth_src=out_smac, eth_dst=out_dmac, ip_dst=ip_dst_addr, ip_ttl=63) tu.send_packet(self, ig_port, pkt) tu.verify_packets(self, exp_pkt, [eg_port])
def runTest(self): ip_dst_addr = "10.0.0.1" ip_dst_addr_str = ipv4_to_binary(ip_dst_addr) ig_port = self.swports(1) eg_port = self.swports(2) # port is 9-bit in v1model, i.e. 2 bytes eg_port_str = stringify(eg_port, 2) smac = "\xee\xcd\x00\x7e\x70\x00" dmac = "\xee\x30\xca\x9d\x1e\x00" # we do not care about the src mac address or the src IP address pkt = testutils.simple_tcp_packet(eth_dst=smac, ip_dst=ip_dst_addr, ip_ttl=64) # no forwarding entry: packet must be dropped testutils.send_packet(self, ig_port, pkt) testutils.verify_no_other_packets(self) # add a forwarding entry self.send_request_add_entry_to_action( "l3_host_fwd", [self.Exact("hdr.ipv4.dst_addr", ip_dst_addr_str)], "set_nexthop", [("port", eg_port_str), ("smac", smac), ("dmac", dmac)]) # check that the entry is hit and that no other packets are received exp_pkt = testutils.simple_tcp_packet(eth_src=smac, eth_dst=dmac, ip_dst=ip_dst_addr, ip_ttl=63) testutils.send_packet(self, ig_port, pkt) testutils.verify_packets(self, exp_pkt, [eg_port])
def send_pkt_expect_it_dropped(self, idx, pkt_seqnum): ig_port = 0 eg_port = 2 pkt_in = self.make_pkt(idx, pkt_seqnum) tu.send_packet(self, ig_port, pkt_in) tu.verify_no_other_packets(self)
def runArpBroadcastTest(self, tagged_ports, untagged_ports): zero_mac_addr = ":".join(["00"] * 6) vlan_id = 10 next_id = vlan_id mcast_group_id = vlan_id all_ports = set(tagged_ports + untagged_ports) arp_pkt = testutils.simple_arp_packet(pktlen=76) # Account for VLAN header size in total pktlen vlan_arp_pkt = testutils.simple_arp_packet(vlan_vid=vlan_id, pktlen=80) for port in tagged_ports: self.set_ingress_port_vlan(port, True, vlan_id, vlan_id) for port in untagged_ports: self.set_ingress_port_vlan(port, False, 0, vlan_id) self.add_bridging_entry(vlan_id, zero_mac_addr, zero_mac_addr, next_id) self.add_next_multicast(next_id, mcast_group_id) self.add_mcast_group(mcast_group_id, all_ports) for port in untagged_ports: self.set_egress_vlan_pop(port, vlan_id) for inport in all_ports: pkt_to_send = vlan_arp_pkt if inport in tagged_ports else arp_pkt testutils.send_packet(self, inport, str(pkt_to_send)) # Packet should be received on all ports expect the ingress one. verify_tagged_ports = set(tagged_ports) verify_tagged_ports.discard(inport) for tport in verify_tagged_ports: testutils.verify_packet(self, vlan_arp_pkt, tport) verify_untagged_ports = set(untagged_ports) verify_untagged_ports.discard(inport) for uport in verify_untagged_ports: testutils.verify_packet(self, arp_pkt, uport) testutils.verify_no_other_packets(self)
def test(self, pkt): mcast_group_id = 10 mcast_ports = [self.port1, self.port2, self.port3] self.add_mcast_group(group_id=mcast_group_id, ports=mcast_ports) self.add_l2_ternary_entry(eth_dst=MAC_BROADCAST, eth_dst_mask=MAC_FULL_MASK, mcast_group_id=mcast_group_id) self.add_l2_ternary_entry(eth_dst=MAC_MULTICAST, eth_dst_mask=MAC_MULTICAST_MASK, mcast_group_id=mcast_group_id) self.add_acl_cpu_entry(eth_type=ARP_ETH_TYPE, clone=True) self.add_acl_cpu_entry(eth_type=IPV6_ETH_TYPE, ip_proto=ICMPV6_IP_PROTO, icmp_type=NS_ICMPV6_TYPE, clone=True) self.add_clone_session(CPU_CLONE_SESSION_ID, [self.cpu_port]) for inport in mcast_ports: testutils.send_packet(self, inport, str(pkt)) # Pkt should be received on CPU and on all ports # except the ingress one. self.verify_packet_in(exp_pkt=pkt, exp_in_port=inport) verify_ports = set(mcast_ports) verify_ports.discard(inport) for port in verify_ports: testutils.verify_packet(self, pkt, port) testutils.verify_no_other_packets(self)
def runControlPacketInTest(self, pppoed_pkt, line_mapped=True): s_tag = vlan_id_outer = 888 c_tag = vlan_id_inner = 777 self.setup_bng() # If a line mapping is not provided, we expect packets to be processed # with line ID 0 (e.g. counters updated at index 0). line_id = 0 if line_mapped: line_id = 99 self.set_upstream_line_map( s_tag=s_tag, c_tag=c_tag, line_id=line_id) pppoed_pkt = pkt_add_vlan(pppoed_pkt, vlan_vid=vlan_id_inner) pppoed_pkt = pkt_add_vlan(pppoed_pkt, vlan_vid=vlan_id_outer) old_terminated = self.read_pkt_count_upstream("terminated", line_id) old_dropped = self.read_pkt_count_upstream("dropped", line_id) old_control = self.read_pkt_count_upstream("control", line_id) testutils.send_packet(self, self.port1, str(pppoed_pkt)) self.verify_packet_in(pppoed_pkt, self.port1) testutils.verify_no_other_packets(self) new_terminated = self.read_pkt_count_upstream("terminated", line_id) new_dropped = self.read_pkt_count_upstream("dropped", line_id) new_control = self.read_pkt_count_upstream("control", line_id) # Only control plane packets. self.assertEqual(new_terminated, old_terminated) self.assertEqual(new_dropped, old_dropped) self.assertEqual(new_control, old_control + 1)
def runTest(self): pkt = "ab" * 20 testutils.send_packet(self, (0, 1), str(pkt)) print "packet sent" testutils.verify_packet(self, pkt, (1, 1)) # We remove a port to test port_remove, but in order to execute # subsequent tests, we need to make sure we re-add the port # afterwards. In order to re-add the port, we need the interface name, # which is what this method is for. This is a little hacky but fine for # testing. In practice, you would not be removing ports which are part # of the original ptf config. def find_ifname(device_number, port_number): for port_id, ifname in config["port_map"].items(): if (device_number, port_number) == port_id: return ifname ifname = find_ifname(1, 1) self.assertTrue(self.dataplane.port_remove(1, 1)) testutils.send_packet(self, (0, 1), str(pkt)) print "packet sent" testutils.verify_no_other_packets(self, device_number=1) self.dataplane.port_add(ifname, 1, 1) testutils.send_packet(self, (0, 1), str(pkt)) print "packet sent" testutils.verify_packet(self, pkt, (1, 1))
def runTest(self): pktlen = 400 pkt = testutils.simple_ipv6ip_packet(pktlen=pktlen) self.assertEqual(len(pkt), pktlen) testutils.send_packet(self, (0, 1), pkt) print("packet sent") testutils.verify_packet(self, pkt, (1, 1)) testutils.verify_no_other_packets(self, 1)
def runPacketInTest(self, pkt): vlan_id = 10 self.add_forwarding_acl_cpu_entry(eth_type=pkt.type) for port in [self.port1, self.port2]: self.set_ingress_port_vlan(port, False, 0, vlan_id) testutils.send_packet(self, port, str(pkt)) self.verify_packet_in(pkt, port) testutils.verify_no_other_packets(self)
def runPacketInTest(self, pkt, eth_type=None): if eth_type is None: eth_type = pkt[Ether].type self.add_acl_cpu_entry(eth_type=eth_type) for port in [self.port1, self.port2, self.port3]: testutils.send_packet(self, port, str(pkt)) self.verify_packet_in(pkt, port) testutils.verify_no_other_packets(self)
def runTest(self): pktlen = 70 pkt = testutils.simple_ipv4ip_packet(pktlen=pktlen) pkt2 = testutils.simple_ipv4ip_packet(pktlen=pktlen, inner_frame=pkt["IP"]) testutils.send_packet(self, (0, 1), pkt2) print("packet sent") testutils.verify_packet(self, pkt2, (1, 1)) testutils.verify_no_other_packets(self, 1)
def runPacketInTest(self, pkt, eth_type, tagged=False, vlan_id=10): self.add_forwarding_acl_cpu_entry(eth_type=eth_type) for port in [self.port1, self.port2]: if tagged: self.set_ingress_port_vlan(port, True, vlan_id, vlan_id) else: self.set_ingress_port_vlan(port, False, 0, vlan_id) testutils.send_packet(self, port, str(pkt)) self.verify_packet_in(pkt, port) testutils.verify_no_other_packets(self)
def runTest(self): eg_port = swports[2] dmac = '22:22:22:22:22:22' dkey = '22:22:22:22:22:23' dmask = 'ff:ff:ff:ff:ff:f0' port_mask = 0 pkt = testutils.simple_tcp_packet(eth_dst=dmac) pkt2 = testutils.simple_tcp_packet(eth_dst=dkey) exp_pkt = pkt exp_pkt2 = pkt2 # Get bfrt_info and set it as part of the test bfrt_info = self.interface.bfrt_info_get("tna_dkm") # Set the scope of the table to ALL_PIPES logger.info("=============== Testing Dyn Key Mask ===============") target = gc.Target(device_id=0, pipe_id=0xffff) logger.info("set dyn key mask") forward_table = bfrt_info.table_get("SwitchIngress.forward") forward_table.info.key_field_annotation_add("hdr.ethernet.dst_addr", "mac") key_mask = forward_table.make_key( [gc.KeyTuple('hdr.ethernet.dst_addr', dmask), gc.KeyTuple('ig_intr_md.ingress_port', port_mask)]) forward_table.attribute_dyn_key_mask_set(target, key_mask) resp = forward_table.attribute_get(target, "DynamicKeyMask") for d in resp: assert d["fields"].to_dict()["ig_intr_md.ingress_port"]["value"] == port_mask assert d["fields"].to_dict()["hdr.ethernet.dst_addr"]["value"] == dmask logger.info("Add entry") key_list = [forward_table.make_key( [gc.KeyTuple('hdr.ethernet.dst_addr', dmac), gc.KeyTuple('ig_intr_md.ingress_port', swports_0[0])])] data_list = [forward_table.make_data([gc.DataTuple('port', eg_port)], "SwitchIngress.hit")] forward_table.entry_add(target, key_list, data_list) self.send_and_verify_packet(swports_0[0], eg_port, pkt2, exp_pkt2) self.send_and_verify_packet(swports_1[0], eg_port, pkt2, exp_pkt2) if int(testutils.test_param_get('num_pipes')) > 2: self.send_and_verify_packet(swports_2[0], eg_port, pkt2, exp_pkt2) if int(testutils.test_param_get('num_pipes')) > 3: self.send_and_verify_packet(swports_3[0], eg_port, pkt2, exp_pkt2) self.send_and_verify_packet(swports_0[0], eg_port, pkt, exp_pkt) self.send_and_verify_packet(swports_1[0], eg_port, pkt, exp_pkt) if int(testutils.test_param_get('num_pipes')) > 2: self.send_and_verify_packet(swports_2[0], eg_port, pkt, exp_pkt) if int(testutils.test_param_get('num_pipes')) > 3: self.send_and_verify_packet(swports_3[0], eg_port, pkt, exp_pkt) testutils.verify_no_other_packets(self, timeout=2) logger.info("Delete the entry") forward_table.entry_del(target, key_list)
def runTest(self): pktlen = 1000 udp = testutils.simple_udp_packet() ipv6 = testutils.simple_ipv6ip_packet(inner_frame=udp['UDP']) gre = testutils.simple_grev6_packet(pktlen=pktlen, inner_frame=ipv6["IPv6"]) self.assertEqual(gre['GRE'].proto, 0x86DD) testutils.send_packet(self, (0, 1), gre) print("packet sent") testutils.verify_packet(self, gre, (1, 1)) testutils.verify_no_other_packets(self, 1)
def runControlPacketOutTest(self, pppoed_pkt): vlan_id_outer = 888 vlan_id_inner = 777 self.setup_bng() # Assuming pkts are double-tagged at the control plane. pppoed_pkt = pkt_add_vlan(pppoed_pkt, vlan_vid=vlan_id_inner) pppoed_pkt = pkt_add_vlan(pppoed_pkt, vlan_vid=vlan_id_outer) self.verify_packet_out(pppoed_pkt, self.port1) testutils.verify_no_other_packets(self)
def runPacketOutTest(self, pkt): for port in [self.port1, self.port2]: port_hex = stringify(port, 2) packet_out = p4runtime_pb2.PacketOut() packet_out.payload = str(pkt) egress_physical_port = packet_out.metadata.add() egress_physical_port.metadata_id = 1 egress_physical_port.value = port_hex self.send_packet_out(packet_out) testutils.verify_packet(self, pkt, port) testutils.verify_no_other_packets(self)
def runTest(self): ''' Simple test to check if a digest is received after sending a packet. ''' ig_port = swports[2] smac = '00:01:02:03:04:05' dmac = '00:06:07:08:09:0a' pkt = testutils.simple_tcp_packet(eth_dst=dmac, eth_src=smac) # Get bfrt_info and set it as part of the test bfrt_info = self.interface.bfrt_info_get("tna_digest") # The learn object can be retrieved using a lesser qualified name on the condition # that it is unique learn_filter = bfrt_info.learn_get("digest_a") learn_filter.info.data_field_annotation_add("src_addr", "mac") learn_filter.info.data_field_annotation_add("dst_addr", "mac") logger.info("Sending packet on port %d", ig_port) testutils.send_packet(self, ig_port, pkt) logger.info("Packet is expected to get dropped.") testutils.verify_no_other_packets(self) digest = self.interface.digest_get() recv_target = digest.target self.assertTrue( recv_target.device_id == self.device_id, "Error! Recv device id = %d does not match expected = %d" % (recv_target.device_id, self.device_id)) exp_pipe_id = (ig_port >> 7) & 0x3 self.assertTrue( recv_target.pipe_id == exp_pipe_id, "Error! Recv pipe id = %d does not match expected = %d" % (recv_target.pipe_id, exp_pipe_id)) data_list = learn_filter.make_data_list(digest) data_dict = data_list[0].to_dict() recv_src_addr = data_dict["src_addr"] recv_port = data_dict["port"] recv_dst_addr = data_dict["dst_addr"] self.assertTrue( smac == recv_src_addr, "Error! smac = %s received smac = %s" % (str(smac), str(recv_src_addr))) self.assertTrue( dmac == recv_dst_addr, "Error! dmac = %s received dmac = %s" % (str(dmac), str(recv_dst_addr))) self.assertTrue( ig_port == recv_port, "Error! port = %s received port = %s" % (str(ig_port), str(recv_port)))
def runTest(self): ig_port = swports[1] eg_port = swports[2] dmac = '22:22:22:22:22:22' target = client.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("tna_action_profile") forward_table = bfrt_info.table_get("SwitchIngress.forward") action_profile = bfrt_info.table_get("SwitchIngress.action_profile") ap_key = action_profile.make_key( [client.KeyTuple('$ACTION_MEMBER_ID', 1)]) action_profile.entry_add(target, [ap_key], [ action_profile.make_data([client.DataTuple('port', eg_port)], 'SwitchIngress.set_port') ]) fwd_key = forward_table.make_key([ client.KeyTuple('ig_intr_md.ingress_port', ig_port), client.KeyTuple('vid', 0) ]) forward_table.entry_add(target, [fwd_key], [ forward_table.make_data([client.DataTuple('$ACTION_MEMBER_ID', 1)]) ]) try: pkt = testutils.simple_tcp_packet(eth_dst=dmac) logger.info("Sending packet on port %d", ig_port) testutils.send_packet(self, ig_port, pkt) exp_pkt = pkt logger.info("Expecting packet on port %d", eg_port) testutils.verify_packets(self, exp_pkt, [eg_port]) finally: forward_table.entry_del(target, [fwd_key]) action_profile.entry_del(target, [ap_key]) try: logger.info("Sending packet on port %d", ig_port) testutils.send_packet(self, ig_port, pkt) logger.info("Packet is expected to get dropped.") testutils.verify_no_other_packets(self) finally: pass
def read_SeqNumReg(self, idx_int): logging.debug("read_seqNumReg idx={}".format(idx_int)) pkt = scapy.Ether() pktout_dict = { 'payload': bytes(pkt), 'metadata': { 'opcode': self.opcode_name2int['READ_REGISTER'], 'reserved1': 0, 'operand0': idx_int, 'operand1': 0, 'operand2': 0, 'operand3': 0 } } pktout_pb = self.encode_packet_out_metadata(pktout_dict) self.send_packet_out(pktout_pb) logging.debug("read_seqNumReg pktout_dict={}".format(pktout_dict)) exp_pkt = pkt exp_pktinfo = \ {'metadata': {'input_port': self.CPU_PORT, 'punt_reason': self.punt_reason_name2int['OPERATION_RESPONSE'], 'opcode': self.opcode_name2int['READ_REGISTER'], 'operand0': idx_int, 'operand1': 0, 'operand2': 0, 'operand3': 0}, 'payload': bytes(exp_pkt)} tu.verify_no_other_packets(self) pkt_pb = self.get_packet_in() pktinfo = self.decode_packet_in_metadata(pkt_pb) # We want to check the contents of the response packet that # comes back from reading, but we want this function to work # even if we do not know what the read value is. So take the # read value from the response packet, and make that value # part of the expected value. That field will thus always # match. We will still catch any problems if any of the other # fields contain unxpected values. seqnum_int = pktinfo['metadata']['operand1'] exp_pktinfo['metadata']['operand1'] = seqnum_int logging.debug("read_seqNumReg exp_pktinfo={}".format(exp_pktinfo)) logging.debug("read_seqNumReg pktinfo={}".format(pktinfo)) self.verify_packet_in(exp_pktinfo, pktinfo) return seqnum_int
def runArpBroadcastTest(self, tagged_ports, untagged_ports): zero_mac_addr = ":".join(["00"] * 6) vlan_id = 10 next_id = vlan_id mcast_group_id = vlan_id all_ports = tagged_ports + untagged_ports arp_pkt = testutils.simple_arp_packet(pktlen=MIN_PKT_LEN - 4) # Account for VLAN header size in total pktlen vlan_arp_pkt = testutils.simple_arp_packet(vlan_vid=vlan_id, pktlen=MIN_PKT_LEN) for port in tagged_ports: self.set_ingress_port_vlan(port, True, vlan_id, vlan_id) for port in untagged_ports: self.set_ingress_port_vlan(port, False, 0, vlan_id) self.add_bridging_entry(vlan_id, zero_mac_addr, zero_mac_addr, next_id) self.add_forwarding_acl_cpu_entry(eth_type=ETH_TYPE_ARP, clone=True) self.add_next_multicast(next_id, mcast_group_id) # FIXME: use clone session APIs when supported on PI # For now we add the CPU port to the mc group. self.add_mcast_group(mcast_group_id, all_ports + [self.cpu_port]) for port in untagged_ports: self.set_egress_vlan_pop(port, vlan_id) for inport in all_ports: pkt_to_send = vlan_arp_pkt if inport in tagged_ports else arp_pkt testutils.send_packet(self, inport, str(pkt_to_send)) # Pkt should be received on CPU and on all ports, except the ingress one. self.verify_packet_in(exp_pkt=pkt_to_send, exp_in_port=inport) verify_tagged_ports = set(tagged_ports) verify_tagged_ports.discard(inport) for tport in verify_tagged_ports: testutils.verify_packet(self, vlan_arp_pkt, tport) verify_untagged_ports = set(untagged_ports) verify_untagged_ports.discard(inport) for uport in verify_untagged_ports: testutils.verify_packet(self, arp_pkt, uport) testutils.verify_no_other_packets(self)
def write_SeqNumReg(self, idx_int, seqnum_int): logging.debug("write_seqNumReg idx={} seqnum={}".format( idx_int, seqnum_int)) pkt = scapy.Ether() pktout_dict = { 'payload': bytes(pkt), 'metadata': { 'opcode': self.opcode_name2int['WRITE_REGISTER'], 'reserved1': 0, 'operand0': idx_int, 'operand1': seqnum_int, 'operand2': 0, 'operand3': 0 } } pktout_pb = self.encode_packet_out_metadata(pktout_dict) self.send_packet_out(pktout_pb) logging.debug("write_seqNumReg pktout_dict={}".format(pktout_dict)) exp_pkt = pkt exp_pktinfo = \ {'metadata': {'input_port': self.CPU_PORT, 'punt_reason': self.punt_reason_name2int['OPERATION_RESPONSE'], 'opcode': self.opcode_name2int['WRITE_REGISTER'], 'operand0': idx_int, 'operand1': seqnum_int, 'operand2': 0, 'operand3': 0}, 'payload': bytes(exp_pkt)} logging.debug("write_seqNumReg exp_pktinfo={}".format(exp_pktinfo)) tu.verify_no_other_packets(self) pkt_pb = self.get_packet_in() pktinfo = self.decode_packet_in_metadata(pkt_pb) logging.debug("write_seqNumReg pktinfo={}".format(pktinfo)) self.verify_packet_in(exp_pktinfo, pktinfo)
def MultiSliceTestHelper(self, table_obj, exm_0_field_name, tcam_field_name, lpm_field_name, exm_1_field_name, is_multi_field): """ @brief This is a helper function that - Adds multiple field sliced entry in the table - For some runs, purposely creates discrepancies between the key fields that are already programmed and the values in the sent pkts and ensures that the packet doesn't hit the entry. The way this is done is, the ipv6 address is first generated. Then the value of the field slice is extraced from that address. Then a bit which we expect to match on is flipped in the extracted value. Thus there will be a mismatch between the value present in the packet and the value installed in the hardware which will cause the packet to miss - Always scrambles the bits which are not expected to match on - Reads back the entry and verifies - Sends packets and verifies, - If the installed key fields match the ones in the pkt, then the pkt should hit the entry - If they don't match then the pkt should miss the entry - Finally deletes the entry """ ig_port = swports[1] eg_port = swports[2] dmac = '22:22:22:22:22:22' target = gc.Target(device_id=0, pipe_id=0xffff) num_entries = 100 for entry_idx in range(num_entries): logger.info("Processing entry %d ", entry_idx) try: # Generate ipv6 dst addr and mask ipv6_dst_addr = generateIpv6Addr() ipv6_dst_addr_mask = generateIpv6Addr() logger.debug("Generated dst v6 addr is " + ipv6_dst_addr) logger.debug("Generated dst v6 mask is " + ipv6_dst_addr_mask) # Generate ipv6 src addr and mask ipv6_src_addr = generateIpv6Addr() ipv6_src_addr_mask = generateIpv6Addr() logger.debug("Generated src v6 addr is " + ipv6_src_addr) logger.debug("Generated src v6 mask is " + ipv6_src_addr_mask) # Extract all the field values from the dst addr tcam_v6_addr = ipv6_dst_addr tcam_v6_addr_mask = ipv6_dst_addr_mask lpm_v6_addr = ipv6_dst_addr exm_0_v6_addr = ipv6_dst_addr exm_1_v6_addr = ipv6_dst_addr if is_multi_field == True: # This indicates that the total 4 field slices are from 2 different fields, (2 slices from 1 field each) # Thus, the first exm field slice and tcam field slice are actually slices of a ipv6 src addr (Refer the p4 # program for deduction). Hence set them accordingly tcam_v6_addr = ipv6_src_addr tcam_v6_addr_mask = ipv6_src_addr_mask exm_0_v6_addr = ipv6_src_addr pkt = testutils.simple_tcpv6_packet(eth_dst=dmac, ipv6_dst=ipv6_dst_addr, ipv6_src=ipv6_src_addr) exp_pkt = pkt # Start off by expecting the sent packet to match on all the fields should_exm_match_0 = True should_exm_match_1 = True should_tcam_match = True should_lpm_match = True # For different iterations of the test, we want to tamper with different fields individually if entry_idx % 5 == 1: should_exm_match_0 = False elif entry_idx % 5 == 2: should_exm_match_1 = False elif entry_idx % 5 == 3: should_tcam_match = False elif entry_idx % 5 == 4: should_lpm_match = False # We use this set to keep track of bits we want to flip/garble within a field slice garble_bit_index = set() # exm exm_val_0 = getIpv6AddrFieldSliceValue(exm_0_field_name, exm_0_v6_addr) exm_field_byte_width_0 = getFieldSliceByteWidthFromName( exm_0_field_name) exm_field_bit_width_0 = getFieldSliceBitWidthFromName( exm_0_field_name) logger.debug("EXM_0 value before scrambling " + hex(exm_val_0)) # Scramble bits if we want the pkt to miss in this iteration because of a mismatch on this field if should_exm_match_0 == False: # Flip any bit which we expect to match on index = random.randint(0, exm_field_bit_width_0 - 1) exm_val_0 = garbleBits(exm_val_0, [index]) logger.debug("EXM_0 value after scrambling " + hex(exm_val_0)) # ternary tcam_val = getIpv6AddrFieldSliceValue(tcam_field_name, tcam_v6_addr) tcam_mask = getIpv6AddrFieldSliceValue(tcam_field_name, tcam_v6_addr_mask) tcam_field_bit_width = getFieldSliceBitWidthFromName( tcam_field_name) tcam_field_byte_width = getFieldSliceByteWidthFromName( tcam_field_name) logger.debug("TCAM value before scrambling " + hex(tcam_val)) # Scramble bits if we want the pkt to miss in this iteration because of a mismatch on this field if should_tcam_match == False: # Flip any bit which we expect to match on index = tcam_field_bit_width for i in range(tcam_field_bit_width): if ((tcam_mask >> i) & 0x01) == 1: index = i if index == tcam_field_bit_width: # indicates that the generated mask is all zeros. Thus ternary field is always going to match # Hence flip the flag accordingly should_tcam_match = True else: tcam_val = garbleBits(tcam_val, [index]) # Always scramble bits which are don't care garble_bit_index.clear() for i in range(tcam_field_bit_width): bit_val = (tcam_mask >> i) & 1 if bit_val == 0: garble_bit_index.add(i) tcam_val = garbleBits(tcam_val, garble_bit_index) logger.debug("TCAM value after scrambling " + hex(tcam_val)) # We never scramble the tcam mask logger.debug("TCAM mask " + hex(tcam_mask)) # lpm lpm_value_bit_width = getFieldSliceBitWidthFromName(lpm_field_name) lpm_value_byte_width = getFieldSliceByteWidthFromName( lpm_field_name) p_len = random.randint(1, lpm_value_bit_width) lpm_value = getIpv6AddrFieldSliceValue(lpm_field_name, lpm_v6_addr) logger.debug("LPM value before scrambling " + hex(lpm_value)) logger.debug("LPM prefix width " + hex(p_len)) # Scramble bits if we want the pkt to miss in this iteration because of a mismatch on this field if should_lpm_match == False: # Flip any bit within the prefix length so that the value in the packet # won't match with the value programmed. We are always flipping the bit # at index p_len lpm_value = garbleBits(lpm_value, [lpm_value_bit_width - p_len]) if p_len != lpm_value_bit_width: # Always scramble the bits which are not supposed to be looked up anyway garble_bit_index.clear() for i in range(lpm_value_bit_width - 1 - p_len): garble_bit_index.add(i) lpm_value = garbleBits(lpm_value, garble_bit_index) logger.debug("LPM value after scrambling " + hex(lpm_value)) # exm exm_val_1 = getIpv6AddrFieldSliceValue(exm_1_field_name, exm_1_v6_addr) exm_field_byte_width_1 = getFieldSliceByteWidthFromName( exm_1_field_name) exm_field_bit_width_1 = getFieldSliceBitWidthFromName( exm_1_field_name) logger.debug("EXM_1 value before scrambling " + hex(exm_val_1)) # Scramble bits if we want the pkt to miss in this iteration because of a mismatch on this field if should_exm_match_1 == False: # Flip any bit which we expect to match on index = random.randint(0, exm_field_bit_width_1 - 1) exm_val_1 = garbleBits(exm_val_1, [index]) logger.debug("EXM_1 value after scrambling " + hex(exm_val_1)) logger.info("Insert the entry") table_key = table_obj.make_key([ gc.KeyTuple(self.port_field_name, ig_port), gc.KeyTuple(exm_0_field_name, exm_val_0), gc.KeyTuple(tcam_field_name, tcam_val, tcam_mask), gc.KeyTuple(lpm_field_name, lpm_value, prefix_len=p_len), gc.KeyTuple(exm_1_field_name, exm_val_1), gc.KeyTuple("$MATCH_PRIORITY", 1) ]) table_obj.entry_add(target, [table_key], [getDataObj(table_obj, eg_port)]) # Get the entry resp = table_obj.entry_get(target, None, {"from_hw": True}) # for lpm and tcam, the mask is applied on the value before programming it in the hardware # thus get the expected lpm and tcam val to be read from hw lpm_val_hw = (((lpm_value) >> (lpm_value_bit_width - p_len)) << (lpm_value_bit_width - p_len)) tcam_value_hw = tcam_val & tcam_mask for data, key in resp: data_dict = data.to_dict() key_dict = key.to_dict() assert key_dict[self.port_field_name]['value'] == ig_port assert key_dict[exm_0_field_name]['value'] == exm_val_0 assert key_dict[tcam_field_name]['value'] == tcam_value_hw assert key_dict[tcam_field_name]['mask'] == tcam_mask assert key_dict[lpm_field_name]['value'] == lpm_val_hw assert key_dict[lpm_field_name]['prefix_len'] == p_len assert key_dict[exm_1_field_name]['value'] == exm_val_1 # Send the packet testutils.send_packet(self, ig_port, pkt) logger.info("Should Exm_0 match %d", should_exm_match_0) logger.info("Should Tcam match %d", should_tcam_match) logger.info("Should Lpm match %d", should_lpm_match) logger.info("Should Exm_1 match %d", should_exm_match_1) if should_exm_match_0 == 1 and should_tcam_match == 1 and should_lpm_match == 1 and should_exm_match_1 == 1: # For this iteration we expect the pkt to match on all the field slices logger.info( "Expecting packet on port %d after installing entry %d", eg_port, entry_idx) testutils.verify_packet(self, exp_pkt, eg_port) else: # For this iteration we expect the pkt to miss on any one of the fields and hence to get dropped logger.info( "Expecting the packet to get dropped after installing entry %d", entry_idx) testutils.verify_no_other_packets(self) finally: # Delete the entry logger.info("Delete the entry") table_obj.entry_del(target, [table_key]) testutils.send_packet(self, ig_port, pkt) logger.info("Packet is expected to get dropped.") testutils.verify_no_other_packets(self)
def runTest(self): ig_port = swports[1] eg_port = swports[2] dmac = '22:22:22:22:22:22' logger.info("Range field slices are not supported yet") # FIXME This test fails return self.set_bfrt_info( self.parse_bfrt_info(self.get_bfrt_info("tna_field_slice"))) target = self.Target(device_id=0, pipe_id=0xffff) num_entries = 100 for entry_idx in range(num_entries): logger.info("Processing entry %d", entry_idx) try: ipv6_dst_addr = generateIpv6Addr() pkt = testutils.simple_tcpv6_packet(eth_dst=dmac, ipv6_dst=ipv6_dst_addr) logger.debug("Ipv6 addr is " + ipv6_dst_addr) exp_pkt = pkt range_bit_width = getFieldSliceBitWidthFromName( self.range_field_name) range_byte_width = getFieldSliceByteWidthFromName( self.range_field_name) range_start = 1 range_end = 0 while range_end < range_start: range_start = random.randint(0, pow(2, range_bit_width)) range_end = random.randint(0, pow(2, range_bit_width)) pkt_range_value = getIpv6AddrFieldSliceValue( self.range_field_name, ipv6_dst_addr) range_start = pkt_range_value - 1 range_end = pkt_range_value + 1 should_range_match = False if pkt_range_value >= range_start and pkt_range_value <= range_end: logger.info("Entry is expected to hit") should_range_match = True else: logger.info("Entry is expected to miss") logger.debug("Range start is " + hex(range_start)) logger.debug("Range end is " + hex(range_end)) logger.debug("Pkt Range value is " + hex(pkt_range_value)) logger.info("Insert the entry") self.insert_table_entry( target, self.table_name, [ self.KeyField('ig_intr_md.ingress_port', self.to_bytes(ig_port, 2)), self.KeyField( self.range_field_name, low=self.to_bytes(range_start, range_byte_width), high=self.to_bytes(range_end, range_byte_width)), self.KeyField("$MATCH_PRIORITY", self.to_bytes(1, 4)) ], 'SwitchIngress.hit', [self.DataField('port', self.to_bytes(eg_port, 2))]) testutils.send_packet(self, ig_port, pkt) if should_range_match == True: logger.info("Expecting packet on port %d", eg_port) testutils.verify_packet(self, exp_pkt, eg_port) testutils.verify_no_other_packets(self) # Get key field ids key_port_field_id = self.get_key_field( self.table_name, "ig_intr_md.ingress_port") key_ipv6_dst_field_id = self.get_key_field( self.table_name, self.range_field_name) # Get all the entries resp = self.get_table_entry(target, self.table_name, None, {"from_hw": True}) key_dict = {} entry_iter = self.parseEntryGetResponse(resp, key_dict) for data_dict in entry_iter: assert key_dict[key_port_field_id][ 'value'] == self.to_bytes(ig_port, 2) assert key_dict[key_ipv6_dst_field_id][ 'low'] == self.to_bytes(range_start, range_byte_width) assert key_dict[key_ipv6_dst_field_id][ 'high'] == self.to_bytes(range_end, range_byte_width) finally: logger.info("Delete the entry") self.delete_table_entry(target, self.table_name, [ self.KeyField('ig_intr_md.ingress_port', self.to_bytes(ig_port, 2)), self.KeyField( self.range_field_name, low=self.to_bytes(range_start, range_byte_width), high=self.to_bytes(range_end, range_byte_width)), self.KeyField("$MATCH_PRIORITY", self.to_bytes(1, 4)) ]) testutils.send_packet(self, ig_port, pkt) logger.info("Packet is expected to get dropped.") testutils.verify_no_other_packets(self)
def SingleFieldSingleSliceLpmHelper(self, table_obj, lpm_field_name): """ @brief This is a helper function that adds a field slice entry in the table, sends packets and verifies, reads back the entry and verifies and then finally deletes the entry """ ig_port = swports[1] eg_port = swports[2] dmac = '22:22:22:22:22:22' num_entries = 100 for entry_idx in range(num_entries): logger.info("Processing entry %d", entry_idx) try: # Generate ipv6 addr ipv6_dst_addr = generateIpv6Addr() logger.debug("Ipv6 addr is " + ipv6_dst_addr) pkt = testutils.simple_tcpv6_packet(eth_dst=dmac, ipv6_dst=ipv6_dst_addr) exp_pkt = pkt target = gc.Target(device_id=0, pipe_id=0xffff) # Extract the lpm val, lpm field width in bits and bytes that is going to be programmed from the # generated ipv6 addr lpm_field_val = getIpv6AddrFieldSliceValue(lpm_field_name, ipv6_dst_addr) lpm_field_width_byte = getFieldSliceByteWidthFromName( lpm_field_name) lpm_value_bit_width = getFieldSliceBitWidthFromName(lpm_field_name) # Choose a prefix len between 1 and lpm field bit width p_len = random.randint(1, lpm_value_bit_width) logger.debug("LPM val is " + hex(lpm_field_val)) logger.debug("LPM prefix len is " + hex(p_len)) # Insert the entry logger.info("Insert the entry") table_key = table_obj.make_key([ gc.KeyTuple(self.port_field_name, ig_port), gc.KeyTuple(lpm_field_name, lpm_field_val, prefix_len=p_len) ]) table_obj.entry_add(target, [table_key], [getDataObj(table_obj, eg_port)]) testutils.send_packet(self, ig_port, pkt) logger.info("Expecting packet on port %d", eg_port) testutils.verify_packet(self, exp_pkt, eg_port) testutils.verify_no_other_packets(self) # Get the entry resp = table_obj.entry_get(target, None, {"from_hw": True}) # for lpm, the mask is applied on the value before programming it in the hardware # thus get the expected lpm field val to be read from hw lpm_field_val_hw = (((lpm_field_val) >> (lpm_value_bit_width - p_len)) << (lpm_value_bit_width - p_len)) for data, key in resp: data_dict = data.to_dict() key_dict = key.to_dict() assert key_dict[self.port_field_name]['value'] == ig_port assert key_dict[lpm_field_name]['value'] == lpm_field_val_hw assert key_dict[lpm_field_name]['prefix_len'] == p_len finally: # Delete the entry logger.info("Delete the entry") table_obj.entry_del(target, [table_key]) testutils.send_packet(self, ig_port, pkt) logger.info("Packet is expected to get dropped.") testutils.verify_no_other_packets(self)
def runTest(self): ig_port = swports[1] eg_port = swports[2] dmac = '22:22:22:22:22:22' bfrt_info = self.interface.bfrt_info_get("tna_field_slice") num_entries = 100 table_obj = bfrt_info.table_get(self.table_name) table_key = None for entry_idx in range(num_entries): logger.info("Processing entry %d", entry_idx) try: # Generate ipv6 addr ipv6_dst_addr = generateIpv6Addr() logger.debug("Ipv6 addr is " + ipv6_dst_addr) pkt = testutils.simple_tcpv6_packet(eth_dst=dmac, ipv6_dst=ipv6_dst_addr) exp_pkt = pkt target = gc.Target(device_id=0, pipe_id=0xffff) # Extract the exact match val that is going to be programmed from the # generated ipv6 addr exm_value = getIpv6AddrFieldSliceValue(self.exm_field_name, ipv6_dst_addr) logger.debug("EXM val is " + hex(exm_value)) # Insert the entry logger.info("Insert the entry") table_key = table_obj.make_key([ gc.KeyTuple(self.port_field_name, ig_port), gc.KeyTuple(self.exm_field_name, exm_value) ]) table_obj.entry_add(target, [table_key], [getDataObj(table_obj, eg_port)]) testutils.send_packet(self, ig_port, pkt) logger.info("Expecting packet on port %d", eg_port) testutils.verify_packet(self, exp_pkt, eg_port) testutils.verify_no_other_packets(self) # Get the entry resp = table_obj.entry_get(target, None, {"from_hw": True}) for data, key in resp: data_dict = data.to_dict() key_dict = key.to_dict() assert key_dict[self.port_field_name]['value'] == ig_port assert key_dict[self.exm_field_name]['value'] == exm_value finally: # Delete the entry if table_key: logger.info("Delete the entry") table_obj.entry_del(target, [table_key]) testutils.send_packet(self, ig_port, pkt) logger.info("Packet is expected to get dropped") testutils.verify_no_other_packets(self)
def runTest(self): ig_port = swports[1] eg_port = swports[2] dmac = '22:22:22:22:22:22' bfrt_info = self.interface.bfrt_info_get("tna_field_slice") num_entries = 100 table_obj = bfrt_info.table_get(self.table_name) for entry_idx in range(num_entries): logger.info("Processing entry %d", entry_idx) try: # Generate ipv6 addr and mask ipv6_dst_addr = generateIpv6Addr() ipv6_dst_addr_mask = generateIpv6Addr() logger.debug("Ipv6 addr is : " + ipv6_dst_addr) logger.debug("Ipv6 addr mask is :" + ipv6_dst_addr_mask) pkt = testutils.simple_tcpv6_packet(eth_dst=dmac, ipv6_dst=ipv6_dst_addr) exp_pkt = pkt target = gc.Target(device_id=0, pipe_id=0xffff) # Extract the tcam val and mask that is going to be programmed from the # generated ipv6 addr and mask tcam_field_val = getIpv6AddrFieldSliceValue( self.tcam_field_name, ipv6_dst_addr) logger.debug("TCAM val is " + hex(tcam_field_val)) tcam_field_mask = getIpv6AddrFieldSliceValue( self.tcam_field_name, ipv6_dst_addr_mask) logger.debug("TCAM mask is " + hex(tcam_field_mask)) tcam_field_width_byte = getFieldSliceByteWidthFromName( self.tcam_field_name) # Insert the entry logger.info("Insert the entry") table_key = table_obj.make_key([ gc.KeyTuple(self.port_field_name, ig_port), gc.KeyTuple(self.tcam_field_name, tcam_field_val, tcam_field_mask), gc.KeyTuple("$MATCH_PRIORITY", 1) ]) table_obj.entry_add(target, [table_key], [getDataObj(table_obj, eg_port)]) testutils.send_packet(self, ig_port, pkt) logger.info("Expecting packet on port %d", eg_port) testutils.verify_packet(self, exp_pkt, eg_port) testutils.verify_no_other_packets(self) # Get the entry resp = table_obj.entry_get(target, None, {"from_hw": True}) # For tcam, the mask is applied on the value before programming it in the hardware # Thus form the expected tcam value to be read from the hw tcam_field_val_hw = (tcam_field_val & tcam_field_mask) for data, key in resp: data_dict = data.to_dict() key_dict = key.to_dict() assert key_dict[self.port_field_name]['value'] == ig_port assert key_dict[ self.tcam_field_name]['value'] == tcam_field_val_hw assert key_dict[ self.tcam_field_name]['mask'] == tcam_field_mask finally: # Delete the entry logger.info("Delete the entry") table_obj.entry_del(target, [table_key]) testutils.send_packet(self, ig_port, pkt) logger.info("Packet is expected to get dropped.") testutils.verify_no_other_packets(self)
def runTest(self): p4_name_to_put = p4_name_to_pick = new_p4_name = "tna_ternary_match" profile_name_to_put = profile_name_to_pick = "pipe" # Send a Verify and warm_init_begin and warm_init_end logger.info( "Sending Verify and warm_init_begin and warm_init_end for %s", p4_name_to_put) action = bfruntime_pb2.SetForwardingPipelineConfigRequest.VERIFY_AND_WARM_INIT_BEGIN_AND_END success = self.a.interface.send_set_forwarding_pipeline_config_request( action, base_put_path, [ gc.ForwardingConfig( p4_name_to_put, create_path_bf_rt(base_pick_path, p4_name_to_pick), [ gc.ProfileInfo( profile_name_to_put, create_path_context(base_pick_path, p4_name_to_pick, profile_name_to_pick), create_path_tofino(base_pick_path, p4_name_to_pick, profile_name_to_pick), [0, 1, 2, 3]) ]) ]) if not success: raise RuntimeError("Failed to setFwd") # Check if both the clients have dropped out exception = self.a.interface.exception_q.get(timeout=5) if exception.grpc_error_get().code() != grpc.StatusCode.CANCELLED: logger.error("Did not receive cancelled for a") assert (0) exception = self.b.interface.exception_q.get(timeout=5) if exception.grpc_error_get().code() != grpc.StatusCode.CANCELLED: logger.error("Did not receive cancelled for b") assert (0) # Initiate subscribe and BIND for client 1 self.a.setUpBind(1, new_p4_name) # Try inserting a table entry in the new Program and test it target = gc.Target(device_id=0, pipe_id=0xffff) ig_port = get_port_from_pipes(external_pipes) eg_port = get_port_from_pipes(external_pipes) dip = '10.10.0.1' pkt = testutils.simple_tcp_packet(ip_dst=dip) exp_pkt = pkt self.a.bfrt_info = self.a.interface.bfrt_info_get(new_p4_name) self.a.forward_table = self.a.bfrt_info.table_get( "SwitchIngress.forward") self.a.forward_table.info.key_field_annotation_add( "hdr.ipv4.dst_addr", "ipv4") try: key = self.a.forward_table.make_key([ gc.KeyTuple('$MATCH_PRIORITY', 1), gc.KeyTuple('vrf', 0), gc.KeyTuple('hdr.ipv4.dst_addr', dip, '255.255.0.0') ]) data = self.a.forward_table.make_data( [gc.DataTuple('port', eg_port)], 'SwitchIngress.hit') self.a.forward_table.entry_add(target, [key], [data]) # check get resp = self.a.forward_table.entry_get(target, [key], {"from_hw": True}) data_dict = next(resp)[0].to_dict() recv_port = data_dict["port"] if (recv_port != eg_port): logger.error("Error! port sent = %s received port = %s", str(eg_port), str(recv_port)) assert 0 logger.info("Sending packet on port %d", ig_port) testutils.send_packet(self, ig_port, pkt) logger.info("Expecting packet on port %d", eg_port) testutils.verify_packet(self, exp_pkt, eg_port) testutils.verify_no_other_packets(self, timeout=2) except Exception as e: logger.info("!!!! Test Failed!!!!") import traceback traceback.print_exc() raise e finally: self.a.forward_table.entry_del(target, [ self.a.forward_table.make_key([ gc.KeyTuple('$MATCH_PRIORITY', 1), gc.KeyTuple('vrf', 0), gc.KeyTuple('hdr.ipv4.dst_addr', dip, '255.255.0.0') ]) ]) logger.info("Sending packet on port %d", ig_port) testutils.send_packet(self, ig_port, pkt) logger.info("Packet is expected to get dropped.") testutils.verify_no_other_packets(self)
def runTest(self): ig_port = swports[1] eg_ports = swports[2:6] group_id = 1 target = gc.Target(device_id=dev_id, pipe_id=0xffff) seed = random.randint(1, 65535) random.seed(seed) logger.info("Seed used %d", seed) # Add the new member to the selection table. pkt = testutils.simple_tcp_packet() exp_pkt = pkt max_grp_size = 200 # Get bfrt_info and set it as part of the test bfrt_info = self.interface.bfrt_info_get(p4_program_name) forward_table = bfrt_info.table_get("SwitchIngress.forward") action_table = bfrt_info.table_get( "SwitchIngress.example_action_selector_ap") sel_table = bfrt_info.table_get( "SwitchIngress.example_action_selector") members = [] member_status = [False] * len(eg_ports) exp_ports = [] # Disable 2 of the ports disable = random.sample(list(range(len(eg_ports))), 2) for i, port in enumerate(eg_ports): # Create a new member for each port with the port number as the id. action_table.entry_add(target, [ action_table.make_key([gc.KeyTuple('$ACTION_MEMBER_ID', port)]) ], [ action_table.make_data([gc.DataTuple('port', port)], 'SwitchIngress.hit') ]) members.append(port) if i not in disable: member_status[i] = True exp_ports.append(port) # Create a dictionary with the member_status and members mem_dict = { members[i]: member_status[i] for i in range(0, len(members)) } # Add the new member to the selection table. # Adding all members at the same time along with the max group size sel_table.entry_add(target, [ sel_table.make_key([gc.KeyTuple('$SELECTOR_GROUP_ID', group_id)]) ], [ sel_table.make_data([ gc.DataTuple('$MAX_GROUP_SIZE', max_grp_size), gc.DataTuple('$ACTION_MEMBER_ID', int_arr_val=members), gc.DataTuple('$ACTION_MEMBER_STATUS', bool_arr_val=member_status) ]) ]) forward_table.entry_add(target, [ forward_table.make_key( [gc.KeyTuple('ig_intr_md.ingress_port', ig_port)]) ], [ forward_table.make_data( [gc.DataTuple('$SELECTOR_GROUP_ID', group_id)]) ]) try: logger.info("Sending packet on port %d", ig_port) testutils.send_packet(self, ig_port, pkt) logger.info("Expecting packet on one of enabled ports %s", exp_ports) testutils.verify_any_packet_any_port(self, [exp_pkt], exp_ports) finally: forward_table.entry_del(target, [ forward_table.make_key( [gc.KeyTuple('ig_intr_md.ingress_port', ig_port)]) ]) # Delete Selector Table entry logger.info("Deleting Selector group id %d", group_id) sel_table.entry_del(target, [ sel_table.make_key( [gc.KeyTuple('$SELECTOR_GROUP_ID', group_id)]) ]) # Delete Action profile members for port in eg_ports: logger.info("Deleting Action profile member id %d", port) action_table.entry_del(target, [ action_table.make_key( [gc.KeyTuple('$ACTION_MEMBER_ID', port)]) ]) logger.info("Sending packet on port %d", ig_port) testutils.send_packet(self, ig_port, pkt) logger.info("Packet is expected to get dropped.") testutils.verify_no_other_packets(self)
def runTest(self): ig_port = swports[1] eg_port = swports[2] smac = '11:33:55:77:99:00' smac_mask = 'ff:ff:ff:ff:ff:ff' dmac = '00:11:22:33:44:55' # Get bfrt_info and set it as part of the test bfrt_info = self.interface.bfrt_info_get("tna_operations") pkt = testutils.simple_tcp_packet(eth_dst=dmac, eth_src=smac) exp_pkt = pkt target = client.Target(device_id=0, pipe_id=0xffff) forward_table = bfrt_info.table_get("SwitchIngress.forward") forward_table.info.key_field_annotation_add("hdr.ethernet.src_addr", "mac") forward_table.entry_add(target, [ forward_table.make_key([ client.KeyTuple('hdr.ethernet.src_addr', smac, smac_mask), client.KeyTuple('$MATCH_PRIORITY', 0) ]) ], [ forward_table.make_data([ client.DataTuple('port', eg_port), client.DataTuple('$COUNTER_SPEC_BYTES', 0), client.DataTuple('$COUNTER_SPEC_PKTS', 0) ], 'SwitchIngress.hit') ]) # Default packet size is 100 bytes and model adds 4 bytes of CRC pkt_size = 100 + 4 num_pkts = 3 num_bytes = num_pkts * pkt_size logger.info("Sending packet on port %d", ig_port) for i in range(0, num_pkts): testutils.send_packet(self, ig_port, pkt) testutils.verify_packets(self, exp_pkt, [eg_port]) logger.info("Expecting packet on port %d", eg_port) # Get count from sw. It should be 0 resp = forward_table.entry_get(target, [ forward_table.make_key([ client.KeyTuple('hdr.ethernet.src_addr', smac, smac_mask), client.KeyTuple('$MATCH_PRIORITY', 0) ]) ], {"from_hw": False}) # parse resp to get the counter data_dict = next(resp)[0].to_dict() recv_pkts = data_dict["$COUNTER_SPEC_PKTS"] recv_bytes = data_dict["$COUNTER_SPEC_BYTES"] # should be 0 if (0 != recv_pkts): logger.error("Error! expected 0 received count = %s", str(recv_pkts)) assert 0 if (0 != recv_bytes): logger.error("Error! expected 0 received count = %s", str(recv_bytes)) assert 0 # apply table op to sync counters on the direct table forward_table.operations_execute(target, 'SyncCounters') # Get count from sw. It should be correct resp = forward_table.entry_get( target, [ forward_table.make_key([ client.KeyTuple('hdr.ethernet.src_addr', smac, smac_mask), client.KeyTuple('$MATCH_PRIORITY', 0) ]) ], {"from_hw": False}, forward_table.make_data([ client.DataTuple("$COUNTER_SPEC_BYTES"), client.DataTuple("$COUNTER_SPEC_PKTS") ], 'SwitchIngress.hit')) # parse resp to get the counter data_dict = next(resp)[0].to_dict() recv_pkts = data_dict["$COUNTER_SPEC_PKTS"] recv_bytes = data_dict["$COUNTER_SPEC_BYTES"] if (num_pkts != recv_pkts): logger.error("Error! packets sent = %s received count = %s", str(num_pkts), str(recv_pkts)) assert 0 if (num_bytes != recv_bytes): logger.error("Error! bytes sent = %s received count = %s", str(num_bytes), str(recv_bytes)) assert 0 forward_table.entry_del(target, [ forward_table.make_key([ client.KeyTuple('hdr.ethernet.src_addr', smac, smac_mask), client.KeyTuple('$MATCH_PRIORITY', 0) ]) ]) logger.info("Sending packet on port %d", ig_port) testutils.send_packet(self, ig_port, pkt) logger.info("Packet is expected to get dropped.") testutils.verify_no_other_packets(self)
def runTest(self): self.group_id = 1 ig_port = swports[1] eg_ports = swports[2:-1] num_ports = len(eg_ports) target = gc.Target(device_id=dev_id, pipe_id=0xffff) # Get bfrt_info and set it as part of the test bfrt_info = self.interface.bfrt_info_get("tna_action_selector") forward_table = bfrt_info.table_get("SwitchIngress.forward") action_table = bfrt_info.table_get( "SwitchIngress.example_action_selector_ap") sel_table = bfrt_info.table_get( "SwitchIngress.example_action_selector") set_dest_table = bfrt_info.table_get("SwitchIngress.set_dest") act_prof_size = 2048 max_grp_size = 200 # Prepare action profile table by filling with members logger.info("Filling action profile table") for i in range(1, act_prof_size + 1): action_table.entry_add( target, [action_table.make_key([gc.KeyTuple('$ACTION_MEMBER_ID', i)])], [ action_table.make_data([gc.DataTuple('idx', i)], 'SwitchIngress.set_md') ]) set_dest_table.entry_add( target, [set_dest_table.make_key([gc.KeyTuple('ig_md.md', i)])], [ set_dest_table.make_data( [gc.DataTuple('port', eg_ports[i % num_ports])], 'SwitchIngress.hit') ]) # Perform some preliminary member set operations. They should all succeed # since there are no match entries pointing to the group. # Fill up the selector group logger.info("Churning selector group without match ref") members = random.sample(range(1, act_prof_size + 1), max_grp_size) member_status = [True] * max_grp_size sel_table.entry_add(target, [ sel_table.make_key( [gc.KeyTuple('$SELECTOR_GROUP_ID', self.group_id)]) ], [ sel_table.make_data([ gc.DataTuple('$MAX_GROUP_SIZE', max_grp_size), gc.DataTuple('$ACTION_MEMBER_ID', int_arr_val=members), gc.DataTuple('$ACTION_MEMBER_STATUS', bool_arr_val=member_status) ]) ]) # Disable all members member_status = [False] * max_grp_size self.modify_grp(sel_table, members, member_status) # Perform a few churns for _ in range(10): num_mbrs = random.randint(1, max_grp_size) members = random.sample(range(1, act_prof_size + 1), num_mbrs) member_status = [ random.choice([False, True]) for _ in range(num_mbrs) ] self.modify_grp(sel_table, members, member_status) # Clear the group members = [] member_status = [] self.modify_grp(sel_table, members, member_status) logger.info( "Try to add a match entry to refer to empty group. " + "This should fail, i.e. we expect an gRPC error to be displayed:") try: forward_table.entry_add(target, [ forward_table.make_key( [gc.KeyTuple('ig_intr_md.ingress_port', ig_port)]) ], [ forward_table.make_data( [gc.DataTuple('$SELECTOR_GROUP_ID', self.group_id)]) ]) except: pass usage = next(forward_table.usage_get(target)) assert usage == 0 logger.info(" Test successful") # Add a member so the match entry can be attached members = [1] member_status = [True] self.modify_grp(sel_table, members, member_status) logger.info("Adding match entry") forward_table.entry_add(target, [ forward_table.make_key( [gc.KeyTuple('ig_intr_md.ingress_port', ig_port)]) ], [ forward_table.make_data( [gc.DataTuple('$SELECTOR_GROUP_ID', self.group_id)]) ]) # Verify pkt = testutils.simple_tcp_packet() testutils.send_packet(self, ig_port, pkt) testutils.verify_any_packet_any_port(self, [pkt], [eg_ports[1]]) # Perform some membership churn. Packets should come out only on # active members. for i in range(10): logger.info("Preparing group for churn iter %d", i) num_mbrs = random.randint(1, max_grp_size) members = random.sample(range(1, act_prof_size + 1), num_mbrs) member_status = [ random.choice([False, True]) for _ in range(num_mbrs) ] # If all members are disabled by chance, ensure the API will fail, # then enable the first and move on. if True not in member_status: api_failed = False try: sel_table.entry_mod(target, [ sel_table.make_key( [gc.KeyTuple('$SELECTOR_GROUP_ID', self.group_id)]) ], [ sel_table.make_data([ gc.DataTuple('$ACTION_MEMBER_ID', int_arr_val=members), gc.DataTuple('$ACTION_MEMBER_STATUS', bool_arr_val=member_status) ]) ]) except: api_failed = True pass assert api_failed member_status[0] = True self.modify_grp(sel_table, members, member_status) logger.info("Sending some packets for churn iter %d", i) active_ports = [ eg_ports[members[idx] % num_ports] for idx, status in enumerate(member_status) if status ] for _ in range(100): eth_src = '%x:%x:%x:%x:%x:%x' % (random.randint( 0, 255), random.randint(0, 255), random.randint( 0, 255), random.randint(0, 255), random.randint( 0, 255), random.randint(0, 255)) eth_dst = '%x:%x:%x:%x:%x:%x' % (random.randint( 0, 255), random.randint(0, 255), random.randint( 0, 255), random.randint(0, 255), random.randint( 0, 255), random.randint(0, 255)) ip_src = '%d.%d.%d.%d' % (random.randint( 0, 255), random.randint(0, 255), random.randint( 0, 255), random.randint(0, 255)) ip_dst = '%d.%d.%d.%d' % (random.randint( 0, 255), random.randint(0, 255), random.randint( 0, 255), random.randint(0, 255)) pkt = testutils.simple_tcp_packet(eth_src=eth_src, eth_dst=eth_dst, ip_src=ip_src, ip_dst=ip_dst) testutils.send_packet(self, ig_port, pkt) testutils.verify_any_packet_any_port(self, [pkt], active_ports) # Try to empty or delete the group. Should fail since there is a match # reference logger.info( "Try to empty or delete a group with active references. " + "This should fail, i.e. we expect an gRPC error to be displayed:") try: members = [] member_status = [] sel_table.entry_mod(target, [ sel_table.make_key( [gc.KeyTuple('$SELECTOR_GROUP_ID', self.group_id)]) ], [ sel_table.make_data([ gc.DataTuple('$ACTION_MEMBER_ID', int_arr_val=members), gc.DataTuple('$ACTION_MEMBER_STATUS', bool_arr_val=member_status) ]) ]) except: pass get_resp = sel_table.entry_get(target, [ sel_table.make_key( [gc.KeyTuple('$SELECTOR_GROUP_ID', self.group_id)]) ], {"from_hw": False}) data_dict = next(get_resp)[0].to_dict() assert len(data_dict["$ACTION_MEMBER_ID"]) > 0 try: sel_table.entry_del(target, [ sel_table.make_key( [gc.KeyTuple('$SELECTOR_GROUP_ID', self.group_id)]) ]) except: pass usage = next(sel_table.usage_get(target)) assert usage == 1 # Delete match entry logger.info("Deleting match entry") forward_table.entry_del(target, [ forward_table.make_key( [gc.KeyTuple('ig_intr_md.ingress_port', ig_port)]) ]) # Delete Selector Table entry logger.info("Deleting Selector group id %d", self.group_id) sel_table.entry_del(target, [ sel_table.make_key( [gc.KeyTuple('$SELECTOR_GROUP_ID', self.group_id)]) ]) # Delete Action profile members logger.info("Deleting action profile members") for i in range(1, act_prof_size + 1): action_table.entry_del( target, [action_table.make_key([gc.KeyTuple('$ACTION_MEMBER_ID', i)])]) set_dest_table.entry_del( target, [set_dest_table.make_key([gc.KeyTuple('ig_md.md', i)])]) logger.info("Sending packet on port %d", ig_port) testutils.send_packet(self, ig_port, pkt) logger.info("Packet is expected to get dropped.") testutils.verify_no_other_packets(self)