예제 #1
0
    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])
예제 #2
0
    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])
예제 #3
0
    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)
예제 #4
0
    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)
예제 #5
0
    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)
예제 #6
0
    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)
예제 #7
0
    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))
예제 #8
0
 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)
예제 #9
0
 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)
예제 #10
0
 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)
예제 #11
0
    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)
예제 #12
0
 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)
예제 #13
0
    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)
예제 #14
0
    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)
예제 #15
0
    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)
예제 #16
0
    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)
예제 #17
0
    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)))
예제 #18
0
    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
예제 #19
0
    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
예제 #20
0
    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)
예제 #21
0
    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)
예제 #22
0
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)
예제 #23
0
    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)
예제 #24
0
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)
예제 #25
0
    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)
예제 #26
0
    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)
예제 #27
0
    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)
예제 #28
0
    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)
예제 #29
0
    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)
예제 #30
0
    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)