Problems encountered with p4runtime

I plan to use P4runtime to assume forwarding rules for my switch, but I ran into the following problem。


and my code is following:

    p4info_helper = p4runtime_lib.helper.P4InfoHelper(p4info_file_path)

    try:

        s1 = p4runtime_lib.bmv2.Bmv2SwitchConnection(
            name='s1',
            address='127.0.0.1:50051',
            device_id=0,
            proto_dump_file='logs/s1-p4runtime-request.txt'
        )
        s2 = p4runtime_lib.bmv2.Bmv2SwitchConnection(
            name='s2',
            address='127.0.0.1:50052',
            device_id=1,
            proto_dump_file='logs/s2-p4runtime-request.txt'
        )
        s3 = p4runtime_lib.bmv2.Bmv2SwitchConnection(
            name='s3',
            address='127.0.0.1:50053',
            device_id=2,
            proto_dump_file='logs/s3-p4runtime-request.txt'
        )
        s4 = p4runtime_lib.bmv2.Bmv2SwitchConnection(
            name='s4',
            address='127.0.0.1:50054',
            device_id=3,
            proto_dump_file='logs/s4-p4runtime-request.txt'
        )
        s5 = p4runtime_lib.bmv2.Bmv2SwitchConnection(
            name='s5',
            address='127.0.0.1:50055',
            device_id=4,
            proto_dump_file='logs/s5-p4runtime-request.txt'
        )

        s1.MasterArbitrationUpdate()
        s2.MasterArbitrationUpdate()
        s3.MasterArbitrationUpdate()
        s4.MasterArbitrationUpdate()
        s5.MasterArbitrationUpdate()

        #在交换机上安装P4程序
        s1.SetForwardingPipelineConfig(p4info=p4info_helper.p4info, bmv2_json_file_path=bmv2_file_path)
        print("Installed P4 Program using SetForwardingPipelingeConfig on s1")

        s2.SetForwardingPipelineConfig(p4info=p4info_helper.p4info, bmv2_json_file_path=bmv2_file_path)
        print("Installed P4 Program using SetForwardingPipelingeConfig on s2")

        s3.SetForwardingPipelineConfig(p4info=p4info_helper.p4info, bmv2_json_file_path=bmv2_file_path)
        print("Installed P4 Program using SetForwardingPipelingeConfig on s3")

        s4.SetForwardingPipelineConfig(p4info=p4info_helper.p4info, bmv2_json_file_path=bmv2_file_path)
        print("Installed P4 Program using SetForwardingPipelingeConfig on s4")

        s5.SetForwardingPipelineConfig(p4info=p4info_helper.p4info, bmv2_json_file_path=bmv2_file_path)
        print("Installed P4 Program using SetForwardingPipelingeConfig on s5")
        writeRules(p4info_helper, switch_name=s1, table_name="MyIngress.Is_local_ip", action="NoAction", match_fields="hdr.ipv4.dstAddr", match_value="192.168.7.128")
        writeRules(p4info_helper, switch_name=s3, table_name="MyIngress.Is_local_ip", action="NoAction", match_fields="hdr.ipv4.dstAddr", match_value="192.168.10.128")
        writeRules(p4info_helper, switch_name=s3, table_name="MyIngress.Is_local_ip", action="NoAction", match_fields="hdr.ipv4.dstAddr", match_value="192.168.11.128")
        writeRules(p4info_helper, switch_name=s5, table_name="MyIngress.Is_local_ip", action="NoAction", match_fields="hdr.ipv4.dstAddr", match_value="192.168.8.128")
        

        #ipv4_route
        writeRouteRules(p4info_helper, switch_name=s1, table_name="MyIngress.ipv4_lpm", action="MyIngress.ipv4_forward", match_fields="hdr.ipv4.dstAddr", match_value="10.0.1.2", value1="00:00:0a:00:01:02", value2=1)
        writeRouteRules(p4info_helper, switch_name=s1, table_name="MyIngress.ipv4_lpm", action="MyIngress.ipv4_forward", match_fields="hdr.ipv4.dstAddr", match_value="192.168.7.129", value1="b4:05:5d:9d:a9:20", value2=2)
        writeRouteRules(p4info_helper, switch_name=s1, table_name="MyIngress.ipv4_lpm", action="MyIngress.ipv4_forward", match_fields="hdr.ipv4.dstAddr", match_value="192.168.10.128", value1="b4:05:5d:9d:a9:20", value2=2)
        writeRouteRules(p4info_helper, switch_name=s1, table_name="MyIngress.ipv4_lpm", action="MyIngress.ipv4_forward", match_fields="hdr.ipv4.dstAddr", match_value="192.168.11.129", value1="b4:05:5d:9d:a9:20", value2=2)
      
        writeRouteRules(p4info_helper, switch_name=s2, table_name="MyIngress.ipv4_lpm", action="MyIngress.ipv4_forward", match_fields="hdr.ipv4.dstAddr", match_value="192.168.7.128", value1="b4:05:5d:9d:a8:20", value2=1)
        writeRouteRules(p4info_helper, switch_name=s2, table_name="MyIngress.ipv4_lpm", action="MyIngress.ipv4_forward", match_fields="hdr.ipv4.dstAddr", match_value="192.168.10.128", value1="b4:05:5d:9d:aa:50", value2=2)
        writeRouteRules(p4info_helper, switch_name=s2, table_name="MyIngress.ipv4_lpm", action="MyIngress.ipv4_forward", match_fields="hdr.ipv4.dstAddr", match_value="192.168.11.129", value1="b4:05:5d:9d:aa:50", value2=2)
        writeRouteRules(p4info_helper, switch_name=s2, table_name="MyIngress.ipv4_lpm", action="MyIngress.ipv4_forward", match_fields="hdr.ipv4.dstAddr", match_value="192.168.8.128", value1="b4:05:5d:9d:aa:50", value2=2)

        writeRouteRules(p4info_helper, switch_name=s3, table_name="MyIngress.ipv4_lpm", action="MyIngress.ipv4_forward", match_fields="hdr.ipv4.dstAddr", match_value="192.168.7.128", value1="b4:05:5d:9d:aa:21", value2=1)
        writeRouteRules(p4info_helper, switch_name=s3, table_name="MyIngress.ipv4_lpm", action="MyIngress.ipv4_forward", match_fields="hdr.ipv4.dstAddr", match_value="192.168.10.129", value1="b4:05:5d:9d:aa:21", value2=1)
        writeRouteRules(p4info_helper, switch_name=s3, table_name="MyIngress.ipv4_lpm", action="MyIngress.ipv4_forward", match_fields="hdr.ipv4.dstAddr", match_value="192.168.11.129", value1="b4:05:5d:78:72:ac", value2=2)
        writeRouteRules(p4info_helper, switch_name=s3, table_name="MyIngress.ipv4_lpm", action="MyIngress.ipv4_forward", match_fields="hdr.ipv4.dstAddr", match_value="192.168.8.128", value1="b4:05:5d:78:72:ac", value2=2)

        writeRouteRules(p4info_helper, switch_name=s4, table_name="MyIngress.ipv4_lpm", action="MyIngress.ipv4_forward", match_fields="hdr.ipv4.dstAddr", match_value="192.168.7.128", value1="b4:05:5d:9d:aa:f0", value2=1)
        writeRouteRules(p4info_helper, switch_name=s4, table_name="MyIngress.ipv4_lpm", action="MyIngress.ipv4_forward", match_fields="hdr.ipv4.dstAddr", match_value="192.168.10.129", value1="b4:05:5d:9d:aa:f0", value2=1)
        writeRouteRules(p4info_helper, switch_name=s4, table_name="MyIngress.ipv4_lpm", action="MyIngress.ipv4_forward", match_fields="hdr.ipv4.dstAddr", match_value="192.168.11.128", value1="b4:05:5d:9d:aa:f0", value2=1)
        writeRouteRules(p4info_helper, switch_name=s4, table_name="MyIngress.ipv4_lpm", action="MyIngress.ipv4_forward", match_fields="hdr.ipv4.dstAddr", match_value="192.168.8.128", value1="b4:05:5d:9d:23:21", value2=2)

        writeRouteRules(p4info_helper, switch_name=s5, table_name="MyIngress.ipv4_lpm", action="MyIngress.ipv4_forward", match_fields="hdr.ipv4.dstAddr", match_value="10.0.2.2", value1="00:00:0a:00:02:02", value2=2)
        writeRouteRules(p4info_helper, switch_name=s5, table_name="MyIngress.ipv4_lpm", action="MyIngress.ipv4_forward", match_fields="hdr.ipv4.dstAddr", match_value="192.168.10.129", value1="b4:05:5d:78:72:ab", value2=1)
        writeRouteRules(p4info_helper, switch_name=s5, table_name="MyIngress.ipv4_lpm", action="MyIngress.ipv4_forward", match_fields="hdr.ipv4.dstAddr", match_value="192.168.11.128", value1="b4:05:5d:78:72:ab", value2=1)
        writeRouteRules(p4info_helper, switch_name=s5, table_name="MyIngress.ipv4_lpm", action="MyIngress.ipv4_forward", match_fields="hdr.ipv4.dstAddr", match_value="192.168.8.129", value1="b4:05:5d:78:72:ab", value2=1)




        #read rules on switch
        readTableRules(p4info_helper, s1)
        readTableRules(p4info_helper, s2)
        readTableRules(p4info_helper, s3)
        readTableRules(p4info_helper, s4)
        readTableRules(p4info_helper, s5)

I cannot see the error that appears with this issue,Is this because I added too many table entries at once?How can I solve this problem?

I have omitted a part of the table that appears in the code

It is not clear at which step the failure is occurring. Do you know which is line 219 in the file 2_controller.py? Looking at that line should at least tell you on which step it failed.

If you stop all instances of simple_switch_grpc and start them all up again from scratch, does the error occur in that same place repeatedly? Or is it sometimes in one place, sometimes in another?

Thank you for your answer.

Line 219 is
writeRouteRules(p4info_helper, switch_name=s1, table_name="MyIngress.ipv4_lpm", action="MyIngress.ipv4_forward", match_fields="hdr.ipv4.dstAddr", match_value="10.0.1.2", value1="00:00:0a:00:01:02", value2=1)

On top of that there are some other rules written to the switch.Try restarting the whole project, clean it and make it again, and then execute the python program again, it still prompts this error at the same place.

Once I comment out the following writes to the ipv4_lpm table, the script can be executed normally.

So a couple of things that might or might not lead to the answer:

(1) Every P4 table has a finite size, usually declared in the P4 source code with a size = <number> table property. Attempting to add more entries than that size is either likely, or guaranteed, to fail, depending upon your target device.

(2) The P4Runtime API, which I suspect you are probably using, disallows duplicate keys from being added to a table. Are you perhaps trying to add the same key twice to the same table?

Thank you for your reply. Regarding the two possibilities you suggested, I did a detailed examination of each.
(1) My table size is 1024, and I am pretty sure that the entries in the table do not exceed this value, because the network topology is very simple.
(2) I rechecked the key values of each table imported and there are no duplicate keys in the same table of a switch.
I have a guess about whether there is a limit on the number of tables that can be imported at once in the P4 runtime API? Or is there a limit to this in simple_switch_gRPC?

There must be some finite limit to the number of P4 tables and/or other P4 objects supported by the open source P4Runtime API implementation and simple_switch_grpc, but I’d bet that limit is in the thousands, if not more.

Thank you for your reply. I really can’t check the cause of the error, the following is the declaration of this function writeRouteRules, I don’t know if there could be an error here.

def writeRouteRules(p4info_helper, switch_name, table_name, action, match_fields, match_value, value1, value2):
    if action=="MyIngress.id_forward":
        table_entry = p4info_helper.buildTableEntry(
            table_name,
            match_fields={
                match_fields: match_value
            },
            action_name=action,
            action_params={
            "dstAddr": value1,
            "srcAddr": value2
        }
        )
        switch_name.WriteTableEntry(table_entry)
        print("Installed route rules %s on %s" % (table_name, switch_name.name))
        return
    table_entry = p4info_helper.buildTableEntry(
        table_name,
        match_fields={
            match_fields: (match_value, 24)
        },
        action_name=action,
        action_params={
            "dstAddr": value1,
            "port": value2
        }
    )
    switch_name.WriteTableEntry(table_entry)
    print("Installed route rules %s on %s" % (table_name, switch_name.name))

I tried to debug the program in a single step and this message appeared:

I tried to change a line of code in writeRouteRules:

match_fields={
            match_fields: (match_value, 24)
        },

Change the 24 to 32 and the code will work
I can’t figure out why the mask would have an effect here

If you are ever attempting to add two lpm keys like “10.1.1.1/24” and “10.1.1.2/24”, those are actually both the same as “10.1.1.0/24”, and thus duplicate keys, which P4Runtime API does not allow.

I do not know if that is occurring in your case, but your mention that changing the prefix length from 24 to 32 caused the error to go away makes it possible.

Thank you very much, I think it should be so.