Modeling User Externs - 2022.2 English - UG1308

Vitis Networking P4 User Guide (UG1308)

Document ID
UG1308
Version
2022.2 English
Revision

The Vitis Networking P4 behavioral model is provided as a precompiled executable, but it supports the dynamic loading of additional shared object (.so) files which can contain code to simulate the behavior of the custom functionality. If a P4 program contains instances of UserExtern, the model must be extended in this way before it will be possible to launch it using the JSON emitted by the compiler for the P4 program in question. Doing so without extending the model causes the model to treat the portion of the JSON describing the UserExtern as invalid, resulting in an error message that begins as follows:

Invalid reference to extern type 'minimal_user_extern_example'
bad_json:
   <unrecognised JSON declaration is printed here>

The behavioral model accepts a command line argument, --load-modules, which takes a comma-separated list of shared object files as the parameter value. On program startup, the behavioral model parses the list, scans the directories specified by the LD_LIBRARY_PATH environment variable for matching files and loads the first match it finds for each entry in the list. The shared object(s) specified should provide suitable definitions for all instances of UserExtern present in the P4 program being modeled.

The user_externs.cpp file provided contains a minimal example of the declarations needed to create a shared object that models the UserExtern instance from the user_externs.p4 file.

The source file is heavily commented, but the steps required are detailed here for convenience:
  • The C++ file must define a class with the same name as the instance of the UserExtern in the P4 code.
  • The defined class must publicly inherit from a behavioral modeling class named ExternType.
  • The defined class must contain the following statement in the public region:
    • BM_EXTERN_ATTRIBUTES {}
    • This statement is a macro which generates the appropriate constructor for the class.
  • The defined class must contain a public method that conforms to the following specification:
    • Return type: void
    • Name: apply
    • Number of parameters: 2
    • First parameter: const reference of correct data type
    • Second parameter: non-const reference of correct data type
  • Following the class definition, the class must be installed using the BM_REGISTER_EXTERN() macro.
    • This class takes a single parameter, the name of the class being registered.
  • Following the installation of the class definition, the apply() method must be installed using the BM_REGISTER_EXTERN_METHOD() macro:
    • First parameter: the name of the class for which the method is being registered
    • Second parameter: apply
    • Third parameter: const reference of correct data type
    • Fourth parameter: non-const reference of correct data type

The correct data type to be used depends on the data type of the parameter passed to the apply() method in the original P4 program. This is where an understanding of the compiler's JSON output comes into play. Examine the section of the JSON that describes the invocation of the apply() method to identify the correct type to use in the C++ code. The following table presents a mapping between the "type" attribute in JSON and the corresponding C++ type:

Table 1. Mappings
JSON TYPE C++ TYPE NOTE
hexstr Data & Parameter passed in P4 is a constant
runtime_data Data & Parameter passed in P4 is an action parameter
field Field & Parameter passed in P4 is a local variable/metadata field/header field
header Header & Parameter passed in P4 is a structure/header
The behavior modeled in user_externs.cpp is to "round-trip" a value, that is, the input passed is propagated directly to the output. While this example is trivial, far more sophisticated modeling is possible. A full discussion of the possibilities is outside the scope of this document, but users are advised to refer to the definitions in the following files to gain an understanding of the operations that can be performed on the parameters to the apply() method:
  • {XILINX_VIVADO}/examples/vitis_net_p4_examples/user_externs/include/bm/bm_sim/data.h
  • {XILINX_VIVADO}/examples/vitis_net_p4_examples/user_externs/include/bm/bm_sim/fields.h
  • {XILINX_VIVADO}/examples/vitis_net_p4_examples/user_externs/include/bm/bm_sim/headers.h

At this point it is worth highlighting a key feature of the UserExtern support in Vitis Networking P4. There is a one-to-one relationship between an instance of the UserExtern object in P4 and the classes needed to model that instance in C++, that is, one C++ class definition per UserExtern instance. This means that an arbitrary number of instances can be modeled, because the link between P4 and the behavioral model is done on a per-instance basis.