P4Runtime

repository·main·Indexed 41 days ago

https://github.com/p4lang/p4runtime

A control plane protocol used to control the data plane elements of a device defined by a P4 program. It provides a precise API definition via protobuf files, a formal specification, and client/server libraries for Go, Python, and Rust (via p4runtime-prost and p4runtime-tonic).

Tokens
26.5K
Snippets
52
Records
96
Agent score
52%

What's inside P4Runtime

  1. P4Runtime Overview and Scope

    main

    P4Runtime is a control plane specification designed to provide vendor-independent, protocol-independent runtime APIs for P4-defined data planes. It allows a controller to manage P4 built-in objects (tables, Value Sets) and Portable Switch Architecture (PSA) externs (e.g., Counters, Meters, Action Profiles).

    Key Capabilities:

    • Runtime Control: Manage P4 entities and PSA externs.
    • Extension Mechanism: Control architecture-specific (non-PSA) externs.
    • Session Management: Support for SDN use-cases and controller replication.
    • Role Partitioning: Divide P4 forwarding elements into different roles for different controllers.
    • Packet I/O: Stream packets to and from the control plane.
    • Batching: Support for atomic operations.
    • Reconfiguration: In-the-field device reconfiguration with new P4 programs.

    Compatibility Note: P4Runtime is designed for P4~16~ (version 1.2.4 or later). It is recommended to use P4~16~ 1.2.5. P4~14~ programs must be translated to P4~16~ to be compatible.

  2. Perform wildcard reads with Entity messages

    main

    When performing a ReadRequest, you must specify exactly which entity types to read within the entities oneof field. P4Runtime does not support performing a wildcard read on the entire forwarding state by providing an empty Entity message. If an empty Entity message is sent, the server must return an INVALID_ARGUMENT error.

    Example of a valid Entity configuration in a ReadRequest (protobuf representation):

    device_id: "DEVICE_ID"
    entities {
      extern_entry { }  // read all extern instances
      table_entry { }  // read all table entries
      action_profile_member { }  // read all members for all action profiles
      action_profile_group { }  // read all groups for all action profiles
    }
    device_id: "DEVICE_ID"
    entities {
      extern_entry { } 
      table_entry { } 
      action_profile_member { } 
      action_profile_group { } 
    }
  3. Configure Meters and Direct Meters

    main

    Meters are used to track statistics for rate-limiting (marking or dropping packets).

    Meter Types

    • TWO_RATE_THREE_COLOR (trTCM): The standard type (RFC 2698). Uses two rates to split packets into GREEN, YELLOW, or RED. This is the default.
    • SINGLE_RATE_THREE_COLOR (srTCM): Uses one rate and an Excess Burst Size (EBS) (RFC 2697).
    • SINGLE_RATE_TWO_COLOR: A simplified version of srTCM that only marks packets GREEN or RED using a single rate (CIR) and burst size (CBS).

    Indexed vs Direct Meters

    • Indexed Meters (Meter): Provide a fixed number of independent cells. The Meter message includes a size (int64) and index_type_name.
    • Direct Meters (DirectMeter): Associated with a match-action table. The DirectMeter message includes a direct_table_id (uint32).

    Meter Specification (MeterSpec)

    Both share a preamble and a spec defining the Unit (BYTES or PACKETS) and the Type (as listed above).

    @two_rate_three_color
    direct_meter<color_type>(MeterType.bytes) my_meter;
  4. Understand P4Runtime Message Formatting Principles

    main

    Scalar vs Message Fields

    • Scalar Fields (proto3): Numeric types (default 0) and strings (default "") cannot be distinguished from an unset state. In P4Runtime, 0 and "" are reserved to mean "unset". For example, a 0 ID is an error in a WriteRequest.
    • Message Fields (proto3): An unset message field is distinguishable from a field set to its default value. This is used for wildcard operations. For example, in a CounterEntry, if the index message field is unset, the server performs a wildcard read of all entries. If it is set, only that specific index is read.

    Read-Write Symmetry

    Clients should expect that if they write an entity and then read it back, the messages will match (except for data plane volatile objects).

    Data Plane Volatile Objects

    Some objects change due to data plane actions without controller intervention. These violate strict read-write symmetry:

    • TableEntry: counter_data or meter_counter_data can change on match. elapsed_ns or idle_timeout_ns can change based on idle timeouts. PNA tables with add_on_miss: true can have entries inserted by the data plane.
    • MeterEntry / DirectMeterEntry: counter_data is modified by the data plane.
    • CounterEntry / DirectCounterEntry: data is modified by the data plane.
    • RegisterEntry: data is modified by the data plane.
  5. Recommended URI formats for `p4runtime_translation` annotations

    main

    When using the p4runtime_translation annotation in P4 code to define how types should be interpreted by P4Runtime, follow these URI naming conventions to avoid collisions and ensure clarity:

    1. PSA Architecture: Use p4.org/psa/v1/<type_name>. The p4.org domain is reserved for the p4.org organization.
    2. Proprietary Architectures: Use <domain_name>/<proprietary_arch>/<type_name>. Example: mycompany.com/our_arch/PortId.
    3. User-defined types in P4_16: If the type is not part of an architecture but defined in user code, use <domain_name>/<arch>/<P4_program>/<type_name>. The <arch> element is optional. The domain_name should be the owner of the P4 program.
  6. Understand the three types of P4 tables

    main

    Every P4 table falls into one of three categories based on how they are defined in the P4~16~ source code and how they appear in the P4Info:

    • Normal table: Neither entries nor const entries are declared. In P4Info, both is_const_table and has_initial_entries are false.
    • Constant table: Declared with const entries. These tables have immutable match entries. In P4Info, is_const_table is true. If the source code contains at least one entry, has_initial_entries is also true.
    • Preinitialized table: Declared with entries (without const). These tables have at least one entry in the source list. In P4Info, is_const_table is false and has_initial_entries is true.

    A preinitialized table can contain a mix of entries: some marked const (which behave like constant table entries) and others not marked const (which behave like normal table entries and can be modified or deleted).

  7. Manage constant tables

    main

    Constant tables (identified by is_const_table: true in P4Info) have immutable match entries.

    Allowed Operations:

    • MODIFY operations on direct resources.
    • Setting the default action (provided the default action itself is not constant).

    Restrictions:

    • Any other write update attempt must return a PERMISSION_DENIED error.
    • MODIFY requests must specify match fields and priority to identify the entry, but must not specify an action, even if it matches the existing one. Specifying an action will trigger a PERMISSION_DENIED error.

    Reading:

    • Contents can be queried via ReadRequest. The server must return table_id, match, action, is_default_action, and priority (if required), plus any direct resources.
    • Idle timeouts are not supported for static entries.
  8. Translate PSA Port Metadata for Portability

    main

    To support multiple Portable Switch Architecture (PSA) targets with different port number spaces, P4Runtime uses metadata translation. A centralized controller can use a uniform 32-bit port numbering space, which the P4Runtime server translates to the target-specific bitwidth (e.g., 9-bit or 10-bit).

    Implementation via @p4runtime_translation

    In the P4 program, use the @p4runtime_translation annotation to define how a type should be translated. The first argument is the URI for the numerical mapping (provided via out-of-band config), and the second is the SDN bitwidth.

    @p4runtime_translation("p4.org/psa/v1/PortId_t", 32)
    type bit<9> PortId_t;
    
    @p4runtime_translation("p4.org/psa/v1/PortIdInHeader_t", 32)
    type bit<32> PortIdInHeader_t;

    SDN Port Constants

    P4Runtime reserves specific 32-bit constants for special ports:

    • SDN_PORT_UNKNOWN: 0
    • SDN_PORT_MIN: 1
    • SDN_PORT_MAX: 0xfffffeff
    • SDN_PORT_RECIRCULATE: 0xfffffffa
    • SDN_PORT_CPU: 0xfffffffd
  9. Program Action Selectors using One-Shot updates

    main

    Action Selectors can be programmed using a 'one-shot' method, which is a single table_entry update that includes the entire action profile (members and groups) in one message. This is semantically equivalent to programming the table entry, the group, and the members individually using separate WriteRequest batches.

    Key Semantics:

    • Read-Write Symmetry: If a one-shot message is used for a WriteRequest, the server must return that exact same message in response to a ReadRequest (it must not return a 'desugared' version of individual members/groups).
    • Consistency: All tables associated with an action selector must use the same programming style. You cannot mix one-shot updates with ActionProfileMember/ActionProfileGroup messages for the same action selector; doing so will result in an INVALID_ARGUMENT error.
    • Mandatory Support: A P4Runtime server must support one-shot programming for action selectors. Support for the individual ActionProfileMember and ActionProfileGroup messages is optional.
    table_entry {
      table_id: 0x0212ab34
      match { /* lpm match */ }
      action {
        action_profile_action_set {
          action_profile_actions {
            action { /* set nexthop 1 */ }
            weight: 1
            watch_port: "\x01"
          }
          action_profile_actions {
            action { /* set nexthop 2 */ }
            weight: 2
            watch_port: "\x02"
          }
        }
      }
    }
  10. Configure the Forwarding Pipeline

    main

    The ForwardingPipelineConfig (often called the "Device Configuration" or "P4 Blob") is used to realize a P4 forwarding pipeline.

    It consists of:

    • p4info: The target-agnostic P4 program metadata (output of the P4 compiler).
    • p4_device_config: Opaque binary data containing target-specific configuration.
    • cookie: An optional opaque uint64 used by the control plane to uniquely identify a specific configuration version.
    message ForwardingPipelineConfig {
      config.P4Info p4info = 1;
      bytes p4_device_config = 2;
      message Cookie {
        uint64 cookie = 1;
      }
      Cookie cookie = 3;
    }
  11. Represent complex P4 types using P4Data

    main

    For complex P4 types (like struct, header, header_union, tuple, or stack), P4Runtime uses the P4Data message instead of simple binary strings. This allows the control plane to interact with structured data.

    Canonical Representation Rules

    To ensure read-write symmetry, the following rules must be followed:

    • Order of members: The order of members in P4StructLike and the order of bitstrings in P4Header must match the order in the p4info.proto specification and the original P4 declaration.
    • Invalid Headers: Represented by a P4Header where is_valid is false and the bitstrings field is empty.
    • Invalid Header Unions: Represented by a P4HeaderUnion where valid_header_name is the empty string and the valid_header field is unset.
    • Stacks: The order of entries in P4HeaderStack or P4HeaderUnionStack must be from index 0 to the last element (ascending). The length of the entries field must exactly match the compile-time size specified in P4Info.
  12. Understand P4Runtime numeric ID scopes and allocation

    main

    P4Runtime uses various numeric identifiers across its API. These IDs are categorized by their scope (where they must be unique) and allocation (who chooses the value).

    Key concepts for developers:

    • P4Info Top-Level Scope: IDs for major P4 objects (Tables, Actions, etc.) must be globally unique within a single P4Info message. These are typically chosen by the P4 compiler or the developer via @id annotations.
    • Restricted Scopes: Some IDs are only unique within a specific parent object (e.g., a MatchField ID is only unique within its containing Table or ValueSet).
    • Reference IDs: Many fields in p4runtime.proto use numeric IDs to point back to objects defined in the P4Info message.
    • The ID 0 Special Case: In P4Info, 0 is generally invalid for object IDs, but in ReadRequest messages, an ID of 0 often signifies a request to "read all objects of a certain type."