p4lang / tutorials

P4 language tutorials
Apache License 2.0
1.33k stars 881 forks source link

How to set the idle_timeout? #630

Open dairui777 opened 3 weeks ago

dairui777 commented 3 weeks ago

I want to write a P4 program to set the idle_timeout for a table entry (e.g. 10 seconds).

The BMv2 v1model implementation supports the table property support_timeout. How to set a specific idle_timeout (e.g. 10 seconds) after assigning this table property to true when defining a table?

Can I specify an idle_timeout when installing a table entry? But buildTableEntry in helper.py doesn't seem to provide such a feature.

Thanks a lot!

dairui777 commented 3 weeks ago

I modified basic to try to set idle_timeout. Specifically, I modified insertTableEntryin simple_controller.py.

def insertTableEntry(sw, flow, p4info_helper):
    table_name = flow['table']
    match_fields = flow.get('match') # None if not found
    action_name = flow['action_name']
    default_action = flow.get('default_action') # None if not found
    action_params = flow['action_params']
    priority = flow.get('priority')  # None if not found
    options = flow.get('options')

    table_entry = p4info_helper.buildTableEntry(
        table_name=table_name,
        match_fields=match_fields,
        default_action=default_action,
        action_name=action_name,
        action_params=action_params,
        priority=priority,
        options=options)

    sw.WriteTableEntry(table_entry)

I also modified buildTableEntryin helper.py.

def buildTableEntry(self,
                        table_name,
                        match_fields=None,
                        default_action=False,
                        action_name=None,
                        action_params=None,
                        priority=None,
                        options=None):
        table_entry = p4runtime_pb2.TableEntry()
        table_entry.table_id = self.get_tables_id(table_name)

        if priority is not None:
            table_entry.priority = priority

        if match_fields:
            table_entry.match.extend([
                self.get_match_field_pb(table_name, match_field_name, value)
                for match_field_name, value in match_fields.items()
            ])

        if default_action:
            table_entry.is_default_action = True

        if action_name:
            action = table_entry.action.action
            action.action_id = self.get_actions_id(action_name)
            if action_params:
                action.params.extend([
                    self.get_action_param_pb(action_name, field_name, value)
                    for field_name, value in action_params.items()
                ])

        if options is not None:
            if "idle_timeout_ns" in options:
                table_entry.idle_timeout_ns = options["idle_timeout_ns"]
                print("===dr debug=== options")
                print(options["idle_timeout_ns"])
                print("===dr debug=== options")
            if "elapsed_ns" in options:
                table_entry.time_since_last_hit.elapsed_ns = options["elapsed_ns"]

        return table_entry

I also modified table_entries in s1-runtime.json. The "idle_timeout_ns": 10000000000 means that I want to set idle_timeout as 10 seconds.

"table_entries": [
    {
      "table": "MyIngress.ipv4_lpm",
      "default_action": true,
      "action_name": "MyIngress.drop",
      "action_params": { }
    },
    {
      "table": "MyIngress.ipv4_lpm",
      "match": {
        "hdr.ipv4.dstAddr": ["10.0.1.1", 32]
      },
      "action_name": "MyIngress.ipv4_forward",
      "action_params": {
        "dstAddr": "08:00:00:00:01:11",
        "port": 1
      },
      "options": {
        "idle_timeout_ns": 10000000000
      }
    }
]

I then ran basic and used simple_switch_CLI to look at the table entries and found that the table entries were not deleted due to a timeout. But idle_timeout seems to be in effect. Is the operation of deleting a timeout table entry something that needs to be implemented separately? image

Thanks a lot!

jafingerhut commented 3 weeks ago

There is an example P4 program using the v1model architecture and the idle_timeout feature, and a Python program that does automated testing of it, that you can find here: https://github.com/jafingerhut/p4-guide/tree/master/ptf-tests/idletimeout

I have not read your last comment and understood it in detail, but I would guess you have already figured out a significant fraction of what you were hoping to find out, already, but maybe take a look at my test program above and see if it answers any more of your questions.

jafingerhut commented 3 weeks ago

Oh, and idle_timeout only NOTIFIES the control plane when table entries have not been matched for a long time. It does not automatically delete them. It is up to the control plane software to do that, if it wishes to.

The PNA architecture defines a way to have a table that behaves this way, but also defines a way to define a table where the data plane automatically deletes the entries that are not matched for this timeout duration. I am not aware of any open source implementation in a software switch of this behavior, but there are commercially sold programmable NICs that do implement this.

dairui777 commented 2 weeks ago

Thanks for your help!

I want to implement the deletion of idle timeout table entries in the P4 tutorial project. In the P4 tutorial, how does the controller receive idle timeout notification messages generated by the switch? Thank you.

jafingerhut commented 2 weeks ago

All P4Runtime API clients receive idle timeout notifications from the switch via specific kinds of gRPC messages, over the same TCP connection that the controller uses to send table insert, modification, and delete operations.

I am not certain, but I believe there might not currently be any exercises that demonstrate this.

Because these idle timeout notifications are unsolicited messages from the switch, where by "unsolicited" I simply mean the switch can generate them at any time, without the controller having first made a request, it requires some extra code in the controller to check for these unsolicited messages.

If such code has been developed in Python in the tutorials repository, I am unaware of it. If you are interested in looking for such Python code in the tutoraisl repository and taking advantage of it to create a new exercise that demonstrates this feature, and/or developing new Python code in the tutorials repo to demonstrate this feature, please consider doing so.