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 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:
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 |
- {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.