Differences in serializable_enums encoding and missing enums in generated p4info / pipeline files

Hi,

While working with the DASH P4 program, I noticed some differences in how serializable_enums are represented in the generated p4info text format, as well as some missing enum definitions. For example, I see two different encodings for the same enum values:

serializable_enums {
  key: "dash_tunnel_dscp_mode_t"
  value {
    underlying_type { bitwidth: 16 }
    members {
      name: "PRESERVE_MODEL"
      value: "\000\000"
    }
    members {
      name: "PIPE_MODEL"
      value: "\000\001"
    }
  }
}

and alternatively:

   "dash_tunnel_dscp_mode_t": {
    "underlyingType": {
     "bitwidth": 16
    },
    "members": [
     {
      "name": "PRESERVE_MODEL",
      "value": "AAA="
     },
     {
      "name": "PIPE_MODEL",
      "value": "AAE="
     }
    ]
   },

Both represent the same underlying values (0x0000 and 0x0001), but the encoding differs — one uses escaped binary (\000\001), the other uses base64 ("AAE="). The first one is form the dash_pipeline_p4rt.txt file and the other one is from the dash_pipeline_p4rt.json

My questions are:

  1. What is the difference between these two encodings in practice?
    Are both valid according to the P4Runtime spec, or is one preferred for serializable_enum values in p4info?

  2. I’ve noticed that not all serializable_enums defined in dash_headers.p4 and dash_metadata.p4 are emitted into the generated dash_pipeline_p4rt.json / .txt files.
    Specifically, the following enums are defined in the P4 source but do not appear in the serializable_enums section of the p4info:

    dash_pipeline_stage_t
    dash_eni_mac_type_t
    dash_packet_source_t
    dash_packet_subtype_t
    dash_packet_type_t
    

    I’d like to understand why these are omitted. Is this:

    • Because they’re not referenced in any tables, actions, or metadata?

    • A backend/compiler optimization to exclude unused types?

    • A bug or limitation in p4c or the DASH build flow?

From the P4Runtime v1.0.0 Specification §8.5.5:

“Serializable enum types have an underlying fixed-width unsigned integer representation (bit). All named enum members must be assigned an integer value by the P4 programmer, but not all valid numeric values for the underlying type need to have a corresponding name. P4TypeInfo includes the mapping between entry name and entry value…”

However, it’s not clear:

  • Under what circumstances a serializable_enum defined in the P4 source is guaranteed to appear in the p4info output.

  • Whether there’s a way to force inclusion of all defined enums regardless of their usage.

  • Why different generated files sometimes use base64 vs escaped binary for the same values.

  • If different backends or versions of p4c generate escaped vs base64 encodings.

Is there a known rule for when enums appear in p4info, or a flag to force inclusion of all serializable enums regardless of usage?

Thanks!

I do not know all the details, but I am fairly certain that there are different representations of Protobuf messages, at least these:

  • binary, typically used between production programs using Protobuf. Properties: smallest representation, most difficult for humans to read, file name suffix is I think .bin in p4c
  • Protobuf text format, intended for debugging or other situations where humans want to easily understand the contents. Typical file name suffix is .txtpb. Relevant Protobuf documentation: Text Format Language Specification | Protocol Buffers Documentation
  • Protobuf JSON format, also fairly human-readable, and also a text format, but NOT the same format as Protobuf text format. I think this is also called ProtoJSON format. The documentation shows that values with Protobuf type “bytes” are represented in JSON files as base64. Relevant Protobuf documentation: ProtoJSON Format | Protocol Buffers Documentation

I suspect what you are comparing are two different files, one using the Protobuf text format, and the other using the Protobuf JSON format.

I suspect that P4Info generation only includes the definitions of enum types that are needed to define the type of some object in the P4Info file, e.g. the type of a table key field, or the type of an action parameter, etc. If an enum is not used as the type of anything in the P4Info file, then its definition isn’t absolutely necessary for the controller to know in order to create P4Runtime API messages.

i am not aware of any compiler flag to force inclusion of all serializable enums regardless of usage.

Thanks for the response.

The enum dash_pipeline_stage_t is defined in dash_headers.p4(1) file and is used in multiple source files (2), but when I search the dash_pipeline_p4rt.json file (3), I couldn’t find it in it but it is already used at multiple points. So I’m unable to understand why is not part of the output generated by p4-compiler.

Thanks

OK, here is a complete list of all 5 enum types that appear in a recent version of source file dash-pipeline-v1model-bmv2.p4, a recent version of that from the p4c repository, and some analysis of how they are used in that P4 program.

Version of GitHub - p4lang/p4c: P4_16 reference compiler repository tested:

$ git log -n 1 | cat
commit 2265f80459e06a89ffba26cb51c42cc05b1c023e
Author: Chris Dodd <cdodd@nvidia.com>
Date:   Tue Sep 30 11:48:12 2025 -0700

    Extend CopyStructures to optionally copy tuples (#5364)
    
    Signed-off-by: Chris Dodd <cdodd@nvidia.com>

Command I used to compile source file dash-pipeline-v1model-bmv2.p4

p4c \
    --target bmv2 \
    --arch v1model \
    --p4runtime-files dash-pipeline-v1model-bmv2.p4info.txtpb \
    dash-pipeline-v1model-bmv2.p4

Below is a complete list of all enum type definitions in
dash-pipeline-v1model-bmv2.p4, and some notes about how they are used
in the P4 program, and whether they appear in the P4Info file.


enum bit<16> dash_encapsulation_t {
Defined in P4info file? yes

This type is the type of at least one action parameter, e.g. for
action route_service_tunnel, and that action definition appeared in
the P4Info file because the action is a possible action that can be
configured for the entries of multiple tables in the P4Info file.
Thus the controller needs to know about this type in order to
configure those tables with all of the actions provided by the P4
program.


enum bit<16> dash_tunnel_dscp_mode_t {
Defined in P4info file? yes

Similar to type dash_encapsulation_t


enum bit<16> dash_direction_t {
Defined in P4info file? yes

Only appears as the definition of the enum in the P4Info file, not as
the type of any table key field or action parameter. In the P4
program, it is not used as the type of any table key field or action
parameter, either. I do not know why this type is included in the
P4Info file.


enum bit<32> dash_routing_actions_t {
Defined in P4info file? no

Values of type dash_routing_actions_t are used on the right-hand side
of assignment statements, but no key fields or action parameters have
this type. Thus it is not absolutely 100% required for the controller
to know this type in order to construct P4Info messages. It might be
useful to know for other reasons, but not for the construction of
P4Info messages.


enum bit<16> dash_pipeline_stage_t {
Defined in P4info file? no

Similar to type dash_routing_actions_t

Thanks for the detailed breakdown.

One thing I’m still trying to understand: why does dash_direction_t get included in the P4Info file while dash_routing_actions_t does not? Since neither seems to be used in any action parameters or table keys (so the controller wouldn’t really need to know about them), what drives that difference in behavior?

I do not know the answer to why one is included in the P4Info file but the other is not.

The answer to why lies in the implementation of the code in p4c that generates P4Info files, plus the front-end passes of p4c that are executed before that P4Info generation code begins (so-called “mid-end” passes of p4c and any back-end passes for a particular target are all executed after P4Info files are generated, so cannot affect the contents of generated P4Info files).

The code for generating P4Info files is all in the control-plane directory of the p4c repository here: p4c/control-plane at main · p4lang/p4c · GitHub

Without knowing the answer already, my best guesses would be (a) there is something in the intermediate representation of p4c and its front-end passes such that some enum types are eliminated before the P4Info files are generated, or (b) there is some conditions on which types are generated in P4Info files in the control-plane directory source code itself that control which are included and which are left out, or (c) some combination of those two factors.

You can run a command like the one in this very simple bash script [1], it causes p4c to write out P4 source code representing the contents of p4c’s intermediate representation after each front-end pass executes. You can look through those to see if, and at which stage, enum definitions are changed, and the last of those front-end passes should represent the state of the IR just before P4Info files are created.

[1] p4-guide/bin/p4c-dump-many-passes.sh at master · jafingerhut/p4-guide · GitHub