diff --git a/CMakeLists.txt b/CMakeLists.txt index cb848e2bab..a97cd724e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -544,6 +544,16 @@ set (OTHER_HEADERS add_custom_target(update_includes ALL COMMAND ${CMAKE_COMMAND} -E make_directory ${P4C_BINARY_DIR}/p4include COMMAND ${CMAKE_COMMAND} -E copy_if_different ${P4C_SOURCE_DIR}/p4include/*.p4 ${P4C_BINARY_DIR}/p4include + + COMMAND ${CMAKE_COMMAND} -E make_directory ${P4C_BINARY_DIR}/p4include/_internal + COMMAND ${CMAKE_COMMAND} -E make_directory ${P4C_BINARY_DIR}/p4include/_internal/pna + COMMAND ${CMAKE_COMMAND} -E make_directory ${P4C_BINARY_DIR}/p4include/_internal/pna/v0_5 + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${P4C_SOURCE_DIR}/p4include/_internal/pna/v0_5/*.p4 ${P4C_BINARY_DIR}/p4include/_internal/pna/v0_5 + COMMAND ${CMAKE_COMMAND} -E make_directory ${P4C_BINARY_DIR}/p4include/_internal/pna/v0_7 + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${P4C_SOURCE_DIR}/p4include/_internal/pna/v0_7/*.p4 ${P4C_BINARY_DIR}/p4include/_internal/pna/v0_7 + COMMAND ${CMAKE_COMMAND} -E make_directory ${P4C_BINARY_DIR}/p4include/_internal/pna/dev + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${P4C_SOURCE_DIR}/p4include/_internal/pna/dev/*.p4 ${P4C_BINARY_DIR}/p4include/_internal/pna/dev + COMMAND ${CMAKE_COMMAND} -E make_directory ${P4C_BINARY_DIR}/p4include/bmv2 COMMAND ${CMAKE_COMMAND} -E copy_if_different ${P4C_SOURCE_DIR}/p4include/bmv2/psa.p4 ${P4C_BINARY_DIR}/p4include/bmv2 COMMAND ${CMAKE_COMMAND} -E make_directory ${P4C_BINARY_DIR}/p4include/dpdk diff --git a/backends/tc/ebpfCodeGen.cpp b/backends/tc/ebpfCodeGen.cpp index 3bb5a0c433..bb87c15808 100644 --- a/backends/tc/ebpfCodeGen.cpp +++ b/backends/tc/ebpfCodeGen.cpp @@ -1235,7 +1235,10 @@ const PNAEbpfGenerator *ConvertToEbpfPNA::build(const IR::ToplevelBlock *tlb) { !d->is()) { if (d->srcInfo.isValid()) { auto sourceFile = d->srcInfo.getSourceFile(); - if (sourceFile.endsWith("/pna.p4")) { + // TODO: Similar logic exists in frontends/p4/toP4/toP4.cpp. Consider replacing + // the hard-coding here with a better long term solution. + if (sourceFile.endsWith("/pna.p4") || + sourceFile.find("p4include/_internal") != nullptr) { // do not generate standard PNA types continue; } diff --git a/frontends/common/parser_options.cpp b/frontends/common/parser_options.cpp index 649888bc97..c9cf1dffd2 100644 --- a/frontends/common/parser_options.cpp +++ b/frontends/common/parser_options.cpp @@ -41,6 +41,7 @@ limitations under the License. * machine, the 'p4includePath' would contain the path on the original machine. */ const char *p4includePath = CONFIG_PKGDATADIR "/p4include"; +const char *p4includeInternalPath = CONFIG_PKGDATADIR "/p4include/_internal"; const char *p4_14includePath = CONFIG_PKGDATADIR "/p4_14include"; const char *ParserOptions::defaultMessage = "Compile a P4 program"; diff --git a/frontends/common/parser_options.h b/frontends/common/parser_options.h index 3328394e8f..3841d9dc96 100644 --- a/frontends/common/parser_options.h +++ b/frontends/common/parser_options.h @@ -32,6 +32,7 @@ limitations under the License. // Standard include paths for .p4 header files. The values are determined by // `configure`. extern const char *p4includePath; +extern const char *p4includeInternalPath; extern const char *p4_14includePath; // Base class for compiler options. diff --git a/frontends/p4/toP4/toP4.cpp b/frontends/p4/toP4/toP4.cpp index fffd2702b1..4f7602f72e 100644 --- a/frontends/p4/toP4/toP4.cpp +++ b/frontends/p4/toP4/toP4.cpp @@ -53,6 +53,15 @@ bool ToP4::isSystemFile(cstring file) { return false; } +// Try to guess whether a file is a "system internal" file +bool ToP4::isSystemInternalFile(cstring file) { + if (noIncludes) return false; + if (file.startsWith(p4includeInternalPath) || file.find("p4include/_internal") != nullptr) { + return true; + } + return false; +} + cstring ToP4::ifSystemFile(const IR::Node *node) { if (!node->srcInfo.isValid()) return nullptr; auto sourceFile = node->srcInfo.getSourceFile(); @@ -165,7 +174,11 @@ bool ToP4::preorder(const IR::P4Program *program) { * non-system header */ if (includesEmitted.find(sourceFile) == includesEmitted.end()) { - if (sourceFile.startsWith(p4includePath)) { + if (isSystemFile(sourceFile)) { + // Skip the include if it's an internal system header. + // TODO: This is a temporary hack. Need to figure out a better solution. + if (isSystemInternalFile(sourceFile)) continue; + const char *p = sourceFile.c_str() + strlen(p4includePath); if (*p == '/') p++; if (P4V1::V1Model::instance.file.name == p) { diff --git a/frontends/p4/toP4/toP4.h b/frontends/p4/toP4/toP4.h index 2541022c7d..ecac214c17 100644 --- a/frontends/p4/toP4/toP4.h +++ b/frontends/p4/toP4/toP4.h @@ -72,6 +72,7 @@ class ToP4 : public Inspector { listTerminators.pop_back(); } bool isSystemFile(cstring file); + bool isSystemInternalFile(cstring file); cstring ifSystemFile(const IR::Node *node); // return file containing node if system file // dump node IR tree up to depth - in the form of a comment void dump(unsigned depth, const IR::Node *node = nullptr, unsigned adjDepth = 0); diff --git a/p4include/_internal/pna/README.md b/p4include/_internal/pna/README.md new file mode 100644 index 0000000000..bf503fcc8c --- /dev/null +++ b/p4include/_internal/pna/README.md @@ -0,0 +1,9 @@ +# PNA Standard Libraries + +In this directory, we decompose different versions of the standard `pna.p4` library (as specified in https://github.com/p4lang/pna) into smaller reusable components. Actual backends supporting PNA might modify some of these components in their target-specific `pna.p4` (e.g. `p4include/dpdk/pna.p4`). + +| Version | Release Date | PNA Repo Commit | PNA Spec Link | +| ------- | ------------ | -------------- | ------------- | +| `dev` | N/A | N/A | https://p4.org/p4-spec/docs/pna-working-draft-html-version.html | +| `v0.7` | 2022-12-22 | [9aef684](https://github.com/p4lang/pna/tree/9aef684a8d8e4d1d8ea34b4277bfd329f33e2254) | https://p4.org/p4-spec/docs/PNA-v0.7.html | +| `v0.5` | 2021-05-18 | [e3eb99d](https://github.com/p4lang/pna/tree/e3eb99dc7d59f7a031bc672f8cf6c300f3d166fb) | https://p4.org/p4-spec/docs/PNA-v0.5.0.html | diff --git a/p4include/_internal/pna/dev/all.p4 b/p4include/_internal/pna/dev/all.p4 new file mode 100644 index 0000000000..51108c0104 --- /dev/null +++ b/p4include/_internal/pna/dev/all.p4 @@ -0,0 +1,44 @@ +/* Copyright 2020-present Intel Corporation + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef __PNA_P4__ +#define __PNA_P4__ + +#include + +/** + * P4-16 declaration of the Portable NIC Architecture + */ + +#include <_internal/pna/dev/types_core.p4> +#include <_internal/pna/dev/types_defns.p4> +#include <_internal/pna/dev/types_defns2.p4> +#include <_internal/pna/dev/funcs_int_to_header.p4> +#include <_internal/pna/dev/types_misc.p4> + +#include <_internal/pna/dev/extern_hash.p4> +#include <_internal/pna/dev/extern_checksum.p4> +#include <_internal/pna/dev/extern_counter.p4> +#include <_internal/pna/dev/extern_meter.p4> +#include <_internal/pna/dev/extern_register.p4> +#include <_internal/pna/dev/extern_random.p4> +#include <_internal/pna/dev/extern_action.p4> +#include <_internal/pna/dev/extern_digest.p4> + +#include <_internal/pna/dev/types_metadata.p4> +#include <_internal/pna/dev/extern_funcs.p4> +#include <_internal/pna/dev/blocks.p4> + +#endif // __PNA_P4__ diff --git a/p4include/_internal/pna/dev/blocks.p4 b/p4include/_internal/pna/dev/blocks.p4 new file mode 100644 index 0000000000..755dd736d7 --- /dev/null +++ b/p4include/_internal/pna/dev/blocks.p4 @@ -0,0 +1,24 @@ +// BEGIN:Programmable_blocks +parser MainParserT( + packet_in pkt, + out MH main_hdr, + inout MM main_user_meta, + in pna_main_parser_input_metadata_t istd); + +control MainControlT( + inout MH main_hdr, + inout MM main_user_meta, + in pna_main_input_metadata_t istd, + inout pna_main_output_metadata_t ostd); + +control MainDeparserT( + packet_out pkt, + inout MH main_hdr, + in MM main_user_meta, + in pna_main_output_metadata_t ostd); + +package PNA_NIC( + MainParserT main_parser, + MainControlT main_control, + MainDeparserT main_deparser); +// END:Programmable_blocks diff --git a/p4include/_internal/pna/dev/extern_action.p4 b/p4include/_internal/pna/dev/extern_action.p4 new file mode 100644 index 0000000000..b60904f5c7 --- /dev/null +++ b/p4include/_internal/pna/dev/extern_action.p4 @@ -0,0 +1 @@ +#include <_internal/pna/v0_7/extern_action.p4> diff --git a/p4include/_internal/pna/dev/extern_checksum.p4 b/p4include/_internal/pna/dev/extern_checksum.p4 new file mode 100644 index 0000000000..614ce8b594 --- /dev/null +++ b/p4include/_internal/pna/dev/extern_checksum.p4 @@ -0,0 +1 @@ +#include <_internal/pna/v0_7/extern_checksum.p4> diff --git a/p4include/_internal/pna/dev/extern_counter.p4 b/p4include/_internal/pna/dev/extern_counter.p4 new file mode 100644 index 0000000000..d05ebbd762 --- /dev/null +++ b/p4include/_internal/pna/dev/extern_counter.p4 @@ -0,0 +1 @@ +#include <_internal/pna/v0_7/extern_counter.p4> diff --git a/p4include/_internal/pna/dev/extern_digest.p4 b/p4include/_internal/pna/dev/extern_digest.p4 new file mode 100644 index 0000000000..4da3184f13 --- /dev/null +++ b/p4include/_internal/pna/dev/extern_digest.p4 @@ -0,0 +1 @@ +#include <_internal/pna/v0_7/extern_digest.p4> diff --git a/p4include/_internal/pna/dev/extern_funcs.p4 b/p4include/_internal/pna/dev/extern_funcs.p4 new file mode 100644 index 0000000000..c9a74c1485 --- /dev/null +++ b/p4include/_internal/pna/dev/extern_funcs.p4 @@ -0,0 +1,256 @@ +// The following extern functions are "forwarding" functions -- they +// all set the destination of the packet. Calling one of them +// overwrites and replaces the effect of any earlier call to any of +// the functions in this set. Only the last one executed will +// actually take effect for the packet. + +// + drop_packet +// + send_to_port + + +// drop_packet() - Cause the packet to be dropped when it finishes +// completing the main control. +// +// Invoking drop_packet() is supported only within the main control. + +extern void drop_packet(); + +// BEGIN:send_to_port +extern void send_to_port(in PortId_t dest_port); +// END:send_to_port + +// BEGIN:mirror_packet +extern void mirror_packet(in MirrorSlotId_t mirror_slot_id, + in MirrorSessionId_t mirror_session_id); +// END:mirror_packet + +// TBD: Does it make sense to have a data plane add of a hit action +// that has in, out, or inout parameters? +// +// TBD: Should we require the return value? Can most targets +// implement it? If not, consider having two separate variants of +// add_entry, one with no return value (i.e. type void). Such a +// variant of add_entry seems difficult to use correctly, if it is +// possible for entries to fail to be added. + +// BEGIN:add_entry_extern_function +// The bit width of this type is allowed to be different for different +// target devices. It must be at least a 1-bit wide type. + +typedef bit<1> AddEntryErrorStatus_t; + +const AddEntryErrorStatus_t ADD_ENTRY_SUCCESS = 0; +const AddEntryErrorStatus_t ADD_ENTRY_NOT_DONE = 1; + +// Targets may define target-specific non-0 constants of type +// AddEntryErrorStatus_t if they wish. + +// The add_entry() extern function causes an entry, i.e. a key and its +// corresponding action and action parameter values, to be added to a +// table from the data plane, i.e. without the control plane having to +// take any action at all to cause the table entry to be added. +// +// The key of the new entry added will always be the same as the key +// that was just looked up in the table, and experienced a miss. +// +// `action_name` is the name of an action that must satisfy these +// restrictions: +// + It must be an action that is in the list specified as the +// `actions` property of the table. +// + It must be possible for this action to be the action of an entry +// added to the table, e.g. it is an error if the action has the +// annotation `@defaultonly`. +// + The action to be added must not itself contain a call to +// add_entry(), or anything else that is not supported in a table's +// "hit action". +// +// Type T must be a struct type whose field names have the same name +// as the parameters of the action being added, in the same order, and +// have the same type as the corresponding action parameters. +// +// `action_params` will become the action parameters of the new entry +// to be added. +// +// `expire_time_profile_id` is the initial expire time profile id of +// the entry added. +// +// The return value will be ADD_ENTRY_SUCCESS if the entry was +// successfully added, otherwise it will be some other value not equal +// to ADD_ENTRY_SUCCESS. Targets are allowed to define only one +// failure return value, or several if they wish to provide more +// detail on the reason for the failure to add the entry. +// +// It is NOT defined by PNA, and need not be supported by PNA +// implementations, to call add_entry() within an action that is added +// as an entry of a table, i.e. as a "hit action". It is only defined +// if called within an action that is the default_action, i.e. a "miss +// action" of a table. +// +// For tables with `add_on_miss = true`, some PNA implementations +// might only support `default_action` with the `const` qualifier. +// However, if a PNA implementation can support run-time modifiable +// default actions for such a table, some of which call add_entry() +// and some of which do not, the behavior of such an implementation is +// defined by PNA, and this may be a useful feature. + +extern AddEntryErrorStatus_t add_entry( + string action_name, + in T action_params, + in ExpireTimeProfileId_t expire_time_profile_id); +// END:add_entry_extern_function + +// The following call to add_entry_if(): +// +// add_entry_if(expr, action_name, action_params, expire_time_profile_id); +// +// has exactly the same behavior as the following expression: +// +// (expr) ? add_entry(action_name, action_params, expire_time_profile_id) +// : ADD_ENTRY_NOT_DONE; +// +// and it has the same restrictions on where it can appear in a P4 +// program as that equivalent code. +// +// Rationale: At the time PNA was being designed in 2022, there were +// P4 targets, including the BMv2 software switch in the repository +// https://github.com/p4lang/behavioral-model, that did not fully +// support `if` statements within P4 actions. add_entry_if() enables +// writing P4 code without `if` statements within P4 actions that +// would otherwise require an `if` statement to express the desired +// behavior. Admittedly, this is a work-around for targets with +// limited support for `if` statements within P4 actions. See +// https://github.com/p4lang/pna/issues/63 for more details. + +extern AddEntryErrorStatus_t add_entry_if( + in bool do_add_entry, + string action_name, + in T action_params, + in ExpireTimeProfileId_t expire_time_profile_id); + +extern FlowId_t allocate_flow_id(); + + +// set_entry_expire_time() may only be called from within an action of +// a table with property 'pna_idle_timeout' having a value of +// `NOTIFY_CONTROL` or `AUTO_DELETE`. + +// Calling it causes the expiration time profile id of the matched +// entry to become equal to expire_time_profile_id. + +// It _also_ behaves as if restart_expire_timer() was called. + +extern void set_entry_expire_time( + in ExpireTimeProfileId_t expire_time_profile_id); + + +// restart_expire_timer() may only be called from within an action of +// a table with property 'pna_idle_timeout' having a value of +// `NOTIFY_CONTROL` or `AUTO_DELETE`. + +// Calling it causes the dynamic expiration timer of the entry to be +// reset, so that the entry will remain active from the now until that +// time in the future. + +// TODO: Note that there are targets that support a table with +// property pna_idle_timeout equal to `NOTIFY_CONTROL` or +// `AUTO_DELETE` such that matching an entry _does not_ cause this +// side effect to occur, i.e. it is possible to match an entry and +// _not_ do what `restart_expire_timer()` does. We should document +// this explicitly as common for PNA devices, if that is agreed upon. +// Andy is pretty sure that PSA devices were not expected to have this +// option. + +// Note that for the PSA architecture with psa_idle_timeout = +// PSA_IdleTimeout_t.NOTIFY_CONTROL, I believe there was an implicit +// assumption that _every_ time a table entry was matched, the target +// behaved as if restart_expire_timer() was called, but there was no +// such extern function defined by PSA. + +// The proposal for PNA is that it is possible to match an entry, but +// _not_ call restart_expire_timer(), and this will cause the data +// plane _not_ to restart the table entry's expiration time. That is, +// the expiration time of the entry will continue to be the same as +// before it was matched. + +extern void restart_expire_timer(); + +// The effect of this call: +// +// update_expire_info(a, b, c) +// +// is exactly the same as the effect of the following code: +// +// if (a) { +// if (b) { +// set_entry_expire_time(c); +// } else { +// restart_expire_timer(); +// } +// } + +extern void update_expire_info( + in bool update_aging_info, + in bool update_expire_time, + in ExpireTimeProfileId_t expire_time_profile_id); + + +// Set the expire time of the matched entry in the table to the value +// specified in the parameter expire_time_profile_id, if condition +// in the first parameter evaluates to true. Otherwise, the function +// has no effect. +// +// @param condition The boolean expression to evaluate to determine +// if the expire time will be set. +// @param expire_time_profile_id +// The expire time to set for the matched entry, +// if the data and value parameters are equal. +// +// Examples: +// set_entry_expire_time_if(hdr.tcp.flags == TCP_FLG_SYN && +// meta.direction == OUTBOUND, +// tcp_connection_start_time_profile_id); +// set_entry_expire_time_if(hdr.tcp.flags == TCP_FLG_ACK, +// tcp_connection_continuation_time_protile_id); +// set_entry_expire_time_if(hdr.tcp.flags == TCP_FLG_FIN, +// tcp_connection_close_time_profile_id); + +extern void set_entry_expire_time_if( + in bool condition, + in ExpireTimeProfileId_t expire_time_profile_id); + + +// SelectByDirection is a simple pure function that behaves exactly as +// the P4_16 function definition given in comments below. It is an +// extern function to ensure that the front/mid end of the p4c +// compiler leaves occurrences of it as is, visible to target-specific +// compiler back end code, so targets have all information needed to +// optimize it as they wish. + +// One example of its use is in table key expressions, for tables +// where one wishes to swap IP source/destination addresses for +// packets processed in the different directions. + +/* +T SelectByDirection( + in bool is_network_port, + in T from_net_value, + in T from_host_value) +{ + if (is_network_port) { + return from_net_value; + } else { + return from_host_value; + } +} +*/ + +// A typical call would look like this example: +// +// SelectByDirection(is_net_port(istd.input_port), hdr.ipv4.src_addr, +// hdr.ipv4.dst_addr) + +@pure +extern T SelectByDirection( + in bool is_network_port, + in T from_net_value, + in T from_host_value); diff --git a/p4include/_internal/pna/dev/extern_hash.p4 b/p4include/_internal/pna/dev/extern_hash.p4 new file mode 100644 index 0000000000..009cd9f17e --- /dev/null +++ b/p4include/_internal/pna/dev/extern_hash.p4 @@ -0,0 +1 @@ +#include <_internal/pna/v0_7/extern_hash.p4> diff --git a/p4include/_internal/pna/dev/extern_meter.p4 b/p4include/_internal/pna/dev/extern_meter.p4 new file mode 100644 index 0000000000..26911b4641 --- /dev/null +++ b/p4include/_internal/pna/dev/extern_meter.p4 @@ -0,0 +1 @@ +#include <_internal/pna/v0_7/extern_meter.p4> diff --git a/p4include/_internal/pna/dev/extern_random.p4 b/p4include/_internal/pna/dev/extern_random.p4 new file mode 100644 index 0000000000..082b2255d5 --- /dev/null +++ b/p4include/_internal/pna/dev/extern_random.p4 @@ -0,0 +1 @@ +#include <_internal/pna/v0_7/extern_random.p4> diff --git a/p4include/_internal/pna/dev/extern_register.p4 b/p4include/_internal/pna/dev/extern_register.p4 new file mode 100644 index 0000000000..5a641ef19e --- /dev/null +++ b/p4include/_internal/pna/dev/extern_register.p4 @@ -0,0 +1 @@ +#include <_internal/pna/v0_7/extern_register.p4> diff --git a/p4include/_internal/pna/dev/funcs_int_to_header.p4 b/p4include/_internal/pna/dev/funcs_int_to_header.p4 new file mode 100644 index 0000000000..a89c9edeb2 --- /dev/null +++ b/p4include/_internal/pna/dev/funcs_int_to_header.p4 @@ -0,0 +1 @@ +#include <_internal/pna/v0_7/funcs_int_to_header.p4> diff --git a/p4include/_internal/pna/dev/types_core.p4 b/p4include/_internal/pna/dev/types_core.p4 new file mode 100644 index 0000000000..4792686bb0 --- /dev/null +++ b/p4include/_internal/pna/dev/types_core.p4 @@ -0,0 +1 @@ +#include <_internal/pna/v0_7/types_core.p4> diff --git a/p4include/_internal/pna/dev/types_defns.p4 b/p4include/_internal/pna/dev/types_defns.p4 new file mode 100644 index 0000000000..5972325523 --- /dev/null +++ b/p4include/_internal/pna/dev/types_defns.p4 @@ -0,0 +1 @@ +#include <_internal/pna/v0_7/types_defns.p4> diff --git a/p4include/_internal/pna/dev/types_defns2.p4 b/p4include/_internal/pna/dev/types_defns2.p4 new file mode 100644 index 0000000000..a0ad048074 --- /dev/null +++ b/p4include/_internal/pna/dev/types_defns2.p4 @@ -0,0 +1 @@ +#include <_internal/pna/v0_7/types_defns2.p4> diff --git a/p4include/_internal/pna/dev/types_metadata.p4 b/p4include/_internal/pna/dev/types_metadata.p4 new file mode 100644 index 0000000000..2242a50c07 --- /dev/null +++ b/p4include/_internal/pna/dev/types_metadata.p4 @@ -0,0 +1 @@ +#include <_internal/pna/v0_7/types_metadata.p4> diff --git a/p4include/_internal/pna/dev/types_misc.p4 b/p4include/_internal/pna/dev/types_misc.p4 new file mode 100644 index 0000000000..918035bce4 --- /dev/null +++ b/p4include/_internal/pna/dev/types_misc.p4 @@ -0,0 +1 @@ +#include <_internal/pna/v0_7/types_misc.p4> diff --git a/p4include/_internal/pna/v0_5/all.p4 b/p4include/_internal/pna/v0_5/all.p4 new file mode 100644 index 0000000000..fb75b722c4 --- /dev/null +++ b/p4include/_internal/pna/v0_5/all.p4 @@ -0,0 +1,44 @@ +/* Copyright 2020-present Intel Corporation + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef __PNA_P4__ +#define __PNA_P4__ + +#include + +/** + * P4-16 declaration of the Portable NIC Architecture + */ + +#include <_internal/pna/v0_5/types_core.p4> +#include <_internal/pna/v0_5/types_defns.p4> +#include <_internal/pna/v0_5/types_defns2.p4> +#include <_internal/pna/v0_5/funcs_int_to_header.p4> +#include <_internal/pna/v0_5/types_misc.p4> + +#include <_internal/pna/v0_5/extern_hash.p4> +#include <_internal/pna/v0_5/extern_checksum.p4> +#include <_internal/pna/v0_5/extern_counter.p4> +#include <_internal/pna/v0_5/extern_meter.p4> +#include <_internal/pna/v0_5/extern_register.p4> +#include <_internal/pna/v0_5/extern_random.p4> +#include <_internal/pna/v0_5/extern_action.p4> +#include <_internal/pna/v0_5/extern_digest.p4> + +#include <_internal/pna/v0_5/types_metadata.p4> +#include <_internal/pna/v0_5/extern_funcs.p4> +#include <_internal/pna/v0_5/blocks.p4> + +#endif // __PNA_P4__ diff --git a/p4include/_internal/pna/v0_5/blocks.p4 b/p4include/_internal/pna/v0_5/blocks.p4 new file mode 100644 index 0000000000..8709b3ae8d --- /dev/null +++ b/p4include/_internal/pna/v0_5/blocks.p4 @@ -0,0 +1,31 @@ +// BEGIN:Programmable_blocks +control PreControlT( + in PH pre_hdr, + inout PM pre_user_meta, + in pna_pre_input_metadata_t istd, + inout pna_pre_output_metadata_t ostd); + +parser MainParserT( + packet_in pkt, + out MH main_hdr, + inout MM main_user_meta, + in pna_main_parser_input_metadata_t istd); + +control MainControlT( + inout MH main_hdr, + inout MM main_user_meta, + in pna_main_input_metadata_t istd, + inout pna_main_output_metadata_t ostd); + +control MainDeparserT( + packet_out pkt, + in MH main_hdr, + in MM main_user_meta, + in pna_main_output_metadata_t ostd); + +package PNA_NIC( + MainParserT main_parser, + PreControlT pre_control, + MainControlT main_control, + MainDeparserT main_deparser); +// END:Programmable_blocks diff --git a/p4include/_internal/pna/v0_5/extern_action.p4 b/p4include/_internal/pna/v0_5/extern_action.p4 new file mode 100644 index 0000000000..c6fa267bc6 --- /dev/null +++ b/p4include/_internal/pna/v0_5/extern_action.p4 @@ -0,0 +1,16 @@ +// BEGIN:ActionProfile_extern +extern ActionProfile { + /// Construct an action profile of 'size' entries + ActionProfile(bit<32> size); +} +// END:ActionProfile_extern + +// BEGIN:ActionSelector_extern +extern ActionSelector { + /// Construct an action selector of 'size' entries + /// @param algo hash algorithm to select a member in a group + /// @param size number of entries in the action selector + /// @param outputWidth size of the key + ActionSelector(PNA_HashAlgorithm_t algo, bit<32> size, bit<32> outputWidth); +} +// END:ActionSelector_extern diff --git a/p4include/_internal/pna/v0_5/extern_checksum.p4 b/p4include/_internal/pna/v0_5/extern_checksum.p4 new file mode 100644 index 0000000000..6a830f323a --- /dev/null +++ b/p4include/_internal/pna/v0_5/extern_checksum.p4 @@ -0,0 +1,58 @@ +// BEGIN:Checksum_extern +extern Checksum { + /// Constructor + Checksum(PNA_HashAlgorithm_t hash); + + /// Reset internal state and prepare unit for computation. + /// Every instance of a Checksum object is automatically initialized as + /// if clear() had been called on it. This initialization happens every + /// time the object is instantiated, that is, whenever the parser or control + /// containing the Checksum object are applied. + /// All state maintained by the Checksum object is independent per packet. + void clear(); + + /// Add data to checksum + void update(in T data); + + /// Get checksum for data added (and not removed) since last clear + W get(); +} +// END:Checksum_extern + +// BEGIN:InternetChecksum_extern +// Checksum based on `ONES_COMPLEMENT16` algorithm used in IPv4, TCP, and UDP. +// Supports incremental updating via `subtract` method. +// See IETF RFC 1624. +extern InternetChecksum { + /// Constructor + InternetChecksum(); + + /// Reset internal state and prepare unit for computation. Every + /// instance of an InternetChecksum object is automatically + /// initialized as if clear() had been called on it, once for each + /// time the parser or control it is instantiated within is + /// executed. All state maintained by it is independent per packet. + void clear(); + + /// Add data to checksum. data must be a multiple of 16 bits long. + void add(in T data); + + /// Subtract data from existing checksum. data must be a multiple of + /// 16 bits long. + void subtract(in T data); + + /// Get checksum for data added (and not removed) since last clear + bit<16> get(); + + /// Get current state of checksum computation. The return value is + /// only intended to be used for a future call to the set_state + /// method. + bit<16> get_state(); + + /// Restore the state of the InternetChecksum instance to one + /// returned from an earlier call to the get_state method. This + /// state could have been returned from the same instance of the + /// InternetChecksum extern, or a different one. + void set_state(in bit<16> checksum_state); +} +// END:InternetChecksum_extern diff --git a/p4include/_internal/pna/v0_5/extern_counter.p4 b/p4include/_internal/pna/v0_5/extern_counter.p4 new file mode 100644 index 0000000000..202f0052d3 --- /dev/null +++ b/p4include/_internal/pna/v0_5/extern_counter.p4 @@ -0,0 +1,24 @@ +// BEGIN:CounterType_defn +enum PNA_CounterType_t { + PACKETS, + BYTES, + PACKETS_AND_BYTES +} +// END:CounterType_defn + +// BEGIN:Counter_extern +/// Indirect counter with n_counters independent counter values, where +/// every counter value has a data plane size specified by type W. + +extern Counter { + Counter(bit<32> n_counters, PNA_CounterType_t type); + void count(in S index); +} +// END:Counter_extern + +// BEGIN:DirectCounter_extern +extern DirectCounter { + DirectCounter(PNA_CounterType_t type); + void count(); +} +// END:DirectCounter_extern diff --git a/p4include/_internal/pna/v0_5/extern_digest.p4 b/p4include/_internal/pna/v0_5/extern_digest.p4 new file mode 100644 index 0000000000..9f5d3541cb --- /dev/null +++ b/p4include/_internal/pna/v0_5/extern_digest.p4 @@ -0,0 +1,6 @@ +// BEGIN:Digest_extern +extern Digest { + Digest(); /// define a digest stream to the control plane + void pack(in T data); /// emit data into the stream +} +// END:Digest_extern diff --git a/p4include/_internal/pna/v0_5/extern_funcs.p4 b/p4include/_internal/pna/v0_5/extern_funcs.p4 new file mode 100644 index 0000000000..4647c2e359 --- /dev/null +++ b/p4include/_internal/pna/v0_5/extern_funcs.p4 @@ -0,0 +1,102 @@ +// The following extern functions are "forwarding" functions -- they +// all set the destination of the packet. Calling one of them +// overwrites and replaces the effect of any earlier call to any of +// the functions in this set. Only the last one executed will +// actually take effect for the packet. + +// + drop_packet +// + send_to_port + + +// drop_packet() - Cause the packet to be dropped when it finishes +// completing the main control. +// +// Invoking drop_packet() is supported only within the main control. + +extern void drop_packet(); + +extern void send_to_port(PortId_t dest_port); + +extern void mirror_packet(MirrorSlotId_t mirror_slot_id, + MirrorSessionId_t mirror_session_id); + +// TBD: Does it make sense to have a data plane add of a hit action +// that has in, out, or inout parameters? +// +// TBD: Should we require the return value? Can most targets +// implement it? If not, consider having two separate variants of +// add_entry, one with no return value (i.e. type void). Such a +// variant of add_entry seems difficult to use correctly, if it is +// possible for entries to fail to be added. + +// TBD: For add_entry calls to a table with property 'idle_timeout' or +// 'idle_timeout_with_auto_delete' equal to true, there should +// probably be an optional parameter at the end that specifies the new +// entry's initial expire_time_profile_id. + +extern bool add_entry(string action_name, + in T action_params); + +extern FlowId_t allocate_flow_id(); + + +// set_entry_expire_time() may only be called from within an action of +// a table with property 'idle_timeout' or +// 'idle_timeout_with_auto_delete' equal to true. + +// Calling it causes the expiration time of the entry to be the one +// that the control plane has configured for the specified +// expire_time_profile_id. + +extern void set_entry_expire_time( + in ExpireTimeProfileId_t expire_time_profile_id); + + +// restart_expire_timer() may only be called from within an action of +// a table with property 'idle_timeout' or +// 'idle_timeout_with_auto_delete' equal to true. + +// Calling it causes the dynamic expiration timer of the entry to be +// reset, so that the entry will remain active from the now until that +// time in the future. + +// TBD: Do any targets support a table with one of the idle_timeout +// properties such that matching an entry _does not_ cause this side +// effect to occur? If not, we could simply document it the way that +// I believe it currently behaves in all existing architectures, which +// is that every hit action implicitly causes the entry's expiration +// timer to be reset to its configured time interval in the future. + +extern void restart_expire_timer(); + + +// SelectByDirection is a simple pure function that behaves exactly as +// the P4_16 function definition given in comments below. It is an +// extern function to ensure that the front/mid end of the p4c +// compiler leaves occurrences of it as is, visible to target-specific +// compiler back end code, so targets have all information needed to +// optimize it as they wish. + +// One example of its use is in table key expressions, for tables +// where one wishes to swap IP source/destination addresses for +// packets processed in the different directions. + +/* +T SelectByDirection( + in PNA_Direction_t direction, + in T n2h_value, + in T h2n_value) +{ + if (direction == PNA_Direction_t.NET_TO_HOST) { + return n2h_value; + } else { + return h2n_value; + } +} +*/ + +@pure +extern T SelectByDirection( + in PNA_Direction_t direction, + in T n2h_value, + in T h2n_value); diff --git a/p4include/_internal/pna/v0_5/extern_hash.p4 b/p4include/_internal/pna/v0_5/extern_hash.p4 new file mode 100644 index 0000000000..e67987158d --- /dev/null +++ b/p4include/_internal/pna/v0_5/extern_hash.p4 @@ -0,0 +1,30 @@ +// BEGIN:Hash_algorithms +enum PNA_HashAlgorithm_t { + // TBD what this type's values will be for PNA + TARGET_DEFAULT /// target implementation defined +} +// END:Hash_algorithms + +// BEGIN:Hash_extern +extern Hash { + /// Constructor + Hash(PNA_HashAlgorithm_t algo); + + /// Compute the hash for data. + /// @param data The data over which to calculate the hash. + /// @return The hash value. + O get_hash(in D data); + + /// Compute the hash for data, with modulo by max, then add base. + /// @param base Minimum return value. + /// @param data The data over which to calculate the hash. + /// @param max The hash value is divided by max to get modulo. + /// An implementation may limit the largest value supported, + /// e.g. to a value like 32, or 256, and may also only + /// support powers of 2 for this value. P4 developers should + /// limit their choice to such values if they wish to + /// maximize portability. + /// @return (base + (h % max)) where h is the hash value. + O get_hash(in T base, in D data, in T max); +} +// END:Hash_extern diff --git a/p4include/_internal/pna/v0_5/extern_meter.p4 b/p4include/_internal/pna/v0_5/extern_meter.p4 new file mode 100644 index 0000000000..38107b7ad1 --- /dev/null +++ b/p4include/_internal/pna/v0_5/extern_meter.p4 @@ -0,0 +1,37 @@ +// BEGIN:MeterType_defn +enum PNA_MeterType_t { + PACKETS, + BYTES +} +// END:MeterType_defn + +// BEGIN:MeterColor_defn +enum PNA_MeterColor_t { RED, GREEN, YELLOW } +// END:MeterColor_defn + +// BEGIN:Meter_extern +// Indexed meter with n_meters independent meter states. + +extern Meter { + Meter(bit<32> n_meters, PNA_MeterType_t type); + + // Use this method call to perform a color aware meter update (see + // RFC 2698). The color of the packet before the method call was + // made is specified by the color parameter. + PNA_MeterColor_t execute(in S index, in PNA_MeterColor_t color); + + // Use this method call to perform a color blind meter update (see + // RFC 2698). It may be implemented via a call to execute(index, + // MeterColor_t.GREEN), which has the same behavior. + PNA_MeterColor_t execute(in S index); +} +// END:Meter_extern + +// BEGIN:DirectMeter_extern +extern DirectMeter { + DirectMeter(PNA_MeterType_t type); + // See the corresponding methods for extern Meter. + PNA_MeterColor_t execute(in PNA_MeterColor_t color); + PNA_MeterColor_t execute(); +} +// END:DirectMeter_extern diff --git a/p4include/_internal/pna/v0_5/extern_random.p4 b/p4include/_internal/pna/v0_5/extern_random.p4 new file mode 100644 index 0000000000..7d98b1b97b --- /dev/null +++ b/p4include/_internal/pna/v0_5/extern_random.p4 @@ -0,0 +1,12 @@ +// BEGIN:Random_extern +extern Random { + + /// Return a random value in the range [min, max], inclusive. + /// Implementations are allowed to support only ranges where (max - + /// min + 1) is a power of 2. P4 developers should limit their + /// arguments to such values if they wish to maximize portability. + + Random(T min, T max); + T read(); +} +// END:Random_extern diff --git a/p4include/_internal/pna/v0_5/extern_register.p4 b/p4include/_internal/pna/v0_5/extern_register.p4 new file mode 100644 index 0000000000..91fb6790fa --- /dev/null +++ b/p4include/_internal/pna/v0_5/extern_register.p4 @@ -0,0 +1,13 @@ +// BEGIN:Register_extern +extern Register { + /// Instantiate an array of registers. The initial value is + /// undefined. + Register(bit<32> size); + /// Initialize an array of registers and set their value to + /// initial_value. + Register(bit<32> size, T initial_value); + + T read (in S index); + void write (in S index, in T value); +} +// END:Register_extern diff --git a/p4include/_internal/pna/v0_5/funcs_int_to_header.p4 b/p4include/_internal/pna/v0_5/funcs_int_to_header.p4 new file mode 100644 index 0000000000..d13ef62136 --- /dev/null +++ b/p4include/_internal/pna/v0_5/funcs_int_to_header.p4 @@ -0,0 +1,87 @@ +/* The _int_to_header functions were written to convert a value of + * type _t (a value INTernal to the data path) to a value of + * type InHeader_t inside a header that will be sent to the CPU + * port. + * + * The _header_to_int functions were written to convert values in the + * opposite direction, typically for assigning a value in a header + * received from the CPU port, to a value you wish to use in the rest + * of your code. + * + * The reason that three casts are needed is that each of the original + * and target types is declared via P4_16 'type', so without a cast + * they can only be assigned to values of that identical type. The + * first cast changes it from the original 'type' to a 'bit' value + * of the same bit width W1. The second cast changes its bit width, + * either prepending 0s if it becomes wider, or discarding the most + * significant bits if it becomes narrower. The third cast changes it + * from a 'bit' value to the final 'type', with the same width + * W2. */ + +PortId_t pna_PortId_header_to_int (in PortIdInHeader_t x) { + return (PortId_t) (PortIdUint_t) (PortIdInHeaderUint_t) x; +} +InterfaceId_t pna_InterfaceId_header_to_int (in InterfaceIdInHeader_t x) { + return (InterfaceId_t) (InterfaceIdUint_t) (InterfaceIdInHeaderUint_t) x; +} +MulticastGroup_t pna_MulticastGroup_header_to_int (in MulticastGroupInHeader_t x) { + return (MulticastGroup_t) (MulticastGroupUint_t) (MulticastGroupInHeaderUint_t) x; +} +MirrorSessionId_t pna_MirrorSessionId_header_to_int (in MirrorSessionIdInHeader_t x) { + return (MirrorSessionId_t) (MirrorSessionIdUint_t) (MirrorSessionIdInHeaderUint_t) x; +} +ClassOfService_t pna_ClassOfService_header_to_int (in ClassOfServiceInHeader_t x) { + return (ClassOfService_t) (ClassOfServiceUint_t) (ClassOfServiceInHeaderUint_t) x; +} +PacketLength_t pna_PacketLength_header_to_int (in PacketLengthInHeader_t x) { + return (PacketLength_t) (PacketLengthUint_t) (PacketLengthInHeaderUint_t) x; +} +MulticastInstance_t pna_MulticastInstance_header_to_int (in MulticastInstanceInHeader_t x) { + return (MulticastInstance_t) (MulticastInstanceUint_t) (MulticastInstanceInHeaderUint_t) x; +} +Timestamp_t pna_Timestamp_header_to_int (in TimestampInHeader_t x) { + return (Timestamp_t) (TimestampUint_t) (TimestampInHeaderUint_t) x; +} +FlowId_t pna_FlowId_header_to_int (in FlowIdInHeader_t x) { + return (FlowId_t) (FlowIdUint_t) (FlowIdInHeaderUint_t) x; +} +ExpireTimeProfileId_t pna_ExpireTimeProfileId_header_to_int (in ExpireTimeProfileIdInHeader_t x) { + return (ExpireTimeProfileId_t) (ExpireTimeProfileIdUint_t) (ExpireTimeProfileIdInHeaderUint_t) x; +} +PassNumber_t pna_PassNumber_header_to_int (in PassNumberInHeader_t x) { + return (PassNumber_t) (PassNumberUint_t) (PassNumberInHeaderUint_t) x; +} + +PortIdInHeader_t pna_PortId_int_to_header (in PortId_t x) { + return (PortIdInHeader_t) (PortIdInHeaderUint_t) (PortIdUint_t) x; +} +InterfaceIdInHeader_t pna_InterfaceId_int_to_header (in InterfaceId_t x) { + return (InterfaceIdInHeader_t) (InterfaceIdInHeaderUint_t) (InterfaceIdUint_t) x; +} +MulticastGroupInHeader_t pna_MulticastGroup_int_to_header (in MulticastGroup_t x) { + return (MulticastGroupInHeader_t) (MulticastGroupInHeaderUint_t) (MulticastGroupUint_t) x; +} +MirrorSessionIdInHeader_t pna_MirrorSessionId_int_to_header (in MirrorSessionId_t x) { + return (MirrorSessionIdInHeader_t) (MirrorSessionIdInHeaderUint_t) (MirrorSessionIdUint_t) x; +} +ClassOfServiceInHeader_t pna_ClassOfService_int_to_header (in ClassOfService_t x) { + return (ClassOfServiceInHeader_t) (ClassOfServiceInHeaderUint_t) (ClassOfServiceUint_t) x; +} +PacketLengthInHeader_t pna_PacketLength_int_to_header (in PacketLength_t x) { + return (PacketLengthInHeader_t) (PacketLengthInHeaderUint_t) (PacketLengthUint_t) x; +} +MulticastInstanceInHeader_t pna_MulticastInstance_int_to_header (in MulticastInstance_t x) { + return (MulticastInstanceInHeader_t) (MulticastInstanceInHeaderUint_t) (MulticastInstanceUint_t) x; +} +TimestampInHeader_t pna_Timestamp_int_to_header (in Timestamp_t x) { + return (TimestampInHeader_t) (TimestampInHeaderUint_t) (TimestampUint_t) x; +} +FlowIdInHeader_t pna_FlowId_int_to_header (in FlowId_t x) { + return (FlowIdInHeader_t) (FlowIdInHeaderUint_t) (FlowIdUint_t) x; +} +ExpireTimeProfileIdInHeader_t pna_ExpireTimeProfileId_int_to_header (in ExpireTimeProfileId_t x) { + return (ExpireTimeProfileIdInHeader_t) (ExpireTimeProfileIdInHeaderUint_t) (ExpireTimeProfileIdUint_t) x; +} +PassNumberInHeader_t pna_PassNumber_int_to_header (in PassNumber_t x) { + return (PassNumberInHeader_t) (PassNumberInHeaderUint_t) (PassNumberUint_t) x; +} diff --git a/p4include/_internal/pna/v0_5/types_core.p4 b/p4include/_internal/pna/v0_5/types_core.p4 new file mode 100644 index 0000000000..f215086c4f --- /dev/null +++ b/p4include/_internal/pna/v0_5/types_core.p4 @@ -0,0 +1,77 @@ +/** + * These types need to be defined before including the architecture file + * and the macro protecting them should be defined. + */ +#define PNA_PLACEHOLDER_CORE_TYPES +#ifdef PNA_PLACEHOLDER_CORE_TYPES + +/* The bit widths shown below are placeholders that might not be + * implemented by any PNA device. + * + * Each PNA implementation is free to use its own custom width in bits + * for those types that are bit for some W. */ + +/* These are defined using `typedef`, not `type`, so they are truly + * just different names for the type bit for the particular width W + * shown. Unlike the `type` definitions below, values declared with + * the `typedef` type names can be freely mingled in expressions, just + * as any value declared with type bit can. Values declared with + * one of the `type` names below _cannot_ be so freely mingled, unless + * you first cast them to the corresponding `typedef` type. While + * that may be inconvenient when you need to do arithmetic on such + * values, it is the price to pay for having all occurrences of values + * of the `type` types marked as such in the automatically generated + * control plane API. + * + * Note that the width of typedef Uint_t will always be the same + * as the width of type _t. */ +typedef bit<32> PortIdUint_t; +typedef bit<32> InterfaceIdUint_t; +typedef bit<32> MulticastGroupUint_t; +typedef bit<16> MirrorSessionIdUint_t; +typedef bit<8> MirrorSlotIdUint_t; +typedef bit<8> ClassOfServiceUint_t; +typedef bit<16> PacketLengthUint_t; +typedef bit<16> MulticastInstanceUint_t; +typedef bit<64> TimestampUint_t; +typedef bit<32> FlowIdUint_t; +typedef bit<8> ExpireTimeProfileIdUint_t; +typedef bit<3> PassNumberUint_t; + +typedef bit<32> SecurityAssocIdUint_t; + +@p4runtime_translation("p4.org/pna/v1/PortId_t", 32) +type PortIdUint_t PortId_t; +@p4runtime_translation("p4.org/pna/v1/InterfaceId_t", 32) +type InterfaceIdUint_t InterfaceId_t; +@p4runtime_translation("p4.org/pna/v1/MulticastGroup_t", 32) +type MulticastGroupUint_t MulticastGroup_t; +@p4runtime_translation("p4.org/pna/v1/MirrorSessionId_t", 16) +type MirrorSessionIdUint_t MirrorSessionId_t; +@p4runtime_translation("p4.org/pna/v1/MirrorSlotId_t", 8) +type MirrorSlotIdUint_t MirrorSlotId_t; +@p4runtime_translation("p4.org/pna/v1/ClassOfService_t", 8) +type ClassOfServiceUint_t ClassOfService_t; +@p4runtime_translation("p4.org/pna/v1/PacketLength_t", 16) +type PacketLengthUint_t PacketLength_t; +@p4runtime_translation("p4.org/pna/v1/MulticastInstance_t", 16) +type MulticastInstanceUint_t MulticastInstance_t; +@p4runtime_translation("p4.org/pna/v1/Timestamp_t", 64) +type TimestampUint_t Timestamp_t; +@p4runtime_translation("p4.org/pna/v1/FlowId_t", 32) +type FlowIdUint_t FlowId_t; +@p4runtime_translation("p4.org/pna/v1/ExpireTimeProfileId_t", 8) +type ExpireTimeProfileIdUint_t ExpireTimeProfileId_t; +@p4runtime_translation("p4.org/pna/v1/PassNumber_t", 8) +type PassNumberUint_t PassNumber_t; + +@p4runtime_translation("p4.org/pna/v1/SecurityAssocId_t", 64) +type SecurityAssocIdUint_t SecurityAssocId_t; + +typedef error ParserError_t; + +const InterfaceId_t PNA_PORT_CPU = (InterfaceId_t) 0xfffffffd; + +const MirrorSessionId_t PNA_MIRROR_SESSION_TO_CPU = (MirrorSessionId_t) 0; + +#endif // PNA_PLACEHOLDER_CORE_TYPES diff --git a/p4include/_internal/pna/v0_5/types_defns.p4 b/p4include/_internal/pna/v0_5/types_defns.p4 new file mode 100644 index 0000000000..ebeb5c06e3 --- /dev/null +++ b/p4include/_internal/pna/v0_5/types_defns.p4 @@ -0,0 +1,67 @@ +#ifndef PNA_PLACEHOLDER_CORE_TYPES +#error "Please define the following types for PNA and undef the PNA_PLACEHOLDER_CORE_TYPES macro" +// BEGIN:Type_defns +/* These are defined using `typedef`, not `type`, so they are truly + * just different names for the type bit for the particular width W + * shown. Unlike the `type` definitions below, values declared with + * the `typedef` type names can be freely mingled in expressions, just + * as any value declared with type bit can. Values declared with + * one of the `type` names below _cannot_ be so freely mingled, unless + * you first cast them to the corresponding `typedef` type. While + * that may be inconvenient when you need to do arithmetic on such + * values, it is the price to pay for having all occurrences of values + * of the `type` types marked as such in the automatically generated + * control plane API. + * + * Note that the width of typedef Uint_t will always be the same + * as the width of type _t. */ +typedef bit PortIdUint_t; +typedef bit InterfaceIdUint_t; +typedef bit MulticastGroupUint_t; +typedef bit MirrorSessionIdUint_t; +typedef bit MirrorSlotIdUint_t; +typedef bit ClassOfServiceUint_t; +typedef bit PacketLengthUint_t; +typedef bit MulticastInstanceUint_t; +typedef bit TimestampUint_t; +typedef bit FlowIdUint_t; +typedef bit ExpireTimeProfileIdUint_t; +typedef bit PassNumberUint_t; + +typedef bit SecurityAssocIdUint_t; + +@p4runtime_translation("p4.org/pna/v1/PortId_t", 32) +type PortIdUint_t PortId_t; +@p4runtime_translation("p4.org/pna/v1/InterfaceId_t", 32) +type InterfaceIdUint_t InterfaceId_t; +@p4runtime_translation("p4.org/pna/v1/MulticastGroup_t", 32) +type MulticastGroupUint_t MulticastGroup_t; +@p4runtime_translation("p4.org/pna/v1/MirrorSessionId_t", 16) +type MirrorSessionIdUint_t MirrorSessionId_t; +@p4runtime_translation("p4.org/pna/v1/MirrorSlotId_t", 8) +type MirrorSlotIdUint_t MirrorSlotId_t; +@p4runtime_translation("p4.org/pna/v1/ClassOfService_t", 8) +type ClassOfServiceUint_t ClassOfService_t; +@p4runtime_translation("p4.org/pna/v1/PacketLength_t", 16) +type PacketLengthUint_t PacketLength_t; +@p4runtime_translation("p4.org/pna/v1/MulticastInstance_t", 16) +type MulticastInstanceUint_t MulticastInstance_t; +@p4runtime_translation("p4.org/pna/v1/Timestamp_t", 64) +type TimestampUint_t Timestamp_t; +@p4runtime_translation("p4.org/pna/v1/FlowId_t", 32) +type FlowIdUint_t FlowId_t; +@p4runtime_translation("p4.org/pna/v1/ExpireTimeProfileId_t", 8) +type ExpireTimeProfileIdUint_t ExpireTimeProfileId_t; +@p4runtime_translation("p4.org/pna/v1/PassNumber_t", 8) +type PassNumberUint_t PassNumber_t; + +@p4runtime_translation("p4.org/pna/v1/SecurityAssocId_t", 64) +type SecurityAssocIdUint_t SecurityAssocId_t; + +typedef error ParserError_t; + +const InterfaceId_t PNA_PORT_CPU = (PortId_t) unspecified; + +const MirrorSessionId_t PNA_MIRROR_SESSION_TO_CPU = (MirrorSessiontId_t) unspecified; +// END:Type_defns +#endif // #ifndef PNA_EXAMPLE_CORE_TYPES diff --git a/p4include/_internal/pna/v0_5/types_defns2.p4 b/p4include/_internal/pna/v0_5/types_defns2.p4 new file mode 100644 index 0000000000..1a6f227507 --- /dev/null +++ b/p4include/_internal/pna/v0_5/types_defns2.p4 @@ -0,0 +1,70 @@ +// BEGIN:Type_defns2 + +/* Note: All of the types with `InHeader` in their name are intended + * only to carry values of the corresponding types in packet headers + * between a PNA device and the P4Runtime Server software that manages + * it. + * + * The widths are intended to be at least as large as any PNA device + * will ever have for that type. Thus these types may also be useful + * to define packet headers that are sent directly between a PNA + * device and other devices, without going through P4Runtime Server + * software (e.g. this could be useful for sending packets to a + * controller or data collection system using higher packet rates than + * the P4Runtime Server can handle). If used for this purpose, there + * is no requirement that the PNA data plane _automatically_ perform + * the numerical translation of these types that would occur if the + * header went through the P4Runtime Server. Any such desired + * translation is up to the author of the P4 program to perform with + * explicit code. + * + * All widths must be a multiple of 8, so that any subset of these + * fields may be used in a single P4 header definition, even on P4 + * implementations that restrict headers to contain fields with a + * total length that is a multiple of 8 bits. */ + +/* See the comments near the definition of PortIdUint_t for why these + * typedef definitions exist. */ +typedef bit<32> PortIdInHeaderUint_t; +typedef bit<32> InterfaceIdInHeaderUint_t; +typedef bit<32> MulticastGroupInHeaderUint_t; +typedef bit<16> MirrorSessionIdInHeaderUint_t; +typedef bit<8> MirrorSlotIdInHeaderUint_t; +typedef bit<8> ClassOfServiceInHeaderUint_t; +typedef bit<16> PacketLengthInHeaderUint_t; +typedef bit<16> MulticastInstanceInHeaderUint_t; +typedef bit<64> TimestampInHeaderUint_t; +typedef bit<32> FlowIdInHeaderUint_t; +typedef bit<8> ExpireTimeProfileIdInHeaderUint_t; +typedef bit<8> PassNumberInHeaderUint_t; + +typedef bit<32> SecurityAssocIdInHeaderUint_t; + +@p4runtime_translation("p4.org/pna/v1/PortIdInHeader_t", 32) +type PortIdInHeaderUint_t PortIdInHeader_t; +@p4runtime_translation("p4.org/pna/v1/InterfaceIdInHeader_t", 32) +type InterfaceIdInHeaderUint_t InterfaceIdInHeader_t; +@p4runtime_translation("p4.org/pna/v1/MulticastGroupInHeader_t", 32) +type MulticastGroupInHeaderUint_t MulticastGroupInHeader_t; +@p4runtime_translation("p4.org/pna/v1/MirrorSessionIdInHeader_t", 16) +type MirrorSessionIdInHeaderUint_t MirrorSessionIdInHeader_t; +@p4runtime_translation("p4.org/pna/v1/MirrorSlotIdInHeader_t", 8) +type MirrorSlotIdInHeaderUint_t MirrorSlotIdInHeader_t; +@p4runtime_translation("p4.org/pna/v1/ClassOfServiceInHeader_t", 8) +type ClassOfServiceInHeaderUint_t ClassOfServiceInHeader_t; +@p4runtime_translation("p4.org/pna/v1/PacketLengthInHeader_t", 16) +type PacketLengthInHeaderUint_t PacketLengthInHeader_t; +@p4runtime_translation("p4.org/pna/v1/MulticastInstanceInHeader_t", 16) +type MulticastInstanceInHeaderUint_t MulticastInstanceInHeader_t; +@p4runtime_translation("p4.org/pna/v1/TimestampInHeader_t", 64) +type TimestampInHeaderUint_t TimestampInHeader_t; +@p4runtime_translation("p4.org/pna/v1/FlowIdInHeader_t", 32) +type FlowIdInHeaderUint_t FlowIdInHeader_t; +@p4runtime_translation("p4.org/pna/v1/ExpireTimeProfileIdInHeader_t", 8) +type ExpireTimeProfileIdInHeaderUint_t ExpireTimeProfileIdInHeader_t; +@p4runtime_translation("p4.org/pna/v1/PassNumberInHeader_t", 8) +type PassNumberInHeaderUint_t PassNumberInHeader_t; + +@p4runtime_translation("p4.org/pna/v1/SecurityAssocIdInHeader_t", 64) +type SecurityAssocIdInHeaderUint_t SecurityAssocIdInHeader_t; +// END:Type_defns2 diff --git a/p4include/_internal/pna/v0_5/types_metadata.p4 b/p4include/_internal/pna/v0_5/types_metadata.p4 new file mode 100644 index 0000000000..0f45f97cee --- /dev/null +++ b/p4include/_internal/pna/v0_5/types_metadata.p4 @@ -0,0 +1,83 @@ +enum PNA_Direction_t { + NET_TO_HOST, + HOST_TO_NET +} + +// BEGIN:Metadata_types +enum PNA_PacketPath_t { + // TBD if this type remains, whether it should be an enum or + // several separate fields representing the same cases in a + // different form. + FROM_NET_PORT, + FROM_NET_LOOPEDBACK, + FROM_NET_RECIRCULATED, + FROM_HOST, + FROM_HOST_LOOPEDBACK, + FROM_HOST_RECIRCULATED +} + +struct pna_pre_input_metadata_t { + PortId_t input_port; + ParserError_t parser_error; + PNA_Direction_t direction; + PassNumber_t pass; + bool loopedback; +} + +struct pna_pre_output_metadata_t { + bool decrypt; // TBD: or use said==0 to mean no decrypt? + + // The following things are stored internally within the decrypt + // block, in a table indexed by said: + + // + The decryption algorithm, e.g. AES256, etc. + // + The decryption key + // + Any read-modify-write state in the data plane used to + // implement anti-replay attack detection. + + SecurityAssocId_t said; + bit<16> decrypt_start_offset; // in bytes? + + // TBD whether it is important to explicitly pass information to a + // decryption extern in a way visible to a P4 program about where + // headers were parsed and found. An alternative is to assume + // that the architecture saves the pre parser results somewhere, + // in a way not visible to the P4 program. +} + +struct pna_main_parser_input_metadata_t { + // common fields initialized for all packets that are input to main + // parser, regardless of direction. + PNA_Direction_t direction; + PassNumber_t pass; + bool loopedback; + // If this packet has direction NET_TO_HOST, input_port contains + // the id of the network port on which the packet arrived. + // If this packet has direction HOST_TO_NET, input_port contains + // the id of the vport from which the packet came + PortId_t input_port; // network port id +} + +struct pna_main_input_metadata_t { + // common fields initialized for all packets that are input to main + // parser, regardless of direction. + PNA_Direction_t direction; + PassNumber_t pass; + bool loopedback; + Timestamp_t timestamp; + ParserError_t parser_error; + ClassOfService_t class_of_service; + // See comments for field input_port in struct + // pna_main_parser_input_metadata_t + PortId_t input_port; +} + +// BEGIN:Metadata_main_output +struct pna_main_output_metadata_t { + // common fields used by the architecture to decide what to do with + // the packet next, after the main parser, control, and deparser + // have finished executing one pass, regardless of the direction. + ClassOfService_t class_of_service; // 0 +} +// END:Metadata_main_output +// END:Metadata_types diff --git a/p4include/_internal/pna/v0_5/types_misc.p4 b/p4include/_internal/pna/v0_5/types_misc.p4 new file mode 100644 index 0000000000..2fd5e0c253 --- /dev/null +++ b/p4include/_internal/pna/v0_5/types_misc.p4 @@ -0,0 +1,12 @@ +/// Supported range of values for the pna_idle_timeout table properties +enum PNA_IdleTimeout_t { + NO_TIMEOUT, + NOTIFY_CONTROL +}; + +// BEGIN:Match_kinds +match_kind { + range, /// Used to represent min..max intervals + selector /// Used for dynamic action selection via the ActionSelector extern +} +// END:Match_kinds diff --git a/p4include/_internal/pna/v0_7/all.p4 b/p4include/_internal/pna/v0_7/all.p4 new file mode 100644 index 0000000000..e06a396a35 --- /dev/null +++ b/p4include/_internal/pna/v0_7/all.p4 @@ -0,0 +1,44 @@ +/* Copyright 2020-present Intel Corporation + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef __PNA_P4__ +#define __PNA_P4__ + +#include + +/** + * P4-16 declaration of the Portable NIC Architecture + */ + +#include <_internal/pna/v0_7/types_core.p4> +#include <_internal/pna/v0_7/types_defns.p4> +#include <_internal/pna/v0_7/types_defns2.p4> +#include <_internal/pna/v0_7/funcs_int_to_header.p4> +#include <_internal/pna/v0_7/types_misc.p4> + +#include <_internal/pna/v0_7/extern_hash.p4> +#include <_internal/pna/v0_7/extern_checksum.p4> +#include <_internal/pna/v0_7/extern_counter.p4> +#include <_internal/pna/v0_7/extern_meter.p4> +#include <_internal/pna/v0_7/extern_register.p4> +#include <_internal/pna/v0_7/extern_random.p4> +#include <_internal/pna/v0_7/extern_action.p4> +#include <_internal/pna/v0_7/extern_digest.p4> + +#include <_internal/pna/v0_7/types_metadata.p4> +#include <_internal/pna/v0_7/extern_funcs.p4> +#include <_internal/pna/v0_7/blocks.p4> + +#endif // __PNA_P4__ diff --git a/p4include/_internal/pna/v0_7/blocks.p4 b/p4include/_internal/pna/v0_7/blocks.p4 new file mode 100644 index 0000000000..66aebe8de4 --- /dev/null +++ b/p4include/_internal/pna/v0_7/blocks.p4 @@ -0,0 +1,24 @@ +// BEGIN:Programmable_blocks +parser MainParserT( + packet_in pkt, + out MH main_hdr, + inout MM main_user_meta, + in pna_main_parser_input_metadata_t istd); + +control MainControlT( + inout MH main_hdr, + inout MM main_user_meta, + in pna_main_input_metadata_t istd, + inout pna_main_output_metadata_t ostd); + +control MainDeparserT( + packet_out pkt, + in MH main_hdr, + in MM main_user_meta, + in pna_main_output_metadata_t ostd); + +package PNA_NIC( + MainParserT main_parser, + MainControlT main_control, + MainDeparserT main_deparser); +// END:Programmable_blocks diff --git a/p4include/_internal/pna/v0_7/extern_action.p4 b/p4include/_internal/pna/v0_7/extern_action.p4 new file mode 100644 index 0000000000..b7e6f918b6 --- /dev/null +++ b/p4include/_internal/pna/v0_7/extern_action.p4 @@ -0,0 +1 @@ +#include <_internal/pna/v0_5/extern_action.p4> diff --git a/p4include/_internal/pna/v0_7/extern_checksum.p4 b/p4include/_internal/pna/v0_7/extern_checksum.p4 new file mode 100644 index 0000000000..5d89b999be --- /dev/null +++ b/p4include/_internal/pna/v0_7/extern_checksum.p4 @@ -0,0 +1 @@ +#include <_internal/pna/v0_5/extern_checksum.p4> diff --git a/p4include/_internal/pna/v0_7/extern_counter.p4 b/p4include/_internal/pna/v0_7/extern_counter.p4 new file mode 100644 index 0000000000..3710148d7f --- /dev/null +++ b/p4include/_internal/pna/v0_7/extern_counter.p4 @@ -0,0 +1,26 @@ +// BEGIN:CounterType_defn +enum PNA_CounterType_t { + PACKETS, + BYTES, + PACKETS_AND_BYTES +} +// END:CounterType_defn + +// BEGIN:Counter_extern +/// Indirect counter with n_counters independent counter values, where +/// every counter value has a data plane size specified by type W. + +@noWarn("unused") +extern Counter { + Counter(bit<32> n_counters, PNA_CounterType_t type); + void count(in S index); +} +// END:Counter_extern + +// BEGIN:DirectCounter_extern +@noWarn("unused") +extern DirectCounter { + DirectCounter(PNA_CounterType_t type); + void count(); +} +// END:DirectCounter_extern diff --git a/p4include/_internal/pna/v0_7/extern_digest.p4 b/p4include/_internal/pna/v0_7/extern_digest.p4 new file mode 100644 index 0000000000..a59b576197 --- /dev/null +++ b/p4include/_internal/pna/v0_7/extern_digest.p4 @@ -0,0 +1 @@ +#include <_internal/pna/v0_5/extern_digest.p4> diff --git a/p4include/_internal/pna/v0_7/extern_funcs.p4 b/p4include/_internal/pna/v0_7/extern_funcs.p4 new file mode 100644 index 0000000000..e6f4377009 --- /dev/null +++ b/p4include/_internal/pna/v0_7/extern_funcs.p4 @@ -0,0 +1,252 @@ +// The following extern functions are "forwarding" functions -- they +// all set the destination of the packet. Calling one of them +// overwrites and replaces the effect of any earlier call to any of +// the functions in this set. Only the last one executed will +// actually take effect for the packet. + +// + drop_packet +// + send_to_port + + +// drop_packet() - Cause the packet to be dropped when it finishes +// completing the main control. +// +// Invoking drop_packet() is supported only within the main control. + +extern void drop_packet(); + +extern void send_to_port(PortId_t dest_port); + +extern void mirror_packet(MirrorSlotId_t mirror_slot_id, + MirrorSessionId_t mirror_session_id); + +// TBD: Does it make sense to have a data plane add of a hit action +// that has in, out, or inout parameters? +// +// TBD: Should we require the return value? Can most targets +// implement it? If not, consider having two separate variants of +// add_entry, one with no return value (i.e. type void). Such a +// variant of add_entry seems difficult to use correctly, if it is +// possible for entries to fail to be added. + +// BEGIN:add_entry_extern_function +// The bit width of this type is allowed to be different for different +// target devices. It must be at least a 1-bit wide type. + +typedef bit<1> AddEntryErrorStatus_t; + +const AddEntryErrorStatus_t ADD_ENTRY_SUCCESS = 0; +const AddEntryErrorStatus_t ADD_ENTRY_NOT_DONE = 1; + +// Targets may define target-specific non-0 constants of type +// AddEntryErrorStatus_t if they wish. + +// The add_entry() extern function causes an entry, i.e. a key and its +// corresponding action and action parameter values, to be added to a +// table from the data plane, i.e. without the control plane having to +// take any action at all to cause the table entry to be added. +// +// The key of the new entry added will always be the same as the key +// that was just looked up in the table, and experienced a miss. +// +// `action_name` is the name of an action that must satisfy these +// restrictions: +// + It must be an action that is in the list specified as the +// `actions` property of the table. +// + It must be possible for this action to be the action of an entry +// added to the table, e.g. it is an error if the action has the +// annotation `@defaultonly`. +// + The action to be added must not itself contain a call to +// add_entry(), or anything else that is not supported in a table's +// "hit action". +// +// Type T must be a struct type whose field names have the same name +// as the parameters of the action being added, in the same order, and +// have the same type as the corresponding action parameters. +// +// `action_params` will become the action parameters of the new entry +// to be added. +// +// `expire_time_profile_id` is the initial expire time profile id of +// the entry added. +// +// The return value will be ADD_ENTRY_SUCCESS if the entry was +// successfully added, otherwise it will be some other value not equal +// to ADD_ENTRY_SUCCESS. Targets are allowed to define only one +// failure return value, or several if they wish to provide more +// detail on the reason for the failure to add the entry. +// +// It is NOT defined by PNA, and need not be supported by PNA +// implementations, to call add_entry() within an action that is added +// as an entry of a table, i.e. as a "hit action". It is only defined +// if called within an action that is the default_action, i.e. a "miss +// action" of a table. +// +// For tables with `add_on_miss = true`, some PNA implementations +// might only support `default_action` with the `const` qualifier. +// However, if a PNA implementation can support run-time modifiable +// default actions for such a table, some of which call add_entry() +// and some of which do not, the behavior of such an implementation is +// defined by PNA, and this may be a useful feature. + +extern AddEntryErrorStatus_t add_entry( + string action_name, + in T action_params, + in ExpireTimeProfileId_t expire_time_profile_id); +// END:add_entry_extern_function + +// The following call to add_entry_if(): +// +// add_entry_if(expr, action_name, action_params, expire_time_profile_id); +// +// has exactly the same behavior as the following expression: +// +// (expr) ? add_entry(action_name, action_params, expire_time_profile_id) +// : ADD_ENTRY_NOT_DONE; +// +// and it has the same restrictions on where it can appear in a P4 +// program as that equivalent code. +// +// Rationale: At the time PNA was being designed in 2022, there were +// P4 targets, including the BMv2 software switch in the repository +// https://github.com/p4lang/behavioral-model, that did not fully +// support `if` statements within P4 actions. add_entry_if() enables +// writing P4 code without `if` statements within P4 actions that +// would otherwise require an `if` statement to express the desired +// behavior. Admittedly, this is a work-around for targets with +// limited support for `if` statements within P4 actions. See +// https://github.com/p4lang/pna/issues/63 for more details. + +extern AddEntryErrorStatus_t add_entry_if( + in bool do_add_entry, + string action_name, + in T action_params, + in ExpireTimeProfileId_t expire_time_profile_id); + +extern FlowId_t allocate_flow_id(); + + +// set_entry_expire_time() may only be called from within an action of +// a table with property 'pna_idle_timeout' having a value of +// `NOTIFY_CONTROL` or `AUTO_DELETE`. + +// Calling it causes the expiration time profile id of the matched +// entry to become equal to expire_time_profile_id. + +// It _also_ behaves as if restart_expire_timer() was called. + +extern void set_entry_expire_time( + in ExpireTimeProfileId_t expire_time_profile_id); + + +// restart_expire_timer() may only be called from within an action of +// a table with property 'pna_idle_timeout' having a value of +// `NOTIFY_CONTROL` or `AUTO_DELETE`. + +// Calling it causes the dynamic expiration timer of the entry to be +// reset, so that the entry will remain active from the now until that +// time in the future. + +// TODO: Note that there are targets that support a table with +// property pna_idle_timeout equal to `NOTIFY_CONTROL` or +// `AUTO_DELETE` such that matching an entry _does not_ cause this +// side effect to occur, i.e. it is possible to match an entry and +// _not_ do what `restart_expire_timer()` does. We should document +// this explicitly as common for PNA devices, if that is agreed upon. +// Andy is pretty sure that PSA devices were not expected to have this +// option. + +// Note that for the PSA architecture with psa_idle_timeout = +// PSA_IdleTimeout_t.NOTIFY_CONTROL, I believe there was an implicit +// assumption that _every_ time a table entry was matched, the target +// behaved as if restart_expire_timer() was called, but there was no +// such extern function defined by PSA. + +// The proposal for PNA is that it is possible to match an entry, but +// _not_ call restart_expire_timer(), and this will cause the data +// plane _not_ to restart the table entry's expiration time. That is, +// the expiration time of the entry will continue to be the same as +// before it was matched. + +extern void restart_expire_timer(); + +// The effect of this call: +// +// update_expire_info(a, b, c) +// +// is exactly the same as the effect of the following code: +// +// if (a) { +// if (b) { +// set_entry_expire_time(c); +// } else { +// restart_expire_timer(); +// } +// } + +extern void update_expire_info( + in bool update_aging_info, + in bool update_expire_time, + in ExpireTimeProfileId_t expire_time_profile_id); + + +// Set the expire time of the matched entry in the table to the value +// specified in the parameter expire_time_profile_id, if condition +// in the first parameter evaluates to true. Otherwise, the function +// has no effect. +// +// @param condition The boolean expression to evaluate to determine +// if the expire time will be set. +// @param expire_time_profile_id +// The expire time to set for the matched entry, +// if the data and value parameters are equal. +// +// Examples: +// set_expire_time_if(hdr.tcp.flags == TCP_FLG_SYN && +// meta.direction == OUTBOUND, +// tcp_connection_start_time_profile_id); +// set_expire_time_if(hdr.tcp.flags == TCP_FLG_ACK, +// tcp_connection_continuation_time_protile_id); +// set_expire_time_if(hdr.tcp.flags == TCP_FLG_FIN, +// tcp_connection_close_time_profile_id); + +extern void set_entry_expire_time_if( + in bool condition, + in ExpireTimeProfileId_t expire_time_profile_id); + + +// SelectByDirection is a simple pure function that behaves exactly as +// the P4_16 function definition given in comments below. It is an +// extern function to ensure that the front/mid end of the p4c +// compiler leaves occurrences of it as is, visible to target-specific +// compiler back end code, so targets have all information needed to +// optimize it as they wish. + +// One example of its use is in table key expressions, for tables +// where one wishes to swap IP source/destination addresses for +// packets processed in the different directions. + +/* +T SelectByDirection( + in bool is_network_port, + in T from_net_value, + in T from_host_value) +{ + if (is_network_port) { + return from_net_value; + } else { + return from_host_value; + } +} +*/ + +// A typical call would look like this example: +// +// SelectByDirection(is_net_port(istd.input_port), hdr.ipv4.src_addr, +// hdr.ipv4.dst_addr) + +@pure +extern T SelectByDirection( + in bool is_network_port, + in T from_net_value, + in T from_host_value); diff --git a/p4include/_internal/pna/v0_7/extern_hash.p4 b/p4include/_internal/pna/v0_7/extern_hash.p4 new file mode 100644 index 0000000000..8bdc422752 --- /dev/null +++ b/p4include/_internal/pna/v0_7/extern_hash.p4 @@ -0,0 +1,36 @@ +// BEGIN:Hash_algorithms +enum PNA_HashAlgorithm_t { + IDENTITY, + CRC32, + CRC32_CUSTOM, + CRC16, + CRC16_CUSTOM, + ONES_COMPLEMENT16, /// One's complement 16-bit sum used for IPv4 headers, + /// TCP, and UDP. + TARGET_DEFAULT /// target implementation defined +} +// END:Hash_algorithms + +// BEGIN:Hash_extern +extern Hash { + /// Constructor + Hash(PNA_HashAlgorithm_t algo); + + /// Compute the hash for data. + /// @param data The data over which to calculate the hash. + /// @return The hash value. + O get_hash(in D data); + + /// Compute the hash for data, with modulo by max, then add base. + /// @param base Minimum return value. + /// @param data The data over which to calculate the hash. + /// @param max The hash value is divided by max to get modulo. + /// An implementation may limit the largest value supported, + /// e.g. to a value like 32, or 256, and may also only + /// support powers of 2 for this value. P4 developers should + /// limit their choice to such values if they wish to + /// maximize portability. + /// @return (base + (h % max)) where h is the hash value. + O get_hash(in T base, in D data, in T max); +} +// END:Hash_extern diff --git a/p4include/_internal/pna/v0_7/extern_meter.p4 b/p4include/_internal/pna/v0_7/extern_meter.p4 new file mode 100644 index 0000000000..cd1da583e0 --- /dev/null +++ b/p4include/_internal/pna/v0_7/extern_meter.p4 @@ -0,0 +1 @@ +#include <_internal/pna/v0_5/extern_meter.p4> diff --git a/p4include/_internal/pna/v0_7/extern_random.p4 b/p4include/_internal/pna/v0_7/extern_random.p4 new file mode 100644 index 0000000000..26abc15537 --- /dev/null +++ b/p4include/_internal/pna/v0_7/extern_random.p4 @@ -0,0 +1 @@ +#include <_internal/pna/v0_5/extern_random.p4> diff --git a/p4include/_internal/pna/v0_7/extern_register.p4 b/p4include/_internal/pna/v0_7/extern_register.p4 new file mode 100644 index 0000000000..2609c8c814 --- /dev/null +++ b/p4include/_internal/pna/v0_7/extern_register.p4 @@ -0,0 +1 @@ +#include <_internal/pna/v0_5/extern_register.p4> diff --git a/p4include/_internal/pna/v0_7/funcs_int_to_header.p4 b/p4include/_internal/pna/v0_7/funcs_int_to_header.p4 new file mode 100644 index 0000000000..d3f3ac651b --- /dev/null +++ b/p4include/_internal/pna/v0_7/funcs_int_to_header.p4 @@ -0,0 +1,81 @@ +/* The _int_to_header functions were written to convert a value of + * type _t (a value INTernal to the data path) to a value of + * type InHeader_t inside a header that will be sent to the CPU + * port. + * + * The _header_to_int functions were written to convert values in the + * opposite direction, typically for assigning a value in a header + * received from the CPU port, to a value you wish to use in the rest + * of your code. + * + * The reason that three casts are needed is that each of the original + * and target types is declared via P4_16 'type', so without a cast + * they can only be assigned to values of that identical type. The + * first cast changes it from the original 'type' to a 'bit' value + * of the same bit width W1. The second cast changes its bit width, + * either prepending 0s if it becomes wider, or discarding the most + * significant bits if it becomes narrower. The third cast changes it + * from a 'bit' value to the final 'type', with the same width + * W2. */ + +PortId_t pna_PortId_header_to_int (in PortIdInHeader_t x) { + return (PortId_t) (PortIdUint_t) (PortIdInHeaderUint_t) x; +} +InterfaceId_t pna_InterfaceId_header_to_int (in InterfaceIdInHeader_t x) { + return (InterfaceId_t) (InterfaceIdUint_t) (InterfaceIdInHeaderUint_t) x; +} +MulticastGroup_t pna_MulticastGroup_header_to_int (in MulticastGroupInHeader_t x) { + return (MulticastGroup_t) (MulticastGroupUint_t) (MulticastGroupInHeaderUint_t) x; +} +MirrorSessionId_t pna_MirrorSessionId_header_to_int (in MirrorSessionIdInHeader_t x) { + return (MirrorSessionId_t) (MirrorSessionIdUint_t) (MirrorSessionIdInHeaderUint_t) x; +} +ClassOfService_t pna_ClassOfService_header_to_int (in ClassOfServiceInHeader_t x) { + return (ClassOfService_t) (ClassOfServiceUint_t) (ClassOfServiceInHeaderUint_t) x; +} +PacketLength_t pna_PacketLength_header_to_int (in PacketLengthInHeader_t x) { + return (PacketLength_t) (PacketLengthUint_t) (PacketLengthInHeaderUint_t) x; +} +MulticastInstance_t pna_MulticastInstance_header_to_int (in MulticastInstanceInHeader_t x) { + return (MulticastInstance_t) (MulticastInstanceUint_t) (MulticastInstanceInHeaderUint_t) x; +} +Timestamp_t pna_Timestamp_header_to_int (in TimestampInHeader_t x) { + return (Timestamp_t) (TimestampUint_t) (TimestampInHeaderUint_t) x; +} +FlowId_t pna_FlowId_header_to_int (in FlowIdInHeader_t x) { + return (FlowId_t) (FlowIdUint_t) (FlowIdInHeaderUint_t) x; +} +ExpireTimeProfileId_t pna_ExpireTimeProfileId_header_to_int (in ExpireTimeProfileIdInHeader_t x) { + return (ExpireTimeProfileId_t) (ExpireTimeProfileIdUint_t) (ExpireTimeProfileIdInHeaderUint_t) x; +} + +PortIdInHeader_t pna_PortId_int_to_header (in PortId_t x) { + return (PortIdInHeader_t) (PortIdInHeaderUint_t) (PortIdUint_t) x; +} +InterfaceIdInHeader_t pna_InterfaceId_int_to_header (in InterfaceId_t x) { + return (InterfaceIdInHeader_t) (InterfaceIdInHeaderUint_t) (InterfaceIdUint_t) x; +} +MulticastGroupInHeader_t pna_MulticastGroup_int_to_header (in MulticastGroup_t x) { + return (MulticastGroupInHeader_t) (MulticastGroupInHeaderUint_t) (MulticastGroupUint_t) x; +} +MirrorSessionIdInHeader_t pna_MirrorSessionId_int_to_header (in MirrorSessionId_t x) { + return (MirrorSessionIdInHeader_t) (MirrorSessionIdInHeaderUint_t) (MirrorSessionIdUint_t) x; +} +ClassOfServiceInHeader_t pna_ClassOfService_int_to_header (in ClassOfService_t x) { + return (ClassOfServiceInHeader_t) (ClassOfServiceInHeaderUint_t) (ClassOfServiceUint_t) x; +} +PacketLengthInHeader_t pna_PacketLength_int_to_header (in PacketLength_t x) { + return (PacketLengthInHeader_t) (PacketLengthInHeaderUint_t) (PacketLengthUint_t) x; +} +MulticastInstanceInHeader_t pna_MulticastInstance_int_to_header (in MulticastInstance_t x) { + return (MulticastInstanceInHeader_t) (MulticastInstanceInHeaderUint_t) (MulticastInstanceUint_t) x; +} +TimestampInHeader_t pna_Timestamp_int_to_header (in Timestamp_t x) { + return (TimestampInHeader_t) (TimestampInHeaderUint_t) (TimestampUint_t) x; +} +FlowIdInHeader_t pna_FlowId_int_to_header (in FlowId_t x) { + return (FlowIdInHeader_t) (FlowIdInHeaderUint_t) (FlowIdUint_t) x; +} +ExpireTimeProfileIdInHeader_t pna_ExpireTimeProfileId_int_to_header (in ExpireTimeProfileId_t x) { + return (ExpireTimeProfileIdInHeader_t) (ExpireTimeProfileIdInHeaderUint_t) (ExpireTimeProfileIdUint_t) x; +} diff --git a/p4include/_internal/pna/v0_7/types_core.p4 b/p4include/_internal/pna/v0_7/types_core.p4 new file mode 100644 index 0000000000..5c38a078b5 --- /dev/null +++ b/p4include/_internal/pna/v0_7/types_core.p4 @@ -0,0 +1,74 @@ +/** + * These types need to be defined before including the architecture file + * and the macro protecting them should be defined. + */ +#define PNA_PLACEHOLDER_CORE_TYPES +#ifdef PNA_PLACEHOLDER_CORE_TYPES + +/* The bit widths shown below are placeholders that might not be + * implemented by any PNA device. + * + * Each PNA implementation is free to use its own custom width in bits + * for those types that are bit for some W. */ + +/* These are defined using `typedef`, not `type`, so they are truly + * just different names for the type bit for the particular width W + * shown. Unlike the `type` definitions below, values declared with + * the `typedef` type names can be freely mingled in expressions, just + * as any value declared with type bit can. Values declared with + * one of the `type` names below _cannot_ be so freely mingled, unless + * you first cast them to the corresponding `typedef` type. While + * that may be inconvenient when you need to do arithmetic on such + * values, it is the price to pay for having all occurrences of values + * of the `type` types marked as such in the automatically generated + * control plane API. + * + * Note that the width of typedef Uint_t will always be the same + * as the width of type _t. */ +typedef bit<32> PortIdUint_t; +typedef bit<32> InterfaceIdUint_t; +typedef bit<32> MulticastGroupUint_t; +typedef bit<16> MirrorSessionIdUint_t; +typedef bit<8> MirrorSlotIdUint_t; +typedef bit<8> ClassOfServiceUint_t; +typedef bit<16> PacketLengthUint_t; +typedef bit<16> MulticastInstanceUint_t; +typedef bit<64> TimestampUint_t; +typedef bit<32> FlowIdUint_t; +typedef bit<8> ExpireTimeProfileIdUint_t; + +typedef bit<32> SecurityAssocIdUint_t; + +@p4runtime_translation("p4.org/pna/v1/PortId_t", 32) +type PortIdUint_t PortId_t; +@p4runtime_translation("p4.org/pna/v1/InterfaceId_t", 32) +type InterfaceIdUint_t InterfaceId_t; +@p4runtime_translation("p4.org/pna/v1/MulticastGroup_t", 32) +type MulticastGroupUint_t MulticastGroup_t; +@p4runtime_translation("p4.org/pna/v1/MirrorSessionId_t", 16) +type MirrorSessionIdUint_t MirrorSessionId_t; +@p4runtime_translation("p4.org/pna/v1/MirrorSlotId_t", 8) +type MirrorSlotIdUint_t MirrorSlotId_t; +@p4runtime_translation("p4.org/pna/v1/ClassOfService_t", 8) +type ClassOfServiceUint_t ClassOfService_t; +@p4runtime_translation("p4.org/pna/v1/PacketLength_t", 16) +type PacketLengthUint_t PacketLength_t; +@p4runtime_translation("p4.org/pna/v1/MulticastInstance_t", 16) +type MulticastInstanceUint_t MulticastInstance_t; +@p4runtime_translation("p4.org/pna/v1/Timestamp_t", 64) +type TimestampUint_t Timestamp_t; +@p4runtime_translation("p4.org/pna/v1/FlowId_t", 32) +type FlowIdUint_t FlowId_t; +@p4runtime_translation("p4.org/pna/v1/ExpireTimeProfileId_t", 8) +type ExpireTimeProfileIdUint_t ExpireTimeProfileId_t; + +@p4runtime_translation("p4.org/pna/v1/SecurityAssocId_t", 64) +type SecurityAssocIdUint_t SecurityAssocId_t; + +typedef error ParserError_t; + +const InterfaceId_t PNA_PORT_CPU = (InterfaceId_t) 0xfffffffd; + +const MirrorSessionId_t PNA_MIRROR_SESSION_TO_CPU = (MirrorSessionId_t) 0; + +#endif // PNA_PLACEHOLDER_CORE_TYPES diff --git a/p4include/_internal/pna/v0_7/types_defns.p4 b/p4include/_internal/pna/v0_7/types_defns.p4 new file mode 100644 index 0000000000..e35a5a58b5 --- /dev/null +++ b/p4include/_internal/pna/v0_7/types_defns.p4 @@ -0,0 +1,64 @@ +#ifndef PNA_PLACEHOLDER_CORE_TYPES +#error "Please define the following types for PNA and undef the PNA_PLACEHOLDER_CORE_TYPES macro" +// BEGIN:Type_defns +/* These are defined using `typedef`, not `type`, so they are truly + * just different names for the type bit for the particular width W + * shown. Unlike the `type` definitions below, values declared with + * the `typedef` type names can be freely mingled in expressions, just + * as any value declared with type bit can. Values declared with + * one of the `type` names below _cannot_ be so freely mingled, unless + * you first cast them to the corresponding `typedef` type. While + * that may be inconvenient when you need to do arithmetic on such + * values, it is the price to pay for having all occurrences of values + * of the `type` types marked as such in the automatically generated + * control plane API. + * + * Note that the width of typedef Uint_t will always be the same + * as the width of type _t. */ +typedef bit PortIdUint_t; +typedef bit InterfaceIdUint_t; +typedef bit MulticastGroupUint_t; +typedef bit MirrorSessionIdUint_t; +typedef bit MirrorSlotIdUint_t; +typedef bit ClassOfServiceUint_t; +typedef bit PacketLengthUint_t; +typedef bit MulticastInstanceUint_t; +typedef bit TimestampUint_t; +typedef bit FlowIdUint_t; +typedef bit ExpireTimeProfileIdUint_t; + +typedef bit SecurityAssocIdUint_t; + +@p4runtime_translation("p4.org/pna/v1/PortId_t", 32) +type PortIdUint_t PortId_t; +@p4runtime_translation("p4.org/pna/v1/InterfaceId_t", 32) +type InterfaceIdUint_t InterfaceId_t; +@p4runtime_translation("p4.org/pna/v1/MulticastGroup_t", 32) +type MulticastGroupUint_t MulticastGroup_t; +@p4runtime_translation("p4.org/pna/v1/MirrorSessionId_t", 16) +type MirrorSessionIdUint_t MirrorSessionId_t; +@p4runtime_translation("p4.org/pna/v1/MirrorSlotId_t", 8) +type MirrorSlotIdUint_t MirrorSlotId_t; +@p4runtime_translation("p4.org/pna/v1/ClassOfService_t", 8) +type ClassOfServiceUint_t ClassOfService_t; +@p4runtime_translation("p4.org/pna/v1/PacketLength_t", 16) +type PacketLengthUint_t PacketLength_t; +@p4runtime_translation("p4.org/pna/v1/MulticastInstance_t", 16) +type MulticastInstanceUint_t MulticastInstance_t; +@p4runtime_translation("p4.org/pna/v1/Timestamp_t", 64) +type TimestampUint_t Timestamp_t; +@p4runtime_translation("p4.org/pna/v1/FlowId_t", 32) +type FlowIdUint_t FlowId_t; +@p4runtime_translation("p4.org/pna/v1/ExpireTimeProfileId_t", 8) +type ExpireTimeProfileIdUint_t ExpireTimeProfileId_t; + +@p4runtime_translation("p4.org/pna/v1/SecurityAssocId_t", 64) +type SecurityAssocIdUint_t SecurityAssocId_t; + +typedef error ParserError_t; + +const InterfaceId_t PNA_PORT_CPU = (PortId_t) unspecified; + +const MirrorSessionId_t PNA_MIRROR_SESSION_TO_CPU = (MirrorSessiontId_t) unspecified; +// END:Type_defns +#endif // #ifndef PNA_EXAMPLE_CORE_TYPES diff --git a/p4include/_internal/pna/v0_7/types_defns2.p4 b/p4include/_internal/pna/v0_7/types_defns2.p4 new file mode 100644 index 0000000000..ed2e39059b --- /dev/null +++ b/p4include/_internal/pna/v0_7/types_defns2.p4 @@ -0,0 +1,67 @@ +// BEGIN:Type_defns2 + +/* Note: All of the types with `InHeader` in their name are intended + * only to carry values of the corresponding types in packet headers + * between a PNA device and the P4Runtime Server software that manages + * it. + * + * The widths are intended to be at least as large as any PNA device + * will ever have for that type. Thus these types may also be useful + * to define packet headers that are sent directly between a PNA + * device and other devices, without going through P4Runtime Server + * software (e.g. this could be useful for sending packets to a + * controller or data collection system using higher packet rates than + * the P4Runtime Server can handle). If used for this purpose, there + * is no requirement that the PNA data plane _automatically_ perform + * the numerical translation of these types that would occur if the + * header went through the P4Runtime Server. Any such desired + * translation is up to the author of the P4 program to perform with + * explicit code. + * + * All widths must be a multiple of 8, so that any subset of these + * fields may be used in a single P4 header definition, even on P4 + * implementations that restrict headers to contain fields with a + * total length that is a multiple of 8 bits. */ + +/* See the comments near the definition of PortIdUint_t for why these + * typedef definitions exist. */ +typedef bit<32> PortIdInHeaderUint_t; +typedef bit<32> InterfaceIdInHeaderUint_t; +typedef bit<32> MulticastGroupInHeaderUint_t; +typedef bit<16> MirrorSessionIdInHeaderUint_t; +typedef bit<8> MirrorSlotIdInHeaderUint_t; +typedef bit<8> ClassOfServiceInHeaderUint_t; +typedef bit<16> PacketLengthInHeaderUint_t; +typedef bit<16> MulticastInstanceInHeaderUint_t; +typedef bit<64> TimestampInHeaderUint_t; +typedef bit<32> FlowIdInHeaderUint_t; +typedef bit<8> ExpireTimeProfileIdInHeaderUint_t; + +typedef bit<32> SecurityAssocIdInHeaderUint_t; + +@p4runtime_translation("p4.org/pna/v1/PortIdInHeader_t", 32) +type PortIdInHeaderUint_t PortIdInHeader_t; +@p4runtime_translation("p4.org/pna/v1/InterfaceIdInHeader_t", 32) +type InterfaceIdInHeaderUint_t InterfaceIdInHeader_t; +@p4runtime_translation("p4.org/pna/v1/MulticastGroupInHeader_t", 32) +type MulticastGroupInHeaderUint_t MulticastGroupInHeader_t; +@p4runtime_translation("p4.org/pna/v1/MirrorSessionIdInHeader_t", 16) +type MirrorSessionIdInHeaderUint_t MirrorSessionIdInHeader_t; +@p4runtime_translation("p4.org/pna/v1/MirrorSlotIdInHeader_t", 8) +type MirrorSlotIdInHeaderUint_t MirrorSlotIdInHeader_t; +@p4runtime_translation("p4.org/pna/v1/ClassOfServiceInHeader_t", 8) +type ClassOfServiceInHeaderUint_t ClassOfServiceInHeader_t; +@p4runtime_translation("p4.org/pna/v1/PacketLengthInHeader_t", 16) +type PacketLengthInHeaderUint_t PacketLengthInHeader_t; +@p4runtime_translation("p4.org/pna/v1/MulticastInstanceInHeader_t", 16) +type MulticastInstanceInHeaderUint_t MulticastInstanceInHeader_t; +@p4runtime_translation("p4.org/pna/v1/TimestampInHeader_t", 64) +type TimestampInHeaderUint_t TimestampInHeader_t; +@p4runtime_translation("p4.org/pna/v1/FlowIdInHeader_t", 32) +type FlowIdInHeaderUint_t FlowIdInHeader_t; +@p4runtime_translation("p4.org/pna/v1/ExpireTimeProfileIdInHeader_t", 8) +type ExpireTimeProfileIdInHeaderUint_t ExpireTimeProfileIdInHeader_t; + +@p4runtime_translation("p4.org/pna/v1/SecurityAssocIdInHeader_t", 64) +type SecurityAssocIdInHeaderUint_t SecurityAssocIdInHeader_t; +// END:Type_defns2 diff --git a/p4include/_internal/pna/v0_7/types_metadata.p4 b/p4include/_internal/pna/v0_7/types_metadata.p4 new file mode 100644 index 0000000000..2ce4bfae27 --- /dev/null +++ b/p4include/_internal/pna/v0_7/types_metadata.p4 @@ -0,0 +1,46 @@ +enum PNA_Source_t { + FROM_HOST, + FROM_NET +} + +// BEGIN:Metadata_types + +struct pna_main_parser_input_metadata_t { + // common fields initialized for all packets that are input to main + // parser, regardless of direction. + bool recirculated; + // If this packet has FROM_NET source, input_port contains + // the id of the network port on which the packet arrived. + // If this packet has FROM_HOST source, input_port contains + // the id of the vport from which the packet came + PortId_t input_port; // network/host port id +} + +// is_host_port(p) returns true if p is a host port, otherwise false. +extern bool is_host_port (in PortId_t p); + +// is_net_port(p) returns true if p is a network port, otherwise +// false. +extern bool is_net_port (in PortId_t p); + +struct pna_main_input_metadata_t { + // common fields initialized for all packets that are input to main + // parser, regardless of direction. + bool recirculated; + Timestamp_t timestamp; + ParserError_t parser_error; + ClassOfService_t class_of_service; + // See comments for field input_port in struct + // pna_main_parser_input_metadata_t + PortId_t input_port; +} + +// BEGIN:Metadata_main_output +struct pna_main_output_metadata_t { + // common fields used by the architecture to decide what to do with + // the packet next, after the main parser, control, and deparser + // have finished executing one pass, regardless of the direction. + ClassOfService_t class_of_service; // 0 +} +// END:Metadata_main_output +// END:Metadata_types diff --git a/p4include/_internal/pna/v0_7/types_misc.p4 b/p4include/_internal/pna/v0_7/types_misc.p4 new file mode 100644 index 0000000000..89bdcb2d8b --- /dev/null +++ b/p4include/_internal/pna/v0_7/types_misc.p4 @@ -0,0 +1,16 @@ +// BEGIN:enum_PNA_IdleTimeout_t +/// Supported values for the pna_idle_timeout table property +enum PNA_IdleTimeout_t { + NO_TIMEOUT, + NOTIFY_CONTROL, + AUTO_DELETE +}; +// END:enum_PNA_IdleTimeout_t + +// BEGIN:Match_kinds +match_kind { + range, /// Used to represent min..max intervals + selector, /// Used for dynamic action selection via the ActionSelector extern + optional /// Either an exact match, or a wildcard matching any value for the entire field +} +// END:Match_kinds diff --git a/p4include/dpdk/pna.p4 b/p4include/dpdk/pna.p4 index 9f1b7bc87d..fc61d62a46 100644 --- a/p4include/dpdk/pna.p4 +++ b/p4include/dpdk/pna.p4 @@ -27,247 +27,13 @@ limitations under the License. * P4-16 declaration of the Portable NIC Architecture */ -/* The bit widths shown below are placeholders that might not be - * implemented by any PNA device. - * - * Each PNA implementation is free to use its own custom width in bits - * for those types that are bit for some W. */ - -/* These are defined using `typedef`, not `type`, so they are truly - * just different names for the type bit for the particular width W - * shown. Unlike the `type` definitions below, values declared with - * the `typedef` type names can be freely mingled in expressions, just - * as any value declared with type bit can. Values declared with - * one of the `type` names below _cannot_ be so freely mingled, unless - * you first cast them to the corresponding `typedef` type. While - * that may be inconvenient when you need to do arithmetic on such - * values, it is the price to pay for having all occurrences of values - * of the `type` types marked as such in the automatically generated - * control plane API. - * - * Note that the width of typedef Uint_t will always be the same - * as the width of type _t. */ -typedef bit<32> PortIdUint_t; -typedef bit<32> InterfaceIdUint_t; -typedef bit<32> MulticastGroupUint_t; -typedef bit<16> MirrorSessionIdUint_t; -typedef bit<8> MirrorSlotIdUint_t; -typedef bit<8> ClassOfServiceUint_t; -typedef bit<16> PacketLengthUint_t; -typedef bit<16> MulticastInstanceUint_t; -typedef bit<64> TimestampUint_t; -typedef bit<32> FlowIdUint_t; -typedef bit<8> ExpireTimeProfileIdUint_t; -typedef bit<3> PassNumberUint_t; - -typedef bit<32> SecurityAssocIdUint_t; - -@p4runtime_translation("p4.org/pna/v1/PortId_t", 32) -type PortIdUint_t PortId_t; -@p4runtime_translation("p4.org/pna/v1/InterfaceId_t", 32) -type InterfaceIdUint_t InterfaceId_t; -@p4runtime_translation("p4.org/pna/v1/MulticastGroup_t", 32) -type MulticastGroupUint_t MulticastGroup_t; -@p4runtime_translation("p4.org/pna/v1/MirrorSessionId_t", 16) -type MirrorSessionIdUint_t MirrorSessionId_t; -@p4runtime_translation("p4.org/pna/v1/MirrorSlotId_t", 8) -type MirrorSlotIdUint_t MirrorSlotId_t; -@p4runtime_translation("p4.org/pna/v1/ClassOfService_t", 8) -type ClassOfServiceUint_t ClassOfService_t; -@p4runtime_translation("p4.org/pna/v1/PacketLength_t", 16) -type PacketLengthUint_t PacketLength_t; -@p4runtime_translation("p4.org/pna/v1/MulticastInstance_t", 16) -type MulticastInstanceUint_t MulticastInstance_t; -@p4runtime_translation("p4.org/pna/v1/Timestamp_t", 64) -type TimestampUint_t Timestamp_t; -@p4runtime_translation("p4.org/pna/v1/FlowId_t", 32) -type FlowIdUint_t FlowId_t; -@p4runtime_translation("p4.org/pna/v1/ExpireTimeProfileId_t", 8) -type ExpireTimeProfileIdUint_t ExpireTimeProfileId_t; -@p4runtime_translation("p4.org/pna/v1/PassNumber_t", 8) -type PassNumberUint_t PassNumber_t; - -@p4runtime_translation("p4.org/pna/v1/SecurityAssocId_t", 64) -type SecurityAssocIdUint_t SecurityAssocId_t; - -typedef error ParserError_t; - -const InterfaceId_t PNA_PORT_CPU = (InterfaceId_t) 0xfffffffd; - -const MirrorSessionId_t PNA_MIRROR_SESSION_TO_CPU = (MirrorSessionId_t) 0; - -// BEGIN:Type_defns2 - -/* Note: All of the types with `InHeader` in their name are intended - * only to carry values of the corresponding types in packet headers - * between a PNA device and the P4Runtime Server software that manages - * it. - * - * The widths are intended to be at least as large as any PNA device - * will ever have for that type. Thus these types may also be useful - * to define packet headers that are sent directly between a PNA - * device and other devices, without going through P4Runtime Server - * software (e.g. this could be useful for sending packets to a - * controller or data collection system using higher packet rates than - * the P4Runtime Server can handle). If used for this purpose, there - * is no requirement that the PNA data plane _automatically_ perform - * the numerical translation of these types that would occur if the - * header went through the P4Runtime Server. Any such desired - * translation is up to the author of the P4 program to perform with - * explicit code. - * - * All widths must be a multiple of 8, so that any subset of these - * fields may be used in a single P4 header definition, even on P4 - * implementations that restrict headers to contain fields with a - * total length that is a multiple of 8 bits. */ - -/* See the comments near the definition of PortIdUint_t for why these - * typedef definitions exist. */ -typedef bit<32> PortIdInHeaderUint_t; -typedef bit<32> InterfaceIdInHeaderUint_t; -typedef bit<32> MulticastGroupInHeaderUint_t; -typedef bit<16> MirrorSessionIdInHeaderUint_t; -typedef bit<8> MirrorSlotIdInHeaderUint_t; -typedef bit<8> ClassOfServiceInHeaderUint_t; -typedef bit<16> PacketLengthInHeaderUint_t; -typedef bit<16> MulticastInstanceInHeaderUint_t; -typedef bit<64> TimestampInHeaderUint_t; -typedef bit<32> FlowIdInHeaderUint_t; -typedef bit<8> ExpireTimeProfileIdInHeaderUint_t; -typedef bit<8> PassNumberInHeaderUint_t; - -typedef bit<32> SecurityAssocIdInHeaderUint_t; - -@p4runtime_translation("p4.org/pna/v1/PortIdInHeader_t", 32) -type PortIdInHeaderUint_t PortIdInHeader_t; -@p4runtime_translation("p4.org/pna/v1/InterfaceIdInHeader_t", 32) -type InterfaceIdInHeaderUint_t InterfaceIdInHeader_t; -@p4runtime_translation("p4.org/pna/v1/MulticastGroupInHeader_t", 32) -type MulticastGroupInHeaderUint_t MulticastGroupInHeader_t; -@p4runtime_translation("p4.org/pna/v1/MirrorSessionIdInHeader_t", 16) -type MirrorSessionIdInHeaderUint_t MirrorSessionIdInHeader_t; -@p4runtime_translation("p4.org/pna/v1/MirrorSlotIdInHeader_t", 8) -type MirrorSlotIdInHeaderUint_t MirrorSlotIdInHeader_t; -@p4runtime_translation("p4.org/pna/v1/ClassOfServiceInHeader_t", 8) -type ClassOfServiceInHeaderUint_t ClassOfServiceInHeader_t; -@p4runtime_translation("p4.org/pna/v1/PacketLengthInHeader_t", 16) -type PacketLengthInHeaderUint_t PacketLengthInHeader_t; -@p4runtime_translation("p4.org/pna/v1/MulticastInstanceInHeader_t", 16) -type MulticastInstanceInHeaderUint_t MulticastInstanceInHeader_t; -@p4runtime_translation("p4.org/pna/v1/TimestampInHeader_t", 64) -type TimestampInHeaderUint_t TimestampInHeader_t; -@p4runtime_translation("p4.org/pna/v1/FlowIdInHeader_t", 32) -type FlowIdInHeaderUint_t FlowIdInHeader_t; -@p4runtime_translation("p4.org/pna/v1/ExpireTimeProfileIdInHeader_t", 8) -type ExpireTimeProfileIdInHeaderUint_t ExpireTimeProfileIdInHeader_t; -@p4runtime_translation("p4.org/pna/v1/PassNumberInHeader_t", 8) -type PassNumberInHeaderUint_t PassNumberInHeader_t; - -@p4runtime_translation("p4.org/pna/v1/SecurityAssocIdInHeader_t", 64) -type SecurityAssocIdInHeaderUint_t SecurityAssocIdInHeader_t; -// END:Type_defns2 - -/* The _int_to_header functions were written to convert a value of - * type _t (a value INTernal to the data path) to a value of - * type InHeader_t inside a header that will be sent to the CPU - * port. - * - * The _header_to_int functions were written to convert values in the - * opposite direction, typically for assigning a value in a header - * received from the CPU port, to a value you wish to use in the rest - * of your code. - * - * The reason that three casts are needed is that each of the original - * and target types is declared via P4_16 'type', so without a cast - * they can only be assigned to values of that identical type. The - * first cast changes it from the original 'type' to a 'bit' value - * of the same bit width W1. The second cast changes its bit width, - * either prepending 0s if it becomes wider, or discarding the most - * significant bits if it becomes narrower. The third cast changes it - * from a 'bit' value to the final 'type', with the same width - * W2. */ - -PortId_t pna_PortId_header_to_int (in PortIdInHeader_t x) { - return (PortId_t) (PortIdUint_t) (PortIdInHeaderUint_t) x; -} -InterfaceId_t pna_InterfaceId_header_to_int (in InterfaceIdInHeader_t x) { - return (InterfaceId_t) (InterfaceIdUint_t) (InterfaceIdInHeaderUint_t) x; -} -MulticastGroup_t pna_MulticastGroup_header_to_int (in MulticastGroupInHeader_t x) { - return (MulticastGroup_t) (MulticastGroupUint_t) (MulticastGroupInHeaderUint_t) x; -} -MirrorSessionId_t pna_MirrorSessionId_header_to_int (in MirrorSessionIdInHeader_t x) { - return (MirrorSessionId_t) (MirrorSessionIdUint_t) (MirrorSessionIdInHeaderUint_t) x; -} -ClassOfService_t pna_ClassOfService_header_to_int (in ClassOfServiceInHeader_t x) { - return (ClassOfService_t) (ClassOfServiceUint_t) (ClassOfServiceInHeaderUint_t) x; -} -PacketLength_t pna_PacketLength_header_to_int (in PacketLengthInHeader_t x) { - return (PacketLength_t) (PacketLengthUint_t) (PacketLengthInHeaderUint_t) x; -} -MulticastInstance_t pna_MulticastInstance_header_to_int (in MulticastInstanceInHeader_t x) { - return (MulticastInstance_t) (MulticastInstanceUint_t) (MulticastInstanceInHeaderUint_t) x; -} -Timestamp_t pna_Timestamp_header_to_int (in TimestampInHeader_t x) { - return (Timestamp_t) (TimestampUint_t) (TimestampInHeaderUint_t) x; -} -FlowId_t pna_FlowId_header_to_int (in FlowIdInHeader_t x) { - return (FlowId_t) (FlowIdUint_t) (FlowIdInHeaderUint_t) x; -} -ExpireTimeProfileId_t pna_ExpireTimeProfileId_header_to_int (in ExpireTimeProfileIdInHeader_t x) { - return (ExpireTimeProfileId_t) (ExpireTimeProfileIdUint_t) (ExpireTimeProfileIdInHeaderUint_t) x; -} -PassNumber_t pna_PassNumber_header_to_int (in PassNumberInHeader_t x) { - return (PassNumber_t) (PassNumberUint_t) (PassNumberInHeaderUint_t) x; -} +#include <_internal/pna/v0_5/types_core.p4> +// #include <_internal/pna/v0_5/types_defns.p4> +#include <_internal/pna/v0_5/types_defns2.p4> +#include <_internal/pna/v0_5/funcs_int_to_header.p4> +#include <_internal/pna/v0_7/types_misc.p4> -PortIdInHeader_t pna_PortId_int_to_header (in PortId_t x) { - return (PortIdInHeader_t) (PortIdInHeaderUint_t) (PortIdUint_t) x; -} -InterfaceIdInHeader_t pna_InterfaceId_int_to_header (in InterfaceId_t x) { - return (InterfaceIdInHeader_t) (InterfaceIdInHeaderUint_t) (InterfaceIdUint_t) x; -} -MulticastGroupInHeader_t pna_MulticastGroup_int_to_header (in MulticastGroup_t x) { - return (MulticastGroupInHeader_t) (MulticastGroupInHeaderUint_t) (MulticastGroupUint_t) x; -} -MirrorSessionIdInHeader_t pna_MirrorSessionId_int_to_header (in MirrorSessionId_t x) { - return (MirrorSessionIdInHeader_t) (MirrorSessionIdInHeaderUint_t) (MirrorSessionIdUint_t) x; -} -ClassOfServiceInHeader_t pna_ClassOfService_int_to_header (in ClassOfService_t x) { - return (ClassOfServiceInHeader_t) (ClassOfServiceInHeaderUint_t) (ClassOfServiceUint_t) x; -} -PacketLengthInHeader_t pna_PacketLength_int_to_header (in PacketLength_t x) { - return (PacketLengthInHeader_t) (PacketLengthInHeaderUint_t) (PacketLengthUint_t) x; -} -MulticastInstanceInHeader_t pna_MulticastInstance_int_to_header (in MulticastInstance_t x) { - return (MulticastInstanceInHeader_t) (MulticastInstanceInHeaderUint_t) (MulticastInstanceUint_t) x; -} -TimestampInHeader_t pna_Timestamp_int_to_header (in Timestamp_t x) { - return (TimestampInHeader_t) (TimestampInHeaderUint_t) (TimestampUint_t) x; -} -FlowIdInHeader_t pna_FlowId_int_to_header (in FlowId_t x) { - return (FlowIdInHeader_t) (FlowIdInHeaderUint_t) (FlowIdUint_t) x; -} -ExpireTimeProfileIdInHeader_t pna_ExpireTimeProfileId_int_to_header (in ExpireTimeProfileId_t x) { - return (ExpireTimeProfileIdInHeader_t) (ExpireTimeProfileIdInHeaderUint_t) (ExpireTimeProfileIdUint_t) x; -} -PassNumberInHeader_t pna_PassNumber_int_to_header (in PassNumber_t x) { - return (PassNumberInHeader_t) (PassNumberInHeaderUint_t) (PassNumberUint_t) x; -} - -/// Supported range of values for the pna_idle_timeout table properties -enum PNA_IdleTimeout_t { - NO_TIMEOUT, - NOTIFY_CONTROL -}; - -// BEGIN:Match_kinds -match_kind { - range, /// Used to represent min..max intervals - selector, /// Used for dynamic action selection via the ActionSelector extern - optional /// Either an exact match, or a wildcard matching any value for the entire field -} -// END:Match_kinds +// #include <_internal/pna/v0_7/extern_hash.p4> // BEGIN:Hash_algorithms enum PNA_HashAlgorithm_t { @@ -278,6 +44,7 @@ enum PNA_HashAlgorithm_t { CRC16, CRC16_CUSTOM, ONES_COMPLEMENT16, /// One's complement 16-bit sum used for IPv4 headers, + /// TCP, and UDP. TOEPLITZ, TARGET_DEFAULT /// target implementation defined } @@ -307,64 +74,9 @@ extern Hash { } // END:Hash_extern -// BEGIN:Checksum_extern -extern Checksum { - /// Constructor - Checksum(PNA_HashAlgorithm_t hash); - - /// Reset internal state and prepare unit for computation. - /// Every instance of a Checksum object is automatically initialized as - /// if clear() had been called on it. This initialization happens every - /// time the object is instantiated, that is, whenever the parser or control - /// containing the Checksum object are applied. - /// All state maintained by the Checksum object is independent per packet. - void clear(); - - /// Add data to checksum - void update(in T data); +#include <_internal/pna/v0_7/extern_checksum.p4> - /// Get checksum for data added (and not removed) since last clear - W get(); -} -// END:Checksum_extern - -// BEGIN:InternetChecksum_extern -// Checksum based on `ONES_COMPLEMENT16` algorithm used in IPv4, TCP, and UDP. -// Supports incremental updating via `subtract` method. -// See IETF RFC 1624. -extern InternetChecksum { - /// Constructor - InternetChecksum(); - - /// Reset internal state and prepare unit for computation. Every - /// instance of an InternetChecksum object is automatically - /// initialized as if clear() had been called on it, once for each - /// time the parser or control it is instantiated within is - /// executed. All state maintained by it is independent per packet. - void clear(); - - /// Add data to checksum. data must be a multiple of 16 bits long. - void add(in T data); - - /// Subtract data from existing checksum. data must be a multiple of - /// 16 bits long. - void subtract(in T data); - - /// Get checksum for data added (and not removed) since last clear - bit<16> get(); - - /// Get current state of checksum computation. The return value is - /// only intended to be used for a future call to the set_state - /// method. - bit<16> get_state(); - - /// Restore the state of the InternetChecksum instance to one - /// returned from an earlier call to the get_state method. This - /// state could have been returned from the same instance of the - /// InternetChecksum extern, or a different one. - void set_state(in bit<16> checksum_state); -} -// END:InternetChecksum_extern +// #include <_internal/pna/v0_7/extern_counter.p4> // BEGIN:CounterType_defn enum PNA_CounterType_t { @@ -402,6 +114,8 @@ extern DirectCounter { } // END:DirectCounter_extern +// #include <_internal/pna/v0_7/extern_meter.p4> + // BEGIN:MeterType_defn enum PNA_MeterType_t { PACKETS, @@ -454,56 +168,10 @@ extern DirectMeter { } // END:DirectMeter_extern -// BEGIN:Register_extern -extern Register { - /// Instantiate an array of registers. The initial value is - /// undefined. - Register(bit<32> size); - /// Initialize an array of registers and set their value to - /// initial_value. - Register(bit<32> size, T initial_value); - - T read (in S index); - void write (in S index, in T value); -} -// END:Register_extern - -// BEGIN:Random_extern -extern Random { - - /// Return a random value in the range [min, max], inclusive. - /// Implementations are allowed to support only ranges where (max - - /// min + 1) is a power of 2. P4 developers should limit their - /// arguments to such values if they wish to maximize portability. - - Random(T min, T max); - T read(); -} -// END:Random_extern - -// BEGIN:ActionProfile_extern -extern ActionProfile { - /// Construct an action profile of 'size' entries - ActionProfile(bit<32> size); -} -// END:ActionProfile_extern - -// BEGIN:ActionSelector_extern -extern ActionSelector { - /// Construct an action selector of 'size' entries - /// @param algo hash algorithm to select a member in a group - /// @param size number of entries in the action selector - /// @param outputWidth size of the key - ActionSelector(PNA_HashAlgorithm_t algo, bit<32> size, bit<32> outputWidth); -} -// END:ActionSelector_extern - -// BEGIN:Digest_extern -extern Digest { - Digest(); /// define a digest stream to the control plane - void pack(in T data); /// emit data into the stream -} -// END:Digest_extern +#include <_internal/pna/v0_7/extern_register.p4> +#include <_internal/pna/v0_7/extern_random.p4> +#include <_internal/pna/v0_7/extern_action.p4> +#include <_internal/pna/v0_7/extern_digest.p4> // PNA extern for IPsec: // IPsec accelerator result for the current packet @@ -547,107 +215,9 @@ extern ipsec_accelerator { } //END:IPSec extern +#include <_internal/pna/v0_5/types_metadata.p4> - -enum PNA_Direction_t { - NET_TO_HOST, - HOST_TO_NET -} - -// BEGIN:Metadata_types -enum PNA_PacketPath_t { - // TBD if this type remains, whether it should be an enum or - // several separate fields representing the same cases in a - // different form. - FROM_NET_PORT, - FROM_NET_LOOPEDBACK, - FROM_NET_RECIRCULATED, - FROM_HOST, - FROM_HOST_LOOPEDBACK, - FROM_HOST_RECIRCULATED -} - -struct pna_pre_input_metadata_t { - PortId_t input_port; - ParserError_t parser_error; - PNA_Direction_t direction; - PassNumber_t pass; - bool loopedback; -} - -struct pna_pre_output_metadata_t { - bool decrypt; // TBD: or use said==0 to mean no decrypt? - - // The following things are stored internally within the decrypt - // block, in a table indexed by said: - - // + The decryption algorithm, e.g. AES256, etc. - // + The decryption key - // + Any read-modify-write state in the data plane used to - // implement anti-replay attack detection. - - SecurityAssocId_t said; - bit<16> decrypt_start_offset; // in bytes? - - // TBD whether it is important to explicitly pass information to a - // decryption extern in a way visible to a P4 program about where - // headers were parsed and found. An alternative is to assume - // that the architecture saves the pre parser results somewhere, - // in a way not visible to the P4 program. -} - -struct pna_main_parser_input_metadata_t { - // common fields initialized for all packets that are input to main - // parser, regardless of direction. - PNA_Direction_t direction; - PassNumber_t pass; - bool loopedback; - // If this packet has direction NET_TO_HOST, input_port contains - // the id of the network port on which the packet arrived. - // If this packet has direction HOST_TO_NET, input_port contains - // the id of the vport from which the packet came - PortId_t input_port; // network port id -} - -struct pna_main_input_metadata_t { - // common fields initialized for all packets that are input to main - // parser, regardless of direction. - PNA_Direction_t direction; - PassNumber_t pass; - bool loopedback; - Timestamp_t timestamp; - ParserError_t parser_error; - ClassOfService_t class_of_service; - // See comments for field input_port in struct - // pna_main_parser_input_metadata_t - PortId_t input_port; -} - -// BEGIN:Metadata_main_output -struct pna_main_output_metadata_t { - // common fields used by the architecture to decide what to do with - // the packet next, after the main parser, control, and deparser - // have finished executing one pass, regardless of the direction. - ClassOfService_t class_of_service; // 0 -} -// END:Metadata_main_output -// END:Metadata_types - - -// The following extern functions are "forwarding" functions -- they -// all set the destination of the packet. Calling one of them -// overwrites and replaces the effect of any earlier call to any of -// the functions in this set. Only the last one executed will -// actually take effect for the packet. - -// + drop_packet -// + send_to_port - - -// drop_packet() - Cause the packet to be dropped when it finishes -// completing the main control. -// -// Invoking drop_packet() is supported only within the main control. +// #include <_internal/pna/v0_5/extern_funcs.p4> extern void drop_packet(); @@ -658,123 +228,23 @@ extern void mirror_packet(MirrorSlotId_t mirror_slot_id, extern void recirculate(); -// TBD: Does it make sense to have a data plane add of a hit action -// that has in, out, or inout parameters? -// -// TBD: Should we require the return value? Can most targets -// implement it? If not, consider having two separate variants of -// add_entry, one with no return value (i.e. type void). Such a -// variant of add_entry seems difficult to use correctly, if it is -// possible for entries to fail to be added. - -// TBD: For add_entry calls to a table with property 'idle_timeout' or -// 'idle_timeout_with_auto_delete' equal to true, there should -// probably be an optional parameter at the end that specifies the new -// entry's initial expire_time_profile_id. - extern bool add_entry(string action_name, in T action_params, in ExpireTimeProfileId_t expire_time_profile_id); extern FlowId_t allocate_flow_id(); - -// set_entry_expire_time() may only be called from within an action of -// a table with property 'idle_timeout' or -// 'idle_timeout_with_auto_delete' equal to true. - -// Calling it causes the expiration time of the entry to be the one -// that the control plane has configured for the specified -// expire_time_profile_id. - extern void set_entry_expire_time( in ExpireTimeProfileId_t expire_time_profile_id); - -// restart_expire_timer() may only be called from within an action of -// a table with property 'idle_timeout' or -// 'idle_timeout_with_auto_delete' equal to true. - -// Calling it causes the dynamic expiration timer of the entry to be -// reset, so that the entry will remain active from the now until that -// time in the future. - -// TBD: Do any targets support a table with one of the idle_timeout -// properties such that matching an entry _does not_ cause this side -// effect to occur? If not, we could simply document it the way that -// I believe it currently behaves in all existing architectures, which -// is that every hit action implicitly causes the entry's expiration -// timer to be reset to its configured time interval in the future. - extern void restart_expire_timer(); - -// SelectByDirection is a simple pure function that behaves exactly as -// the P4_16 function definition given in comments below. It is an -// extern function to ensure that the front/mid end of the p4c -// compiler leaves occurrences of it as is, visible to target-specific -// compiler back end code, so targets have all information needed to -// optimize it as they wish. - -// One example of its use is in table key expressions, for tables -// where one wishes to swap IP source/destination addresses for -// packets processed in the different directions. - -/* -T SelectByDirection( - in PNA_Direction_t direction, - in T n2h_value, - in T h2n_value) -{ - if (direction == PNA_Direction_t.NET_TO_HOST) { - return n2h_value; - } else { - return h2n_value; - } -} -*/ - @pure extern T SelectByDirection( in PNA_Direction_t direction, in T n2h_value, in T h2n_value); - - - -// BEGIN:Programmable_blocks -control PreControlT( - in PH pre_hdr, - inout PM pre_user_meta, - in pna_pre_input_metadata_t istd, - inout pna_pre_output_metadata_t ostd); - -parser MainParserT( - packet_in pkt, - //in PM pre_user_meta, - out MH main_hdr, - inout MM main_user_meta, - in pna_main_parser_input_metadata_t istd); - -control MainControlT( - //in PM pre_user_meta, - inout MH main_hdr, - inout MM main_user_meta, - in pna_main_input_metadata_t istd, - inout pna_main_output_metadata_t ostd); - -control MainDeparserT( - packet_out pkt, - in MH main_hdr, - in MM main_user_meta, - in pna_main_output_metadata_t ostd); - -package PNA_NIC( - MainParserT main_parser, - PreControlT pre_control, - MainControlT main_control, - MainDeparserT main_deparser); -// END:Programmable_blocks +#include <_internal/pna/v0_5/blocks.p4> #endif // __PNA_P4__ diff --git a/p4include/pna.p4 b/p4include/pna.p4 index 2d3cdb65ac..090794758c 100644 --- a/p4include/pna.p4 +++ b/p4include/pna.p4 @@ -27,337 +27,16 @@ limitations under the License. * P4-16 declaration of the Portable NIC Architecture */ -/* The bit widths shown below are placeholders that might not be - * implemented by any PNA device. - * - * Each PNA implementation is free to use its own custom width in bits - * for those types that are bit for some W. */ - -/* These are defined using `typedef`, not `type`, so they are truly - * just different names for the type bit for the particular width W - * shown. Unlike the `type` definitions below, values declared with - * the `typedef` type names can be freely mingled in expressions, just - * as any value declared with type bit can. Values declared with - * one of the `type` names below _cannot_ be so freely mingled, unless - * you first cast them to the corresponding `typedef` type. While - * that may be inconvenient when you need to do arithmetic on such - * values, it is the price to pay for having all occurrences of values - * of the `type` types marked as such in the automatically generated - * control plane API. - * - * Note that the width of typedef Uint_t will always be the same - * as the width of type _t. */ -typedef bit<32> PortIdUint_t; -typedef bit<32> InterfaceIdUint_t; -typedef bit<32> MulticastGroupUint_t; -typedef bit<16> MirrorSessionIdUint_t; -typedef bit<8> MirrorSlotIdUint_t; -typedef bit<8> ClassOfServiceUint_t; -typedef bit<16> PacketLengthUint_t; -typedef bit<16> MulticastInstanceUint_t; -typedef bit<64> TimestampUint_t; -typedef bit<32> FlowIdUint_t; -typedef bit<8> ExpireTimeProfileIdUint_t; -typedef bit<3> PassNumberUint_t; - -typedef bit<32> SecurityAssocIdUint_t; - -@p4runtime_translation("p4.org/pna/v1/PortId_t", 32) -type PortIdUint_t PortId_t; -@p4runtime_translation("p4.org/pna/v1/InterfaceId_t", 32) -type InterfaceIdUint_t InterfaceId_t; -@p4runtime_translation("p4.org/pna/v1/MulticastGroup_t", 32) -type MulticastGroupUint_t MulticastGroup_t; -@p4runtime_translation("p4.org/pna/v1/MirrorSessionId_t", 16) -type MirrorSessionIdUint_t MirrorSessionId_t; -@p4runtime_translation("p4.org/pna/v1/MirrorSlotId_t", 8) -type MirrorSlotIdUint_t MirrorSlotId_t; -@p4runtime_translation("p4.org/pna/v1/ClassOfService_t", 8) -type ClassOfServiceUint_t ClassOfService_t; -@p4runtime_translation("p4.org/pna/v1/PacketLength_t", 16) -type PacketLengthUint_t PacketLength_t; -@p4runtime_translation("p4.org/pna/v1/MulticastInstance_t", 16) -type MulticastInstanceUint_t MulticastInstance_t; -@p4runtime_translation("p4.org/pna/v1/Timestamp_t", 64) -type TimestampUint_t Timestamp_t; -@p4runtime_translation("p4.org/pna/v1/FlowId_t", 32) -type FlowIdUint_t FlowId_t; -@p4runtime_translation("p4.org/pna/v1/ExpireTimeProfileId_t", 8) -type ExpireTimeProfileIdUint_t ExpireTimeProfileId_t; -@p4runtime_translation("p4.org/pna/v1/PassNumber_t", 8) -type PassNumberUint_t PassNumber_t; - -@p4runtime_translation("p4.org/pna/v1/SecurityAssocId_t", 64) -type SecurityAssocIdUint_t SecurityAssocId_t; - -typedef error ParserError_t; - -const InterfaceId_t PNA_PORT_CPU = (InterfaceId_t) 0xfffffffd; - -const MirrorSessionId_t PNA_MIRROR_SESSION_TO_CPU = (MirrorSessionId_t) 0; - -// BEGIN:Type_defns2 - -/* Note: All of the types with `InHeader` in their name are intended - * only to carry values of the corresponding types in packet headers - * between a PNA device and the P4Runtime Server software that manages - * it. - * - * The widths are intended to be at least as large as any PNA device - * will ever have for that type. Thus these types may also be useful - * to define packet headers that are sent directly between a PNA - * device and other devices, without going through P4Runtime Server - * software (e.g. this could be useful for sending packets to a - * controller or data collection system using higher packet rates than - * the P4Runtime Server can handle). If used for this purpose, there - * is no requirement that the PNA data plane _automatically_ perform - * the numerical translation of these types that would occur if the - * header went through the P4Runtime Server. Any such desired - * translation is up to the author of the P4 program to perform with - * explicit code. - * - * All widths must be a multiple of 8, so that any subset of these - * fields may be used in a single P4 header definition, even on P4 - * implementations that restrict headers to contain fields with a - * total length that is a multiple of 8 bits. */ - -/* See the comments near the definition of PortIdUint_t for why these - * typedef definitions exist. */ -typedef bit<32> PortIdInHeaderUint_t; -typedef bit<32> InterfaceIdInHeaderUint_t; -typedef bit<32> MulticastGroupInHeaderUint_t; -typedef bit<16> MirrorSessionIdInHeaderUint_t; -typedef bit<8> MirrorSlotIdInHeaderUint_t; -typedef bit<8> ClassOfServiceInHeaderUint_t; -typedef bit<16> PacketLengthInHeaderUint_t; -typedef bit<16> MulticastInstanceInHeaderUint_t; -typedef bit<64> TimestampInHeaderUint_t; -typedef bit<32> FlowIdInHeaderUint_t; -typedef bit<8> ExpireTimeProfileIdInHeaderUint_t; -typedef bit<8> PassNumberInHeaderUint_t; - -typedef bit<32> SecurityAssocIdInHeaderUint_t; - -@p4runtime_translation("p4.org/pna/v1/PortIdInHeader_t", 32) -type PortIdInHeaderUint_t PortIdInHeader_t; -@p4runtime_translation("p4.org/pna/v1/InterfaceIdInHeader_t", 32) -type InterfaceIdInHeaderUint_t InterfaceIdInHeader_t; -@p4runtime_translation("p4.org/pna/v1/MulticastGroupInHeader_t", 32) -type MulticastGroupInHeaderUint_t MulticastGroupInHeader_t; -@p4runtime_translation("p4.org/pna/v1/MirrorSessionIdInHeader_t", 16) -type MirrorSessionIdInHeaderUint_t MirrorSessionIdInHeader_t; -@p4runtime_translation("p4.org/pna/v1/MirrorSlotIdInHeader_t", 8) -type MirrorSlotIdInHeaderUint_t MirrorSlotIdInHeader_t; -@p4runtime_translation("p4.org/pna/v1/ClassOfServiceInHeader_t", 8) -type ClassOfServiceInHeaderUint_t ClassOfServiceInHeader_t; -@p4runtime_translation("p4.org/pna/v1/PacketLengthInHeader_t", 16) -type PacketLengthInHeaderUint_t PacketLengthInHeader_t; -@p4runtime_translation("p4.org/pna/v1/MulticastInstanceInHeader_t", 16) -type MulticastInstanceInHeaderUint_t MulticastInstanceInHeader_t; -@p4runtime_translation("p4.org/pna/v1/TimestampInHeader_t", 64) -type TimestampInHeaderUint_t TimestampInHeader_t; -@p4runtime_translation("p4.org/pna/v1/FlowIdInHeader_t", 32) -type FlowIdInHeaderUint_t FlowIdInHeader_t; -@p4runtime_translation("p4.org/pna/v1/ExpireTimeProfileIdInHeader_t", 8) -type ExpireTimeProfileIdInHeaderUint_t ExpireTimeProfileIdInHeader_t; -@p4runtime_translation("p4.org/pna/v1/PassNumberInHeader_t", 8) -type PassNumberInHeaderUint_t PassNumberInHeader_t; - -@p4runtime_translation("p4.org/pna/v1/SecurityAssocIdInHeader_t", 64) -type SecurityAssocIdInHeaderUint_t SecurityAssocIdInHeader_t; -// END:Type_defns2 - -/* The _int_to_header functions were written to convert a value of - * type _t (a value INTernal to the data path) to a value of - * type InHeader_t inside a header that will be sent to the CPU - * port. - * - * The _header_to_int functions were written to convert values in the - * opposite direction, typically for assigning a value in a header - * received from the CPU port, to a value you wish to use in the rest - * of your code. - * - * The reason that three casts are needed is that each of the original - * and target types is declared via P4_16 'type', so without a cast - * they can only be assigned to values of that identical type. The - * first cast changes it from the original 'type' to a 'bit' value - * of the same bit width W1. The second cast changes its bit width, - * either prepending 0s if it becomes wider, or discarding the most - * significant bits if it becomes narrower. The third cast changes it - * from a 'bit' value to the final 'type', with the same width - * W2. */ - -PortId_t pna_PortId_header_to_int (in PortIdInHeader_t x) { - return (PortId_t) (PortIdUint_t) (PortIdInHeaderUint_t) x; -} -InterfaceId_t pna_InterfaceId_header_to_int (in InterfaceIdInHeader_t x) { - return (InterfaceId_t) (InterfaceIdUint_t) (InterfaceIdInHeaderUint_t) x; -} -MulticastGroup_t pna_MulticastGroup_header_to_int (in MulticastGroupInHeader_t x) { - return (MulticastGroup_t) (MulticastGroupUint_t) (MulticastGroupInHeaderUint_t) x; -} -MirrorSessionId_t pna_MirrorSessionId_header_to_int (in MirrorSessionIdInHeader_t x) { - return (MirrorSessionId_t) (MirrorSessionIdUint_t) (MirrorSessionIdInHeaderUint_t) x; -} -ClassOfService_t pna_ClassOfService_header_to_int (in ClassOfServiceInHeader_t x) { - return (ClassOfService_t) (ClassOfServiceUint_t) (ClassOfServiceInHeaderUint_t) x; -} -PacketLength_t pna_PacketLength_header_to_int (in PacketLengthInHeader_t x) { - return (PacketLength_t) (PacketLengthUint_t) (PacketLengthInHeaderUint_t) x; -} -MulticastInstance_t pna_MulticastInstance_header_to_int (in MulticastInstanceInHeader_t x) { - return (MulticastInstance_t) (MulticastInstanceUint_t) (MulticastInstanceInHeaderUint_t) x; -} -Timestamp_t pna_Timestamp_header_to_int (in TimestampInHeader_t x) { - return (Timestamp_t) (TimestampUint_t) (TimestampInHeaderUint_t) x; -} -FlowId_t pna_FlowId_header_to_int (in FlowIdInHeader_t x) { - return (FlowId_t) (FlowIdUint_t) (FlowIdInHeaderUint_t) x; -} -ExpireTimeProfileId_t pna_ExpireTimeProfileId_header_to_int (in ExpireTimeProfileIdInHeader_t x) { - return (ExpireTimeProfileId_t) (ExpireTimeProfileIdUint_t) (ExpireTimeProfileIdInHeaderUint_t) x; -} -PassNumber_t pna_PassNumber_header_to_int (in PassNumberInHeader_t x) { - return (PassNumber_t) (PassNumberUint_t) (PassNumberInHeaderUint_t) x; -} - -PortIdInHeader_t pna_PortId_int_to_header (in PortId_t x) { - return (PortIdInHeader_t) (PortIdInHeaderUint_t) (PortIdUint_t) x; -} -InterfaceIdInHeader_t pna_InterfaceId_int_to_header (in InterfaceId_t x) { - return (InterfaceIdInHeader_t) (InterfaceIdInHeaderUint_t) (InterfaceIdUint_t) x; -} -MulticastGroupInHeader_t pna_MulticastGroup_int_to_header (in MulticastGroup_t x) { - return (MulticastGroupInHeader_t) (MulticastGroupInHeaderUint_t) (MulticastGroupUint_t) x; -} -MirrorSessionIdInHeader_t pna_MirrorSessionId_int_to_header (in MirrorSessionId_t x) { - return (MirrorSessionIdInHeader_t) (MirrorSessionIdInHeaderUint_t) (MirrorSessionIdUint_t) x; -} -ClassOfServiceInHeader_t pna_ClassOfService_int_to_header (in ClassOfService_t x) { - return (ClassOfServiceInHeader_t) (ClassOfServiceInHeaderUint_t) (ClassOfServiceUint_t) x; -} -PacketLengthInHeader_t pna_PacketLength_int_to_header (in PacketLength_t x) { - return (PacketLengthInHeader_t) (PacketLengthInHeaderUint_t) (PacketLengthUint_t) x; -} -MulticastInstanceInHeader_t pna_MulticastInstance_int_to_header (in MulticastInstance_t x) { - return (MulticastInstanceInHeader_t) (MulticastInstanceInHeaderUint_t) (MulticastInstanceUint_t) x; -} -TimestampInHeader_t pna_Timestamp_int_to_header (in Timestamp_t x) { - return (TimestampInHeader_t) (TimestampInHeaderUint_t) (TimestampUint_t) x; -} -FlowIdInHeader_t pna_FlowId_int_to_header (in FlowId_t x) { - return (FlowIdInHeader_t) (FlowIdInHeaderUint_t) (FlowIdUint_t) x; -} -ExpireTimeProfileIdInHeader_t pna_ExpireTimeProfileId_int_to_header (in ExpireTimeProfileId_t x) { - return (ExpireTimeProfileIdInHeader_t) (ExpireTimeProfileIdInHeaderUint_t) (ExpireTimeProfileIdUint_t) x; -} -PassNumberInHeader_t pna_PassNumber_int_to_header (in PassNumber_t x) { - return (PassNumberInHeader_t) (PassNumberInHeaderUint_t) (PassNumberUint_t) x; -} +#include <_internal/pna/v0_5/types_core.p4> +// #include <_internal/pna/v0_5/types_defns.p4> +#include <_internal/pna/v0_5/types_defns2.p4> +#include <_internal/pna/v0_5/funcs_int_to_header.p4> +#include <_internal/pna/v0_7/types_misc.p4> -/// Supported range of values for the pna_idle_timeout table properties -enum PNA_IdleTimeout_t { - NO_TIMEOUT, - NOTIFY_CONTROL -}; - -// BEGIN:Match_kinds -match_kind { - range, /// Used to represent min..max intervals - selector, /// Used for dynamic action selection via the ActionSelector extern - optional /// Either an exact match, or a wildcard matching any value for the entire field -} -// END:Match_kinds +#include <_internal/pna/v0_5/extern_hash.p4> +#include <_internal/pna/v0_7/extern_checksum.p4> -// BEGIN:Hash_algorithms -enum PNA_HashAlgorithm_t { - // TBD what this type's values will be for PNA - TARGET_DEFAULT /// target implementation defined -} -// END:Hash_algorithms - -// BEGIN:Hash_extern -extern Hash { - /// Constructor - Hash(PNA_HashAlgorithm_t algo); - - /// Compute the hash for data. - /// @param data The data over which to calculate the hash. - /// @return The hash value. - O get_hash(in D data); - - /// Compute the hash for data, with modulo by max, then add base. - /// @param base Minimum return value. - /// @param data The data over which to calculate the hash. - /// @param max The hash value is divided by max to get modulo. - /// An implementation may limit the largest value supported, - /// e.g. to a value like 32, or 256, and may also only - /// support powers of 2 for this value. P4 developers should - /// limit their choice to such values if they wish to - /// maximize portability. - /// @return (base + (h % max)) where h is the hash value. - O get_hash(in T base, in D data, in T max); -} -// END:Hash_extern - -// BEGIN:Checksum_extern -extern Checksum { - /// Constructor - Checksum(PNA_HashAlgorithm_t hash); - - /// Reset internal state and prepare unit for computation. - /// Every instance of a Checksum object is automatically initialized as - /// if clear() had been called on it. This initialization happens every - /// time the object is instantiated, that is, whenever the parser or control - /// containing the Checksum object are applied. - /// All state maintained by the Checksum object is independent per packet. - void clear(); - - /// Add data to checksum - void update(in T data); - - /// Get checksum for data added (and not removed) since last clear - W get(); -} -// END:Checksum_extern - -// BEGIN:InternetChecksum_extern -// Checksum based on `ONES_COMPLEMENT16` algorithm used in IPv4, TCP, and UDP. -// Supports incremental updating via `subtract` method. -// See IETF RFC 1624. -extern InternetChecksum { - /// Constructor - InternetChecksum(); - - /// Reset internal state and prepare unit for computation. Every - /// instance of an InternetChecksum object is automatically - /// initialized as if clear() had been called on it, once for each - /// time the parser or control it is instantiated within is - /// executed. All state maintained by it is independent per packet. - void clear(); - - /// Add data to checksum. data must be a multiple of 16 bits long. - void add(in T data); - - /// Subtract data from existing checksum. data must be a multiple of - /// 16 bits long. - void subtract(in T data); - - /// Get checksum for data added (and not removed) since last clear - bit<16> get(); - - /// Get current state of checksum computation. The return value is - /// only intended to be used for a future call to the set_state - /// method. - bit<16> get_state(); - - /// Restore the state of the InternetChecksum instance to one - /// returned from an earlier call to the get_state method. This - /// state could have been returned from the same instance of the - /// InternetChecksum extern, or a different one. - void set_state(in bit<16> checksum_state); -} -// END:InternetChecksum_extern +// #include <_internal/pna/v0_7/extern_counter.p4> // BEGIN:CounterType_defn enum PNA_CounterType_t { @@ -386,6 +65,8 @@ extern DirectCounter { } // END:DirectCounter_extern +// #include <_internal/pna/v0_7/extern_meter.p4> + // BEGIN:MeterType_defn enum PNA_MeterType_t { PACKETS, @@ -424,156 +105,14 @@ extern DirectMeter { } // END:DirectMeter_extern -// BEGIN:Register_extern -extern Register { - /// Instantiate an array of registers. The initial value is - /// undefined. - Register(bit<32> size); - /// Initialize an array of registers and set their value to - /// initial_value. - Register(bit<32> size, T initial_value); - - T read (in S index); - void write (in S index, in T value); -} -// END:Register_extern - -// BEGIN:Random_extern -extern Random { - - /// Return a random value in the range [min, max], inclusive. - /// Implementations are allowed to support only ranges where (max - - /// min + 1) is a power of 2. P4 developers should limit their - /// arguments to such values if they wish to maximize portability. - - Random(T min, T max); - T read(); -} -// END:Random_extern - -// BEGIN:ActionProfile_extern -extern ActionProfile { - /// Construct an action profile of 'size' entries - ActionProfile(bit<32> size); -} -// END:ActionProfile_extern - -// BEGIN:ActionSelector_extern -extern ActionSelector { - /// Construct an action selector of 'size' entries - /// @param algo hash algorithm to select a member in a group - /// @param size number of entries in the action selector - /// @param outputWidth size of the key - ActionSelector(PNA_HashAlgorithm_t algo, bit<32> size, bit<32> outputWidth); -} -// END:ActionSelector_extern - -// BEGIN:Digest_extern -extern Digest { - Digest(); /// define a digest stream to the control plane - void pack(in T data); /// emit data into the stream -} -// END:Digest_extern - -enum PNA_Direction_t { - NET_TO_HOST, - HOST_TO_NET -} - -// BEGIN:Metadata_types -enum PNA_PacketPath_t { - // TBD if this type remains, whether it should be an enum or - // several separate fields representing the same cases in a - // different form. - FROM_NET_PORT, - FROM_NET_LOOPEDBACK, - FROM_NET_RECIRCULATED, - FROM_HOST, - FROM_HOST_LOOPEDBACK, - FROM_HOST_RECIRCULATED -} - -struct pna_pre_input_metadata_t { - PortId_t input_port; - ParserError_t parser_error; - PNA_Direction_t direction; - PassNumber_t pass; - bool loopedback; -} - -struct pna_pre_output_metadata_t { - bool decrypt; // TBD: or use said==0 to mean no decrypt? - - // The following things are stored internally within the decrypt - // block, in a table indexed by said: - - // + The decryption algorithm, e.g. AES256, etc. - // + The decryption key - // + Any read-modify-write state in the data plane used to - // implement anti-replay attack detection. - - SecurityAssocId_t said; - bit<16> decrypt_start_offset; // in bytes? - - // TBD whether it is important to explicitly pass information to a - // decryption extern in a way visible to a P4 program about where - // headers were parsed and found. An alternative is to assume - // that the architecture saves the pre parser results somewhere, - // in a way not visible to the P4 program. -} - -struct pna_main_parser_input_metadata_t { - // common fields initialized for all packets that are input to main - // parser, regardless of direction. - PNA_Direction_t direction; - PassNumber_t pass; - bool loopedback; - // If this packet has direction NET_TO_HOST, input_port contains - // the id of the network port on which the packet arrived. - // If this packet has direction HOST_TO_NET, input_port contains - // the id of the vport from which the packet came - PortId_t input_port; // network port id -} - -struct pna_main_input_metadata_t { - // common fields initialized for all packets that are input to main - // parser, regardless of direction. - PNA_Direction_t direction; - PassNumber_t pass; - bool loopedback; - Timestamp_t timestamp; - ParserError_t parser_error; - ClassOfService_t class_of_service; - // See comments for field input_port in struct - // pna_main_parser_input_metadata_t - PortId_t input_port; -} - -// BEGIN:Metadata_main_output -struct pna_main_output_metadata_t { - // common fields used by the architecture to decide what to do with - // the packet next, after the main parser, control, and deparser - // have finished executing one pass, regardless of the direction. - ClassOfService_t class_of_service; // 0 -} -// END:Metadata_main_output -// END:Metadata_types - - -// The following extern functions are "forwarding" functions -- they -// all set the destination of the packet. Calling one of them -// overwrites and replaces the effect of any earlier call to any of -// the functions in this set. Only the last one executed will -// actually take effect for the packet. - -// + drop_packet -// + send_to_port +#include <_internal/pna/v0_7/extern_register.p4> +#include <_internal/pna/v0_7/extern_random.p4> +#include <_internal/pna/v0_7/extern_action.p4> +#include <_internal/pna/v0_7/extern_digest.p4> +#include <_internal/pna/v0_5/types_metadata.p4> -// drop_packet() - Cause the packet to be dropped when it finishes -// completing the main control. -// -// Invoking drop_packet() is supported only within the main control. +// #include <_internal/pna/v0_5/extern_funcs.p4> extern void drop_packet(); @@ -584,123 +123,23 @@ extern void mirror_packet(MirrorSlotId_t mirror_slot_id, extern void recirculate(); -// TBD: Does it make sense to have a data plane add of a hit action -// that has in, out, or inout parameters? -// -// TBD: Should we require the return value? Can most targets -// implement it? If not, consider having two separate variants of -// add_entry, one with no return value (i.e. type void). Such a -// variant of add_entry seems difficult to use correctly, if it is -// possible for entries to fail to be added. - -// TBD: For add_entry calls to a table with property 'idle_timeout' or -// 'idle_timeout_with_auto_delete' equal to true, there should -// probably be an optional parameter at the end that specifies the new -// entry's initial expire_time_profile_id. - extern bool add_entry(string action_name, in T action_params, in ExpireTimeProfileId_t expire_time_profile_id); extern FlowId_t allocate_flow_id(); - -// set_entry_expire_time() may only be called from within an action of -// a table with property 'idle_timeout' or -// 'idle_timeout_with_auto_delete' equal to true. - -// Calling it causes the expiration time of the entry to be the one -// that the control plane has configured for the specified -// expire_time_profile_id. - extern void set_entry_expire_time( in ExpireTimeProfileId_t expire_time_profile_id); - -// restart_expire_timer() may only be called from within an action of -// a table with property 'idle_timeout' or -// 'idle_timeout_with_auto_delete' equal to true. - -// Calling it causes the dynamic expiration timer of the entry to be -// reset, so that the entry will remain active from the now until that -// time in the future. - -// TBD: Do any targets support a table with one of the idle_timeout -// properties such that matching an entry _does not_ cause this side -// effect to occur? If not, we could simply document it the way that -// I believe it currently behaves in all existing architectures, which -// is that every hit action implicitly causes the entry's expiration -// timer to be reset to its configured time interval in the future. - extern void restart_expire_timer(); - -// SelectByDirection is a simple pure function that behaves exactly as -// the P4_16 function definition given in comments below. It is an -// extern function to ensure that the front/mid end of the p4c -// compiler leaves occurrences of it as is, visible to target-specific -// compiler back end code, so targets have all information needed to -// optimize it as they wish. - -// One example of its use is in table key expressions, for tables -// where one wishes to swap IP source/destination addresses for -// packets processed in the different directions. - -/* -T SelectByDirection( - in PNA_Direction_t direction, - in T n2h_value, - in T h2n_value) -{ - if (direction == PNA_Direction_t.NET_TO_HOST) { - return n2h_value; - } else { - return h2n_value; - } -} -*/ - @pure extern T SelectByDirection( in PNA_Direction_t direction, in T n2h_value, in T h2n_value); - - - -// BEGIN:Programmable_blocks -control PreControlT( - in PH pre_hdr, - inout PM pre_user_meta, - in pna_pre_input_metadata_t istd, - inout pna_pre_output_metadata_t ostd); - -parser MainParserT( - packet_in pkt, - //in PM pre_user_meta, - out MH main_hdr, - inout MM main_user_meta, - in pna_main_parser_input_metadata_t istd); - -control MainControlT( - //in PM pre_user_meta, - inout MH main_hdr, - inout MM main_user_meta, - in pna_main_input_metadata_t istd, - inout pna_main_output_metadata_t ostd); - -control MainDeparserT( - packet_out pkt, - in MH main_hdr, - in MM main_user_meta, - in pna_main_output_metadata_t ostd); - -package PNA_NIC( - MainParserT main_parser, - PreControlT pre_control, - MainControlT main_control, - MainDeparserT main_deparser); -// END:Programmable_blocks +#include <_internal/pna/v0_5/blocks.p4> #endif // __PNA_P4__ diff --git a/p4include/tc/pna.p4 b/p4include/tc/pna.p4 index e7cb518ce8..42bdeea9c6 100644 --- a/p4include/tc/pna.p4 +++ b/p4include/tc/pna.p4 @@ -22,408 +22,16 @@ limitations under the License. * P4-16 declaration of the Portable NIC Architecture */ -/** - * These types need to be defined before including the architecture file - * and the macro protecting them should be defined. - */ -#define PNA_PLACEHOLDER_CORE_TYPES -#ifdef PNA_PLACEHOLDER_CORE_TYPES - -/* The bit widths shown below are placeholders that might not be - * implemented by any PNA device. - * - * Each PNA implementation is free to use its own custom width in bits - * for those types that are bit for some W. */ - -/* These are defined using `typedef`, not `type`, so they are truly - * just different names for the type bit for the particular width W - * shown. Unlike the `type` definitions below, values declared with - * the `typedef` type names can be freely mingled in expressions, just - * as any value declared with type bit can. Values declared with - * one of the `type` names below _cannot_ be so freely mingled, unless - * you first cast them to the corresponding `typedef` type. While - * that may be inconvenient when you need to do arithmetic on such - * values, it is the price to pay for having all occurrences of values - * of the `type` types marked as such in the automatically generated - * control plane API. - * - * Note that the width of typedef Uint_t will always be the same - * as the width of type _t. */ -typedef bit<32> PortIdUint_t; -typedef bit<32> InterfaceIdUint_t; -typedef bit<32> MulticastGroupUint_t; -typedef bit<16> MirrorSessionIdUint_t; -typedef bit<8> MirrorSlotIdUint_t; -typedef bit<8> ClassOfServiceUint_t; -typedef bit<16> PacketLengthUint_t; -typedef bit<16> MulticastInstanceUint_t; -typedef bit<64> TimestampUint_t; -typedef bit<32> FlowIdUint_t; -typedef bit<8> ExpireTimeProfileIdUint_t; - -typedef bit<32> SecurityAssocIdUint_t; - -@p4runtime_translation("p4.org/pna/v1/PortId_t", 32) -type PortIdUint_t PortId_t; -@p4runtime_translation("p4.org/pna/v1/InterfaceId_t", 32) -type InterfaceIdUint_t InterfaceId_t; -@p4runtime_translation("p4.org/pna/v1/MulticastGroup_t", 32) -type MulticastGroupUint_t MulticastGroup_t; -@p4runtime_translation("p4.org/pna/v1/MirrorSessionId_t", 16) -type MirrorSessionIdUint_t MirrorSessionId_t; -@p4runtime_translation("p4.org/pna/v1/MirrorSlotId_t", 8) -type MirrorSlotIdUint_t MirrorSlotId_t; -@p4runtime_translation("p4.org/pna/v1/ClassOfService_t", 8) -type ClassOfServiceUint_t ClassOfService_t; -@p4runtime_translation("p4.org/pna/v1/PacketLength_t", 16) -type PacketLengthUint_t PacketLength_t; -@p4runtime_translation("p4.org/pna/v1/MulticastInstance_t", 16) -type MulticastInstanceUint_t MulticastInstance_t; -@p4runtime_translation("p4.org/pna/v1/Timestamp_t", 64) -type TimestampUint_t Timestamp_t; -@p4runtime_translation("p4.org/pna/v1/FlowId_t", 32) -type FlowIdUint_t FlowId_t; -@p4runtime_translation("p4.org/pna/v1/ExpireTimeProfileId_t", 8) -type ExpireTimeProfileIdUint_t ExpireTimeProfileId_t; - -@p4runtime_translation("p4.org/pna/v1/SecurityAssocId_t", 64) -type SecurityAssocIdUint_t SecurityAssocId_t; - -typedef error ParserError_t; - -const InterfaceId_t PNA_PORT_CPU = (InterfaceId_t) 0xfffffffd; - -const MirrorSessionId_t PNA_MIRROR_SESSION_TO_CPU = (MirrorSessionId_t) 0; - -#endif // PNA_PLACEHOLDER_CORE_TYPES - -#ifndef PNA_PLACEHOLDER_CORE_TYPES -#error "Please define the following types for PNA and undef the PNA_PLACEHOLDER_CORE_TYPES macro" -// BEGIN:Type_defns -/* These are defined using `typedef`, not `type`, so they are truly - * just different names for the type bit for the particular width W - * shown. Unlike the `type` definitions below, values declared with - * the `typedef` type names can be freely mingled in expressions, just - * as any value declared with type bit can. Values declared with - * one of the `type` names below _cannot_ be so freely mingled, unless - * you first cast them to the corresponding `typedef` type. While - * that may be inconvenient when you need to do arithmetic on such - * values, it is the price to pay for having all occurrences of values - * of the `type` types marked as such in the automatically generated - * control plane API. - * - * Note that the width of typedef Uint_t will always be the same - * as the width of type _t. */ -typedef bit PortIdUint_t; -typedef bit InterfaceIdUint_t; -typedef bit MulticastGroupUint_t; -typedef bit MirrorSessionIdUint_t; -typedef bit MirrorSlotIdUint_t; -typedef bit ClassOfServiceUint_t; -typedef bit PacketLengthUint_t; -typedef bit MulticastInstanceUint_t; -typedef bit TimestampUint_t; -typedef bit FlowIdUint_t; -typedef bit ExpireTimeProfileIdUint_t; - -typedef bit SecurityAssocIdUint_t; - -@p4runtime_translation("p4.org/pna/v1/PortId_t", 32) -type PortIdUint_t PortId_t; -@p4runtime_translation("p4.org/pna/v1/InterfaceId_t", 32) -type InterfaceIdUint_t InterfaceId_t; -@p4runtime_translation("p4.org/pna/v1/MulticastGroup_t", 32) -type MulticastGroupUint_t MulticastGroup_t; -@p4runtime_translation("p4.org/pna/v1/MirrorSessionId_t", 16) -type MirrorSessionIdUint_t MirrorSessionId_t; -@p4runtime_translation("p4.org/pna/v1/MirrorSlotId_t", 8) -type MirrorSlotIdUint_t MirrorSlotId_t; -@p4runtime_translation("p4.org/pna/v1/ClassOfService_t", 8) -type ClassOfServiceUint_t ClassOfService_t; -@p4runtime_translation("p4.org/pna/v1/PacketLength_t", 16) -type PacketLengthUint_t PacketLength_t; -@p4runtime_translation("p4.org/pna/v1/MulticastInstance_t", 16) -type MulticastInstanceUint_t MulticastInstance_t; -@p4runtime_translation("p4.org/pna/v1/Timestamp_t", 64) -type TimestampUint_t Timestamp_t; -@p4runtime_translation("p4.org/pna/v1/FlowId_t", 32) -type FlowIdUint_t FlowId_t; -@p4runtime_translation("p4.org/pna/v1/ExpireTimeProfileId_t", 8) -type ExpireTimeProfileIdUint_t ExpireTimeProfileId_t; - -@p4runtime_translation("p4.org/pna/v1/SecurityAssocId_t", 64) -type SecurityAssocIdUint_t SecurityAssocId_t; - -typedef error ParserError_t; - -const InterfaceId_t PNA_PORT_CPU = (PortId_t) unspecified; - -const MirrorSessionId_t PNA_MIRROR_SESSION_TO_CPU = (MirrorSessiontId_t) unspecified; -// END:Type_defns -#endif // #ifndef PNA_EXAMPLE_CORE_TYPES +#include <_internal/pna/dev/types_core.p4> +#include <_internal/pna/dev/types_defns.p4> +#include <_internal/pna/dev/types_defns2.p4> +#include <_internal/pna/dev/funcs_int_to_header.p4> +#include <_internal/pna/dev/types_misc.p4> -// BEGIN:Type_defns2 +#include <_internal/pna/dev/extern_hash.p4> +#include <_internal/pna/dev/extern_checksum.p4> -/* Note: All of the types with `InHeader` in their name are intended - * only to carry values of the corresponding types in packet headers - * between a PNA device and the P4Runtime Server software that manages - * it. - * - * The widths are intended to be at least as large as any PNA device - * will ever have for that type. Thus these types may also be useful - * to define packet headers that are sent directly between a PNA - * device and other devices, without going through P4Runtime Server - * software (e.g. this could be useful for sending packets to a - * controller or data collection system using higher packet rates than - * the P4Runtime Server can handle). If used for this purpose, there - * is no requirement that the PNA data plane _automatically_ perform - * the numerical translation of these types that would occur if the - * header went through the P4Runtime Server. Any such desired - * translation is up to the author of the P4 program to perform with - * explicit code. - * - * All widths must be a multiple of 8, so that any subset of these - * fields may be used in a single P4 header definition, even on P4 - * implementations that restrict headers to contain fields with a - * total length that is a multiple of 8 bits. */ - -/* See the comments near the definition of PortIdUint_t for why these - * typedef definitions exist. */ -typedef bit<32> PortIdInHeaderUint_t; -typedef bit<32> InterfaceIdInHeaderUint_t; -typedef bit<32> MulticastGroupInHeaderUint_t; -typedef bit<16> MirrorSessionIdInHeaderUint_t; -typedef bit<8> MirrorSlotIdInHeaderUint_t; -typedef bit<8> ClassOfServiceInHeaderUint_t; -typedef bit<16> PacketLengthInHeaderUint_t; -typedef bit<16> MulticastInstanceInHeaderUint_t; -typedef bit<64> TimestampInHeaderUint_t; -typedef bit<32> FlowIdInHeaderUint_t; -typedef bit<8> ExpireTimeProfileIdInHeaderUint_t; - -typedef bit<32> SecurityAssocIdInHeaderUint_t; - -@p4runtime_translation("p4.org/pna/v1/PortIdInHeader_t", 32) -type PortIdInHeaderUint_t PortIdInHeader_t; -@p4runtime_translation("p4.org/pna/v1/InterfaceIdInHeader_t", 32) -type InterfaceIdInHeaderUint_t InterfaceIdInHeader_t; -@p4runtime_translation("p4.org/pna/v1/MulticastGroupInHeader_t", 32) -type MulticastGroupInHeaderUint_t MulticastGroupInHeader_t; -@p4runtime_translation("p4.org/pna/v1/MirrorSessionIdInHeader_t", 16) -type MirrorSessionIdInHeaderUint_t MirrorSessionIdInHeader_t; -@p4runtime_translation("p4.org/pna/v1/MirrorSlotIdInHeader_t", 8) -type MirrorSlotIdInHeaderUint_t MirrorSlotIdInHeader_t; -@p4runtime_translation("p4.org/pna/v1/ClassOfServiceInHeader_t", 8) -type ClassOfServiceInHeaderUint_t ClassOfServiceInHeader_t; -@p4runtime_translation("p4.org/pna/v1/PacketLengthInHeader_t", 16) -type PacketLengthInHeaderUint_t PacketLengthInHeader_t; -@p4runtime_translation("p4.org/pna/v1/MulticastInstanceInHeader_t", 16) -type MulticastInstanceInHeaderUint_t MulticastInstanceInHeader_t; -@p4runtime_translation("p4.org/pna/v1/TimestampInHeader_t", 64) -type TimestampInHeaderUint_t TimestampInHeader_t; -@p4runtime_translation("p4.org/pna/v1/FlowIdInHeader_t", 32) -type FlowIdInHeaderUint_t FlowIdInHeader_t; -@p4runtime_translation("p4.org/pna/v1/ExpireTimeProfileIdInHeader_t", 8) -type ExpireTimeProfileIdInHeaderUint_t ExpireTimeProfileIdInHeader_t; - -@p4runtime_translation("p4.org/pna/v1/SecurityAssocIdInHeader_t", 64) -type SecurityAssocIdInHeaderUint_t SecurityAssocIdInHeader_t; -// END:Type_defns2 - -/* The _int_to_header functions were written to convert a value of - * type _t (a value INTernal to the data path) to a value of - * type InHeader_t inside a header that will be sent to the CPU - * port. - * - * The _header_to_int functions were written to convert values in the - * opposite direction, typically for assigning a value in a header - * received from the CPU port, to a value you wish to use in the rest - * of your code. - * - * The reason that three casts are needed is that each of the original - * and target types is declared via P4_16 'type', so without a cast - * they can only be assigned to values of that identical type. The - * first cast changes it from the original 'type' to a 'bit' value - * of the same bit width W1. The second cast changes its bit width, - * either prepending 0s if it becomes wider, or discarding the most - * significant bits if it becomes narrower. The third cast changes it - * from a 'bit' value to the final 'type', with the same width - * W2. */ - -PortId_t pna_PortId_header_to_int (in PortIdInHeader_t x) { - return (PortId_t) (PortIdUint_t) (PortIdInHeaderUint_t) x; -} -InterfaceId_t pna_InterfaceId_header_to_int (in InterfaceIdInHeader_t x) { - return (InterfaceId_t) (InterfaceIdUint_t) (InterfaceIdInHeaderUint_t) x; -} -MulticastGroup_t pna_MulticastGroup_header_to_int (in MulticastGroupInHeader_t x) { - return (MulticastGroup_t) (MulticastGroupUint_t) (MulticastGroupInHeaderUint_t) x; -} -MirrorSessionId_t pna_MirrorSessionId_header_to_int (in MirrorSessionIdInHeader_t x) { - return (MirrorSessionId_t) (MirrorSessionIdUint_t) (MirrorSessionIdInHeaderUint_t) x; -} -ClassOfService_t pna_ClassOfService_header_to_int (in ClassOfServiceInHeader_t x) { - return (ClassOfService_t) (ClassOfServiceUint_t) (ClassOfServiceInHeaderUint_t) x; -} -PacketLength_t pna_PacketLength_header_to_int (in PacketLengthInHeader_t x) { - return (PacketLength_t) (PacketLengthUint_t) (PacketLengthInHeaderUint_t) x; -} -MulticastInstance_t pna_MulticastInstance_header_to_int (in MulticastInstanceInHeader_t x) { - return (MulticastInstance_t) (MulticastInstanceUint_t) (MulticastInstanceInHeaderUint_t) x; -} -Timestamp_t pna_Timestamp_header_to_int (in TimestampInHeader_t x) { - return (Timestamp_t) (TimestampUint_t) (TimestampInHeaderUint_t) x; -} -FlowId_t pna_FlowId_header_to_int (in FlowIdInHeader_t x) { - return (FlowId_t) (FlowIdUint_t) (FlowIdInHeaderUint_t) x; -} -ExpireTimeProfileId_t pna_ExpireTimeProfileId_header_to_int (in ExpireTimeProfileIdInHeader_t x) { - return (ExpireTimeProfileId_t) (ExpireTimeProfileIdUint_t) (ExpireTimeProfileIdInHeaderUint_t) x; -} - -PortIdInHeader_t pna_PortId_int_to_header (in PortId_t x) { - return (PortIdInHeader_t) (PortIdInHeaderUint_t) (PortIdUint_t) x; -} -InterfaceIdInHeader_t pna_InterfaceId_int_to_header (in InterfaceId_t x) { - return (InterfaceIdInHeader_t) (InterfaceIdInHeaderUint_t) (InterfaceIdUint_t) x; -} -MulticastGroupInHeader_t pna_MulticastGroup_int_to_header (in MulticastGroup_t x) { - return (MulticastGroupInHeader_t) (MulticastGroupInHeaderUint_t) (MulticastGroupUint_t) x; -} -MirrorSessionIdInHeader_t pna_MirrorSessionId_int_to_header (in MirrorSessionId_t x) { - return (MirrorSessionIdInHeader_t) (MirrorSessionIdInHeaderUint_t) (MirrorSessionIdUint_t) x; -} -ClassOfServiceInHeader_t pna_ClassOfService_int_to_header (in ClassOfService_t x) { - return (ClassOfServiceInHeader_t) (ClassOfServiceInHeaderUint_t) (ClassOfServiceUint_t) x; -} -PacketLengthInHeader_t pna_PacketLength_int_to_header (in PacketLength_t x) { - return (PacketLengthInHeader_t) (PacketLengthInHeaderUint_t) (PacketLengthUint_t) x; -} -MulticastInstanceInHeader_t pna_MulticastInstance_int_to_header (in MulticastInstance_t x) { - return (MulticastInstanceInHeader_t) (MulticastInstanceInHeaderUint_t) (MulticastInstanceUint_t) x; -} -TimestampInHeader_t pna_Timestamp_int_to_header (in Timestamp_t x) { - return (TimestampInHeader_t) (TimestampInHeaderUint_t) (TimestampUint_t) x; -} -FlowIdInHeader_t pna_FlowId_int_to_header (in FlowId_t x) { - return (FlowIdInHeader_t) (FlowIdInHeaderUint_t) (FlowIdUint_t) x; -} -ExpireTimeProfileIdInHeader_t pna_ExpireTimeProfileId_int_to_header (in ExpireTimeProfileId_t x) { - return (ExpireTimeProfileIdInHeader_t) (ExpireTimeProfileIdInHeaderUint_t) (ExpireTimeProfileIdUint_t) x; -} - -// BEGIN:enum_PNA_IdleTimeout_t -/// Supported values for the pna_idle_timeout table property -enum PNA_IdleTimeout_t { - NO_TIMEOUT, - NOTIFY_CONTROL, - AUTO_DELETE -}; -// END:enum_PNA_IdleTimeout_t - -// BEGIN:Match_kinds -match_kind { - range, /// Used to represent min..max intervals - selector, /// Used for dynamic action selection via the ActionSelector extern - optional /// Either an exact match, or a wildcard matching any value for the entire field -} -// END:Match_kinds - -// BEGIN:Hash_algorithms -enum PNA_HashAlgorithm_t { - IDENTITY, - CRC32, - CRC32_CUSTOM, - CRC16, - CRC16_CUSTOM, - ONES_COMPLEMENT16, /// One's complement 16-bit sum used for IPv4 headers, - /// TCP, and UDP. - TARGET_DEFAULT /// target implementation defined -} -// END:Hash_algorithms - -// BEGIN:Hash_extern -extern Hash { - /// Constructor - Hash(PNA_HashAlgorithm_t algo); - - /// Compute the hash for data. - /// @param data The data over which to calculate the hash. - /// @return The hash value. - O get_hash(in D data); - - /// Compute the hash for data, with modulo by max, then add base. - /// @param base Minimum return value. - /// @param data The data over which to calculate the hash. - /// @param max The hash value is divided by max to get modulo. - /// An implementation may limit the largest value supported, - /// e.g. to a value like 32, or 256, and may also only - /// support powers of 2 for this value. P4 developers should - /// limit their choice to such values if they wish to - /// maximize portability. - /// @return (base + (h % max)) where h is the hash value. - O get_hash(in T base, in D data, in T max); -} -// END:Hash_extern - -// BEGIN:Checksum_extern -extern Checksum { - /// Constructor - Checksum(PNA_HashAlgorithm_t hash); - - /// Reset internal state and prepare unit for computation. - /// Every instance of a Checksum object is automatically initialized as - /// if clear() had been called on it. This initialization happens every - /// time the object is instantiated, that is, whenever the parser or control - /// containing the Checksum object are applied. - /// All state maintained by the Checksum object is independent per packet. - void clear(); - - /// Add data to checksum - void update(in T data); - - /// Get checksum for data added (and not removed) since last clear - W get(); -} -// END:Checksum_extern - -// BEGIN:InternetChecksum_extern -// Checksum based on `ONES_COMPLEMENT16` algorithm used in IPv4, TCP, and UDP. -// Supports incremental updating via `subtract` method. -// See IETF RFC 1624. -extern InternetChecksum { - /// Constructor - InternetChecksum(); - - /// Reset internal state and prepare unit for computation. Every - /// instance of an InternetChecksum object is automatically - /// initialized as if clear() had been called on it, once for each - /// time the parser or control it is instantiated within is - /// executed. All state maintained by it is independent per packet. - void clear(); - - /// Add data to checksum. data must be a multiple of 16 bits long. - void add(in T data); - - /// Subtract data from existing checksum. data must be a multiple of - /// 16 bits long. - void subtract(in T data); - - /// Get checksum for data added (and not removed) since last clear - bit<16> get(); - - /// Get current state of checksum computation. The return value is - /// only intended to be used for a future call to the set_state - /// method. - bit<16> get_state(); - - /// Restore the state of the InternetChecksum instance to one - /// returned from an earlier call to the get_state method. This - /// state could have been returned from the same instance of the - /// InternetChecksum extern, or a different one. - void set_state(in bit<16> checksum_state); -} -// END:InternetChecksum_extern +// #include <_internal/pna/dev/extern_counter.p4> // BEGIN:CounterType_defn enum PNA_CounterType_t { @@ -464,6 +72,8 @@ struct tc_ControlPath_DirectCounter { @tc_data W bytes; } +// #include <_internal/pna/dev/extern_meter.p4> + // BEGIN:MeterType_defn enum PNA_MeterType_t { PACKETS, @@ -502,6 +112,8 @@ extern DirectMeter { } // END:DirectMeter_extern +// #include <_internal/pna/dev/extern_register.p4> + // BEGIN:Register_extern extern Register { /// Instantiate an array of registers. The initial value is @@ -521,373 +133,12 @@ struct tc_ControlPath_Register { @tc_data T a_value; } -// BEGIN:Random_extern -extern Random { - - /// Return a random value in the range [min, max], inclusive. - /// Implementations are allowed to support only ranges where (max - - /// min + 1) is a power of 2. P4 developers should limit their - /// arguments to such values if they wish to maximize portability. - - Random(T min, T max); - T read(); -} -// END:Random_extern - -// BEGIN:ActionProfile_extern -extern ActionProfile { - /// Construct an action profile of 'size' entries - ActionProfile(bit<32> size); -} -// END:ActionProfile_extern - -// BEGIN:ActionSelector_extern -extern ActionSelector { - /// Construct an action selector of 'size' entries - /// @param algo hash algorithm to select a member in a group - /// @param size number of entries in the action selector - /// @param outputWidth size of the key - ActionSelector(PNA_HashAlgorithm_t algo, bit<32> size, bit<32> outputWidth); -} -// END:ActionSelector_extern - -// BEGIN:Digest_extern -extern Digest { - Digest(); /// define a digest stream to the control plane - void pack(in T data); /// emit data into the stream -} -// END:Digest_extern - -enum PNA_Source_t { - FROM_HOST, - FROM_NET -} - -// BEGIN:Metadata_types - -struct pna_main_parser_input_metadata_t { - // common fields initialized for all packets that are input to main - // parser, regardless of direction. - bool recirculated; - // If this packet has FROM_NET source, input_port contains - // the id of the network port on which the packet arrived. - // If this packet has FROM_HOST source, input_port contains - // the id of the vport from which the packet came - PortId_t input_port; // network/host port id -} - -// is_host_port(p) returns true if p is a host port, otherwise false. -extern bool is_host_port (in PortId_t p); - -// is_net_port(p) returns true if p is a network port, otherwise -// false. -extern bool is_net_port (in PortId_t p); - -struct pna_main_input_metadata_t { - // common fields initialized for all packets that are input to main - // parser, regardless of direction. - bool recirculated; - Timestamp_t timestamp; - ParserError_t parser_error; - ClassOfService_t class_of_service; - // See comments for field input_port in struct - // pna_main_parser_input_metadata_t - PortId_t input_port; -} - -// BEGIN:Metadata_main_output -struct pna_main_output_metadata_t { - // common fields used by the architecture to decide what to do with - // the packet next, after the main parser, control, and deparser - // have finished executing one pass, regardless of the direction. - ClassOfService_t class_of_service; // 0 -} -// END:Metadata_main_output -// END:Metadata_types - -// The following extern functions are "forwarding" functions -- they -// all set the destination of the packet. Calling one of them -// overwrites and replaces the effect of any earlier call to any of -// the functions in this set. Only the last one executed will -// actually take effect for the packet. - -// + drop_packet -// + send_to_port - - -// drop_packet() - Cause the packet to be dropped when it finishes -// completing the main control. -// -// Invoking drop_packet() is supported only within the main control. - -extern void drop_packet(); - -// BEGIN:send_to_port -extern void send_to_port(in PortId_t dest_port); -// END:send_to_port - -// BEGIN:mirror_packet -extern void mirror_packet(in MirrorSlotId_t mirror_slot_id, - in MirrorSessionId_t mirror_session_id); -// END:mirror_packet - -// TBD: Does it make sense to have a data plane add of a hit action -// that has in, out, or inout parameters? -// -// TBD: Should we require the return value? Can most targets -// implement it? If not, consider having two separate variants of -// add_entry, one with no return value (i.e. type void). Such a -// variant of add_entry seems difficult to use correctly, if it is -// possible for entries to fail to be added. - -// BEGIN:add_entry_extern_function -// The bit width of this type is allowed to be different for different -// target devices. It must be at least a 1-bit wide type. - -typedef bit<1> AddEntryErrorStatus_t; - -const AddEntryErrorStatus_t ADD_ENTRY_SUCCESS = 0; -const AddEntryErrorStatus_t ADD_ENTRY_NOT_DONE = 1; - -// Targets may define target-specific non-0 constants of type -// AddEntryErrorStatus_t if they wish. - -// The add_entry() extern function causes an entry, i.e. a key and its -// corresponding action and action parameter values, to be added to a -// table from the data plane, i.e. without the control plane having to -// take any action at all to cause the table entry to be added. -// -// The key of the new entry added will always be the same as the key -// that was just looked up in the table, and experienced a miss. -// -// `action_name` is the name of an action that must satisfy these -// restrictions: -// + It must be an action that is in the list specified as the -// `actions` property of the table. -// + It must be possible for this action to be the action of an entry -// added to the table, e.g. it is an error if the action has the -// annotation `@defaultonly`. -// + The action to be added must not itself contain a call to -// add_entry(), or anything else that is not supported in a table's -// "hit action". -// -// Type T must be a struct type whose field names have the same name -// as the parameters of the action being added, in the same order, and -// have the same type as the corresponding action parameters. -// -// `action_params` will become the action parameters of the new entry -// to be added. -// -// `expire_time_profile_id` is the initial expire time profile id of -// the entry added. -// -// The return value will be ADD_ENTRY_SUCCESS if the entry was -// successfully added, otherwise it will be some other value not equal -// to ADD_ENTRY_SUCCESS. Targets are allowed to define only one -// failure return value, or several if they wish to provide more -// detail on the reason for the failure to add the entry. -// -// It is NOT defined by PNA, and need not be supported by PNA -// implementations, to call add_entry() within an action that is added -// as an entry of a table, i.e. as a "hit action". It is only defined -// if called within an action that is the default_action, i.e. a "miss -// action" of a table. -// -// For tables with `add_on_miss = true`, some PNA implementations -// might only support `default_action` with the `const` qualifier. -// However, if a PNA implementation can support run-time modifiable -// default actions for such a table, some of which call add_entry() -// and some of which do not, the behavior of such an implementation is -// defined by PNA, and this may be a useful feature. - -extern AddEntryErrorStatus_t add_entry( - string action_name, - in T action_params, - in ExpireTimeProfileId_t expire_time_profile_id); -// END:add_entry_extern_function - -// The following call to add_entry_if(): -// -// add_entry_if(expr, action_name, action_params, expire_time_profile_id); -// -// has exactly the same behavior as the following expression: -// -// (expr) ? add_entry(action_name, action_params, expire_time_profile_id) -// : ADD_ENTRY_NOT_DONE; -// -// and it has the same restrictions on where it can appear in a P4 -// program as that equivalent code. -// -// Rationale: At the time PNA was being designed in 2022, there were -// P4 targets, including the BMv2 software switch in the repository -// https://github.com/p4lang/behavioral-model, that did not fully -// support `if` statements within P4 actions. add_entry_if() enables -// writing P4 code without `if` statements within P4 actions that -// would otherwise require an `if` statement to express the desired -// behavior. Admittedly, this is a work-around for targets with -// limited support for `if` statements within P4 actions. See -// https://github.com/p4lang/pna/issues/63 for more details. - -extern AddEntryErrorStatus_t add_entry_if( - in bool do_add_entry, - string action_name, - in T action_params, - in ExpireTimeProfileId_t expire_time_profile_id); - -extern FlowId_t allocate_flow_id(); - - -// set_entry_expire_time() may only be called from within an action of -// a table with property 'pna_idle_timeout' having a value of -// `NOTIFY_CONTROL` or `AUTO_DELETE`. - -// Calling it causes the expiration time profile id of the matched -// entry to become equal to expire_time_profile_id. - -// It _also_ behaves as if restart_expire_timer() was called. - -extern void set_entry_expire_time( - in ExpireTimeProfileId_t expire_time_profile_id); - - -// restart_expire_timer() may only be called from within an action of -// a table with property 'pna_idle_timeout' having a value of -// `NOTIFY_CONTROL` or `AUTO_DELETE`. - -// Calling it causes the dynamic expiration timer of the entry to be -// reset, so that the entry will remain active from the now until that -// time in the future. - -// TODO: Note that there are targets that support a table with -// property pna_idle_timeout equal to `NOTIFY_CONTROL` or -// `AUTO_DELETE` such that matching an entry _does not_ cause this -// side effect to occur, i.e. it is possible to match an entry and -// _not_ do what `restart_expire_timer()` does. We should document -// this explicitly as common for PNA devices, if that is agreed upon. -// Andy is pretty sure that PSA devices were not expected to have this -// option. - -// Note that for the PSA architecture with psa_idle_timeout = -// PSA_IdleTimeout_t.NOTIFY_CONTROL, I believe there was an implicit -// assumption that _every_ time a table entry was matched, the target -// behaved as if restart_expire_timer() was called, but there was no -// such extern function defined by PSA. - -// The proposal for PNA is that it is possible to match an entry, but -// _not_ call restart_expire_timer(), and this will cause the data -// plane _not_ to restart the table entry's expiration time. That is, -// the expiration time of the entry will continue to be the same as -// before it was matched. - -extern void restart_expire_timer(); - -// The effect of this call: -// -// update_expire_info(a, b, c) -// -// is exactly the same as the effect of the following code: -// -// if (a) { -// if (b) { -// set_entry_expire_time(c); -// } else { -// restart_expire_timer(); -// } -// } - -extern void update_expire_info( - in bool update_aging_info, - in bool update_expire_time, - in ExpireTimeProfileId_t expire_time_profile_id); - - -// Set the expire time of the matched entry in the table to the value -// specified in the parameter expire_time_profile_id, if condition -// in the first parameter evaluates to true. Otherwise, the function -// has no effect. -// -// @param condition The boolean expression to evaluate to determine -// if the expire time will be set. -// @param expire_time_profile_id -// The expire time to set for the matched entry, -// if the data and value parameters are equal. -// -// Examples: -// set_entry_expire_time_if(hdr.tcp.flags == TCP_FLG_SYN && -// meta.direction == OUTBOUND, -// tcp_connection_start_time_profile_id); -// set_entry_expire_time_if(hdr.tcp.flags == TCP_FLG_ACK, -// tcp_connection_continuation_time_protile_id); -// set_entry_expire_time_if(hdr.tcp.flags == TCP_FLG_FIN, -// tcp_connection_close_time_profile_id); - -extern void set_entry_expire_time_if( - in bool condition, - in ExpireTimeProfileId_t expire_time_profile_id); - - -// SelectByDirection is a simple pure function that behaves exactly as -// the P4_16 function definition given in comments below. It is an -// extern function to ensure that the front/mid end of the p4c -// compiler leaves occurrences of it as is, visible to target-specific -// compiler back end code, so targets have all information needed to -// optimize it as they wish. - -// One example of its use is in table key expressions, for tables -// where one wishes to swap IP source/destination addresses for -// packets processed in the different directions. - -/* -T SelectByDirection( - in bool is_network_port, - in T from_net_value, - in T from_host_value) -{ - if (is_network_port) { - return from_net_value; - } else { - return from_host_value; - } -} -*/ - -// A typical call would look like this example: -// -// SelectByDirection(is_net_port(istd.input_port), hdr.ipv4.src_addr, -// hdr.ipv4.dst_addr) - -@pure -extern T SelectByDirection( - in bool is_network_port, - in T from_net_value, - in T from_host_value); - - - - -// BEGIN:Programmable_blocks -parser MainParserT( - packet_in pkt, - out MH main_hdr, - inout MM main_user_meta, - in pna_main_parser_input_metadata_t istd); - -control MainControlT( - inout MH main_hdr, - inout MM main_user_meta, - in pna_main_input_metadata_t istd, - inout pna_main_output_metadata_t ostd); - -control MainDeparserT( - packet_out pkt, - inout MH main_hdr, - in MM main_user_meta, - in pna_main_output_metadata_t ostd); +#include <_internal/pna/dev/extern_random.p4> +#include <_internal/pna/dev/extern_action.p4> +#include <_internal/pna/dev/extern_digest.p4> -package PNA_NIC( - MainParserT main_parser, - MainControlT main_control, - MainDeparserT main_deparser); -// END:Programmable_blocks +#include <_internal/pna/dev/types_metadata.p4> +#include <_internal/pna/dev/extern_funcs.p4> +#include <_internal/pna/dev/blocks.p4> #endif // __PNA_P4__ diff --git a/testdata/p4_16_dpdk_errors_outputs/pna-example-ipsec-err3.p4-error b/testdata/p4_16_dpdk_errors_outputs/pna-example-ipsec-err3.p4-error index 4a40563dd7..efeb066d9e 100644 --- a/testdata/p4_16_dpdk_errors_outputs/pna-example-ipsec-err3.p4-error +++ b/testdata/p4_16_dpdk_errors_outputs/pna-example-ipsec-err3.p4-error @@ -2,11 +2,11 @@ pna-example-ipsec-err3.p4(144): [--Werror=type-error] error: 'ipsec.set_sa_index ipsec.set_sa_index, bit<8>>(sa_index); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- Actual error: -pna.p4(524): set_sa_index: 1 type parameters expected, but 2 type arguments supplied +pna.p4(192): set_sa_index: 1 type parameters expected, but 2 type arguments supplied void set_sa_index(in T sa_index); ^^^^^^^^^^^^ ---- Originating from: -pna.p4(524): Function type 'set_sa_index' does not match invocation type '' +pna.p4(192): Function type 'set_sa_index' does not match invocation type '' void set_sa_index(in T sa_index); ^^^^^^^^^^^^ pna-example-ipsec-err3.p4(144) diff --git a/testdata/p4_16_pna_errors_outputs/pna-dpdk-direct-counter-err-3.p4-error b/testdata/p4_16_pna_errors_outputs/pna-dpdk-direct-counter-err-3.p4-error index 17ff5d758b..fc1407579e 100644 --- a/testdata/p4_16_pna_errors_outputs/pna-dpdk-direct-counter-err-3.p4-error +++ b/testdata/p4_16_pna_errors_outputs/pna-dpdk-direct-counter-err-3.p4-error @@ -1,6 +1,6 @@ -pna.p4(401): [--Werror=unexpected] error: count method of per_prefix_pkt_bytes_count extern can only be invoked from within action of ownertable +pna.p4(113): [--Werror=unexpected] error: count method of per_prefix_pkt_bytes_count extern can only be invoked from within action of ownertable void count(in bit<32> pkt_len); ^^^^^ -pna.p4(401): [--Werror=unexpected] error: count method of per_prefix_bytes_count extern can only be invoked from within action of ownertable +pna.p4(113): [--Werror=unexpected] error: count method of per_prefix_bytes_count extern can only be invoked from within action of ownertable void count(in bit<32> pkt_len); ^^^^^ diff --git a/testdata/p4_16_pna_errors_outputs/pna-dpdk-direct-meter-err-4.p4-error b/testdata/p4_16_pna_errors_outputs/pna-dpdk-direct-meter-err-4.p4-error index e3d200c83c..eaf5960a11 100644 --- a/testdata/p4_16_pna_errors_outputs/pna-dpdk-direct-meter-err-4.p4-error +++ b/testdata/p4_16_pna_errors_outputs/pna-dpdk-direct-meter-err-4.p4-error @@ -1,24 +1,24 @@ pna-dpdk-direct-meter-err-4.p4(111): [--Werror=type-error] error: meter0.execute: extern DirectMeter does not have method matching this call out1 = meter0.execute(color_in, 32w1024); ^^^^^^^^^^^^^^ -pna.p4(444) +pna.p4(158) extern DirectMeter { ^^^^^^^^^^^ pna-dpdk-direct-meter-err-4.p4(113): [--Werror=type-error] error: meter1.execute: extern DirectMeter does not have method matching this call color_out = meter1.execute(color_in, 32w1024); ^^^^^^^^^^^^^^ -pna.p4(444) +pna.p4(158) extern DirectMeter { ^^^^^^^^^^^ pna-dpdk-direct-meter-err-4.p4(119): [--Werror=type-error] error: meter0.execute: extern DirectMeter does not have method matching this call out1 = meter0.execute(color_in, 32w1024); ^^^^^^^^^^^^^^ -pna.p4(444) +pna.p4(158) extern DirectMeter { ^^^^^^^^^^^ pna-dpdk-direct-meter-err-4.p4(148): [--Werror=type-error] error: meter1.execute: extern DirectMeter does not have method matching this call color_out = meter1.execute(color_in, 32w1024); ^^^^^^^^^^^^^^ -pna.p4(444) +pna.p4(158) extern DirectMeter { ^^^^^^^^^^^ diff --git a/testdata/p4_16_pna_errors_outputs/pna-example-mirror-packet-error2.p4-error b/testdata/p4_16_pna_errors_outputs/pna-example-mirror-packet-error2.p4-error index 37ba9cef97..b7f011bce3 100644 --- a/testdata/p4_16_pna_errors_outputs/pna-example-mirror-packet-error2.p4-error +++ b/testdata/p4_16_pna_errors_outputs/pna-example-mirror-packet-error2.p4-error @@ -5,11 +5,11 @@ pna-example-mirror-packet-error2.p4(83): [--Werror=type-error] error: 'mirror_pa pna-example-mirror-packet-error2.p4(83): mirror_slot: argument used for directionless parameter 'mirror_slot_id' must be a compile-time constant mirror_packet(mirror_slot, mirror_session); ^^^^^^^^^^^ -pna.p4(582) +pna.p4(121) extern void mirror_packet(MirrorSlotId_t mirror_slot_id, ^^^^^^^^^^^^^^ ---- Originating from: -pna.p4(582): Function type 'mirror_packet' does not match invocation type '' +pna.p4(121): Function type 'mirror_packet' does not match invocation type '' extern void mirror_packet(MirrorSlotId_t mirror_slot_id, ^^^^^^^^^^^^^ pna-example-mirror-packet-error2.p4(83) @@ -22,11 +22,11 @@ pna-example-mirror-packet-error2.p4(88): [--Werror=type-error] error: 'mirror_pa pna-example-mirror-packet-error2.p4(88): mirror_slot: argument used for directionless parameter 'mirror_slot_id' must be a compile-time constant mirror_packet(mirror_slot, mirror_session); ^^^^^^^^^^^ -pna.p4(582) +pna.p4(121) extern void mirror_packet(MirrorSlotId_t mirror_slot_id, ^^^^^^^^^^^^^^ ---- Originating from: -pna.p4(582): Function type 'mirror_packet' does not match invocation type '' +pna.p4(121): Function type 'mirror_packet' does not match invocation type '' extern void mirror_packet(MirrorSlotId_t mirror_slot_id, ^^^^^^^^^^^^^ pna-example-mirror-packet-error2.p4(88) diff --git a/testdata/p4_16_pna_errors_outputs/pna-example-mirror-packet-error3.p4-error b/testdata/p4_16_pna_errors_outputs/pna-example-mirror-packet-error3.p4-error index 6d3cdf54c4..23c1db8dcc 100644 --- a/testdata/p4_16_pna_errors_outputs/pna-example-mirror-packet-error3.p4-error +++ b/testdata/p4_16_pna_errors_outputs/pna-example-mirror-packet-error3.p4-error @@ -2,11 +2,11 @@ pna-example-mirror-packet-error3.p4(79): [--Werror=type-error] error: 'mirror_pa mirror_packet(MIRROR_SLOT_ID); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- Actual error: -pna.p4(583): mirror_session_id: No argument supplied for parameter +pna.p4(122): mirror_session_id: No argument supplied for parameter MirrorSessionId_t mirror_session_id); ^^^^^^^^^^^^^^^^^ ---- Originating from: -pna.p4(582): Function type 'mirror_packet' does not match invocation type '' +pna.p4(121): Function type 'mirror_packet' does not match invocation type '' extern void mirror_packet(MirrorSlotId_t mirror_slot_id, ^^^^^^^^^^^^^ pna-example-mirror-packet-error3.p4(79)