diff --git a/backends/dpdk/DpdkXfail.cmake b/backends/dpdk/DpdkXfail.cmake index cf485f0549..e42c108b5e 100644 --- a/backends/dpdk/DpdkXfail.cmake +++ b/backends/dpdk/DpdkXfail.cmake @@ -108,3 +108,10 @@ p4c_add_xfail_reason("dpdk" testdata/p4_16_samples/psa-dpdk-struct-field.p4 testdata/p4_16_samples/psa-example-register2-bmv2.p4 ) + +p4c_add_xfail_reason("dpdk" + "must only be called from within an action" + testdata/p4_16_samples/pna-add-on-miss-err.p4 + testdata/p4_16_samples/pna-example-tcp-connection-tracking-err-1.p4 + testdata/p4_16_samples/pna-example-tcp-connection-tracking-err.p4 + ) diff --git a/backends/dpdk/backend.cpp b/backends/dpdk/backend.cpp index cef20e3394..7fb7ebda88 100644 --- a/backends/dpdk/backend.cpp +++ b/backends/dpdk/backend.cpp @@ -72,6 +72,7 @@ void DpdkBackend::convert(const IR::ToplevelBlock *tlb) { new ConvertActionSelectorAndProfile(refMap, typeMap, &structure), new CollectTableInfo(&structure), new CollectAddOnMissTable(refMap, typeMap, &structure), + new ValidateAddOnMissExterns(refMap, typeMap, &structure), new P4::MoveDeclarations(), // Move all local declarations to the beginning new CollectProgramStructure(refMap, typeMap, &structure), new CollectMetadataHeaderInfo(&structure), diff --git a/backends/dpdk/dpdk.def b/backends/dpdk/dpdk.def index b38770450a..7b8f7ebd6b 100644 --- a/backends/dpdk/dpdk.def +++ b/backends/dpdk/dpdk.def @@ -104,7 +104,8 @@ class DpdkApplyStatement : DpdkAsmStatement, IDPDKNode { class DpdkLearnStatement : DpdkAsmStatement, IDPDKNode { cstring action; - optional Expression argument; + Expression timeout; + NullOK optional Expression argument; std::ostream& toSpec(std::ostream& out) const override; } @@ -450,6 +451,12 @@ class DpdkReturnStatement : DpdkAsmStatement, IDPDKNode { #nodbprint } +class DpdkRearmStatement : DpdkAsmStatement, IDPDKNode { + NullOK optional Expression timeout; + std::ostream& toSpec(std::ostream& out) const override; +#nodbprint +} + class DpdkRecirculateStatement : DpdkAsmStatement, IDPDKNode { std::ostream& toSpec(std::ostream& out) const override; #nodbprint diff --git a/backends/dpdk/dpdkArch.cpp b/backends/dpdk/dpdkArch.cpp index f8952e1d75..70c7c13f5b 100644 --- a/backends/dpdk/dpdkArch.cpp +++ b/backends/dpdk/dpdkArch.cpp @@ -2239,6 +2239,12 @@ void CollectAddOnMissTable::postorder(const IR::P4Table* t) { default_action); } } + if (use_add_on_miss) { + for (auto action : t->getActionList()->actionList) { + auto action_decl = refMap->getDeclaration(action->getPath())->to(); + structure->learner_action_table.emplace(action_decl->externalName(), t); + } + } } void CollectAddOnMissTable::postorder(const IR::MethodCallStatement *mcs) { @@ -2255,7 +2261,8 @@ void CollectAddOnMissTable::postorder(const IR::MethodCallStatement *mcs) { BUG_CHECK(ctxt != nullptr, "%1%: add_entry extern can only be used in an action", mcs); // assuming checking on number of arguments is already performed in frontend. - BUG_CHECK(mce->arguments->size() == 2, "%1%: expected two arguments in add_entry extern", mcs); + BUG_CHECK(mce->arguments->size() == 3, + "%1%: expected 3 arguments in add_entry extern", mcs); auto action = mce->arguments->at(0); // assuming syntax check is already performed earlier auto action_name = action->expression->to()->value; @@ -2263,6 +2270,73 @@ void CollectAddOnMissTable::postorder(const IR::MethodCallStatement *mcs) { return; } +void ValidateAddOnMissExterns::postorder(const IR::MethodCallStatement *mcs) { + bool isValidExternCall = false; + cstring propName = ""; + auto mce = mcs->methodCall; + auto mi = P4::MethodInstance::resolve(mce, refMap, typeMap); + if (!mi->is()) { + return; + } + auto func = mi->to(); + auto externFuncName = func->method->name; + if (externFuncName != "restart_expire_timer" && externFuncName != "set_entry_expire_time" && + externFuncName != "add_entry") + return; + auto act = findOrigCtxt(); + BUG_CHECK(act != nullptr, "%1%: %2% extern can only be used in an action", mcs, externFuncName); + auto tbl = ::get(structure->learner_action_table,act->externalName()); + if (externFuncName == "restart_expire_timer" || externFuncName == "set_entry_expire_time") { + bool use_idle_timeout_with_auto_delete = false; + if (tbl) { + auto idle_timeout_with_auto_delete = + tbl->properties->getProperty("idle_timeout_with_auto_delete"); + if (idle_timeout_with_auto_delete != nullptr) { + propName = "idle_timeout_with_auto_delete"; + if (idle_timeout_with_auto_delete->value->is()) { + auto expr = + idle_timeout_with_auto_delete->value->to()->expression; + if (!expr->is()) { + ::error(ErrorType::ERR_UNEXPECTED, + "%1%: expected boolean for 'idle_timeout_with_auto_delete' property", + idle_timeout_with_auto_delete); + return; + } else { + use_idle_timeout_with_auto_delete = expr->to()->value; + if (use_idle_timeout_with_auto_delete) + isValidExternCall = true; + } + } + } + } + } else if (externFuncName == "add_entry") { + if (tbl) { + auto add_on_miss = tbl->properties->getProperty("add_on_miss"); + if (add_on_miss != nullptr) { + propName = "add_on_miss"; + if (add_on_miss->value->is()) { + auto expr = add_on_miss->value->to()->expression; + if (!expr->is()) { + ::error(ErrorType::ERR_UNEXPECTED, + "%1%: expected boolean for 'add_on_miss' property", add_on_miss); + return; + } else { + auto use_add_on_miss = expr->to()->value; + if (use_add_on_miss) + isValidExternCall = true; + } + } + } + } + } + if (!isValidExternCall) { + ::error(ErrorType::ERR_UNEXPECTED, + "%1% must only be called from within an action with '%2%'" + " property equal to true", externFuncName, propName); + } + return; +} + bool ElimHeaderCopy::isHeader(const IR::Expression* e) { auto type = typeMap->getType(e); if (type) diff --git a/backends/dpdk/dpdkArch.h b/backends/dpdk/dpdkArch.h index ea7171c985..6b52463b49 100644 --- a/backends/dpdk/dpdkArch.h +++ b/backends/dpdk/dpdkArch.h @@ -913,6 +913,19 @@ class CollectAddOnMissTable : public Inspector { void postorder(const IR::MethodCallStatement*) override; }; +class ValidateAddOnMissExterns : public Inspector { + P4::ReferenceMap* refMap; + P4::TypeMap* typeMap; + DpdkProgramStructure* structure; + + public: + ValidateAddOnMissExterns(P4::ReferenceMap *refMap, P4::TypeMap *typeMap, + DpdkProgramStructure* structure) : + refMap(refMap), typeMap(typeMap), structure(structure) {} + + void postorder(const IR::MethodCallStatement*) override; +}; + class CollectErrors : public Inspector { DpdkProgramStructure *structure; diff --git a/backends/dpdk/dpdkContext.cpp b/backends/dpdk/dpdkContext.cpp index 82cd8f9376..880291d642 100644 --- a/backends/dpdk/dpdkContext.cpp +++ b/backends/dpdk/dpdkContext.cpp @@ -56,6 +56,37 @@ void DpdkContextGenerator::CollectTablesAndSetAttributes() { tblAttr.size = size->asUnsigned(); auto hidden = tbl->annotations->getSingle(IR::Annotation::hiddenAnnotation); auto selector = tbl->properties->getProperty("selector"); + tblAttr.is_add_on_miss = false; + auto add_on_miss = tbl->properties->getProperty("add_on_miss"); + if (add_on_miss != nullptr) { + if (add_on_miss->value->is()) { + auto expr = add_on_miss->value->to()->expression; + if (!expr->is()) { + ::error(ErrorType::ERR_UNEXPECTED, + "%1%: expected boolean for 'add_on_miss' property", add_on_miss); + return; + } else { + tblAttr.is_add_on_miss = expr->to()->value; + } + } + } + auto idle_timeout_with_auto_delete = + tbl->properties->getProperty("idle_timeout_with_auto_delete"); + if (idle_timeout_with_auto_delete != nullptr) { + if (idle_timeout_with_auto_delete->value->is()) { + auto expr = + idle_timeout_with_auto_delete->value->to()->expression; + if (!expr->is()) { + ::error(ErrorType::ERR_UNEXPECTED, + "%1%: expected boolean for 'idle_timeout_with_auto_delete' property", + idle_timeout_with_auto_delete); + return; + } else { + tblAttr.idle_timeout_with_auto_delete = + expr->to()->value; + } + } + } if (hidden) { tblAttr.tableType = selector ? "selection" : "action"; tblAttr.isHidden = true; @@ -113,6 +144,8 @@ Util::JsonObject* DpdkContextGenerator::initTableCommonJson( tableJson->emplace("table_type", attr.tableType); tableJson->emplace("size", attr.size); tableJson->emplace("p4_hidden", attr.isHidden); + tableJson->emplace("add_on_miss", attr.is_add_on_miss); + tableJson->emplace("idle_timeout_with_auto_delete", attr.idle_timeout_with_auto_delete); return tableJson; } @@ -213,7 +246,8 @@ Util::JsonArray* paramJson, const cstring name, int dest_start, int dest_width) // This functions creates JSON object for match attributes of a table. Util::JsonObject* -DpdkContextGenerator::addMatchAttributes(const IR::P4Table*table, const cstring ctrlName) { +DpdkContextGenerator::addMatchAttributes(const IR::P4Table* table, const cstring ctrlName) { + auto tableAttr = ::get(tableAttrmap, table->name.originalName); auto* match_attributes = new Util::JsonObject(); auto* actFmtArray = new Util::JsonArray(); auto* stageTblArray = new Util::JsonArray(); @@ -236,16 +270,17 @@ DpdkContextGenerator::addMatchAttributes(const IR::P4Table*table, const cstring if (attr.params) { int index = 0; int position = 0; + int param_width = 8; // Minimum width for dpdk action params for (auto param : *(attr.params)) { - // TODO Handle other types of parameters if (param->type->is()) { - addImmediateField(immFldArray, param->name.originalName, - index/8, param->type->width_bits()); - index += param->type->width_bits(); - position++; - } else { + param_width = param->type->width_bits(); + } else if (!param->type->is()) { BUG("Unsupported parameter type %1%", param->type); } + addImmediateField(immFldArray, param->name.originalName, + index/8, param_width); + index += param_width; + position++; } } oneAction->emplace("immediate_fields",immFldArray); @@ -295,16 +330,17 @@ const IR::P4Table * table, const cstring controlName, bool isMatch) { if (attr.params) { int index = 0; int position = 0; + int param_width = 8; for (auto param : *(attr.params)) { - // TODO Handle other types of parameters if (param->type->is()) { - addActionParam(paramJson, param->name.originalName, - param->type->width_bits(), position, index/8); - position++; - index += param->type->width_bits(); - } else { + param_width = param->type->width_bits(); + } else if (!param->type->is()) { BUG("Unsupported parameter type %1%", param->type); } + addActionParam(paramJson, param->name.originalName, + param_width, position, index/8); + index += param_width; + position++; } } act->emplace("p4_parameters", paramJson); diff --git a/backends/dpdk/dpdkContext.h b/backends/dpdk/dpdkContext.h index 3759a75132..4e6cb87580 100644 --- a/backends/dpdk/dpdkContext.h +++ b/backends/dpdk/dpdkContext.h @@ -43,6 +43,8 @@ struct TableAttributes { Match table is a regular P4 table, selection table and action tables are compiler generated tables when psa_implementation is action_selector or action_profile */ cstring tableType; + bool is_add_on_miss; + bool idle_timeout_with_auto_delete; bool isHidden; unsigned size; cstring controlName; diff --git a/backends/dpdk/dpdkHelpers.cpp b/backends/dpdk/dpdkHelpers.cpp index 1654e64fd4..0c645f0ad9 100644 --- a/backends/dpdk/dpdkHelpers.cpp +++ b/backends/dpdk/dpdkHelpers.cpp @@ -768,15 +768,35 @@ bool ConvertStatementToDpdk::preorder(const IR::MethodCallStatement *s) { append_parser_name(parser, IR::ParserState::reject))); add_instr(new IR::DpdkLabelStatement(end_label)); } else if (a->method->name == "add_entry") { + auto args = a->expr->arguments; + auto argSize = args->size(); + if (argSize != 3) { + ::error(ErrorType::ERR_UNEXPECTED, "Unexpected number of arguments for %1%", + a->method->name); + return false; + } auto action = a->expr->arguments->at(0)->expression; auto action_name = action->to()->value; auto param = a->expr->arguments->at(1)->expression; + auto timeout_id = a->expr->arguments->at(2)->expression; + if (timeout_id->is()) { + BUG_CHECK(metadataStruct, "Metadata structure missing unexpectedly!"); + IR::ID tmo(refmap->newName("timeout_id")); + auto timeout = new IR::Member(new IR::PathExpression("m"), tmo); + metadataStruct->fields.push_back(new IR::StructField(tmo, timeout_id->type)); + add_instr(new IR::DpdkMovStatement(timeout, timeout_id)); + timeout_id = timeout; + } if (param->is()) { auto argument = param->to(); - add_instr(new IR::DpdkLearnStatement(action_name, argument)); + add_instr(new IR::DpdkLearnStatement(action_name, timeout_id, argument)); } else if (param->is()) { - auto argument = param->to()->components.at(0)->expression; - add_instr(new IR::DpdkLearnStatement(action_name, argument)); + if (param->to()->components.size() == 0) { + add_instr(new IR::DpdkLearnStatement(action_name, timeout_id)); + } else { + auto argument = param->to()->components.at(0)->expression; + add_instr(new IR::DpdkLearnStatement(action_name, timeout_id, argument)); + } } else if (param->is()) { // Move constant param to metadata as DPDK expects it to be in metadata BUG_CHECK(metadataStruct, "Metadata structure missing unexpectedly!"); @@ -784,10 +804,31 @@ bool ConvertStatementToDpdk::preorder(const IR::MethodCallStatement *s) { metadataStruct->fields.push_back(new IR::StructField(learnArg, param->type)); auto learnMember = new IR::Member(new IR::PathExpression("m"), learnArg); add_instr(new IR::DpdkMovStatement(learnMember, param)); - add_instr(new IR::DpdkLearnStatement(action_name, learnMember)); + add_instr(new IR::DpdkLearnStatement(action_name, timeout_id, learnMember)); } else { ::error(ErrorType::ERR_UNEXPECTED, "%1%: unhandled function", s); } + } else if (a->method->name == "restart_expire_timer") { + add_instr(new IR::DpdkRearmStatement()); + } else if (a->method->name == "set_entry_expire_time") { + auto args = a->expr->arguments; + if (args->size() != 1) { + ::error(ErrorType::ERR_UNEXPECTED, "Expected 1 argument for %1%", + a->method->name); + return false; + } + auto timeout = a->expr->arguments->at(0)->expression; + if (timeout->is()) { + // Move timeout_is to metadata fields as DPDK expects these parameters + // to be in metadata + BUG_CHECK(metadataStruct, "Metadata structure missing unexpectedly!"); + IR::ID tmo(refmap->newName("new_timeout")); + metadataStruct->fields.push_back(new IR::StructField(tmo, timeout->type)); + auto tmoMem = new IR::Member(new IR::PathExpression("m"), tmo); + add_instr(new IR::DpdkMovStatement(tmoMem, timeout)); + timeout = tmoMem; + } + add_instr(new IR::DpdkRearmStatement(timeout)); } else if (a->method->name == "mirror_packet") { auto args = a->expr->arguments; if (args->size() != 2) { diff --git a/backends/dpdk/dpdkProgramStructure.h b/backends/dpdk/dpdkProgramStructure.h index d55a506061..7eea9e2907 100644 --- a/backends/dpdk/dpdkProgramStructure.h +++ b/backends/dpdk/dpdkProgramStructure.h @@ -25,6 +25,7 @@ struct DpdkProgramStructure { ordered_set learner_tables; ordered_set learner_actions; ordered_map> learner_action_params; + ordered_map learner_action_table; IR::IndexedVector variables; diff --git a/backends/dpdk/midend.cpp b/backends/dpdk/midend.cpp index 3bd5e6f490..11d23c16ef 100644 --- a/backends/dpdk/midend.cpp +++ b/backends/dpdk/midend.cpp @@ -156,7 +156,8 @@ DpdkMidEnd::DpdkMidEnd(CompilerOptions &options, if (arch == "pna") { return new P4::ValidateTableProperties({"pna_implementation", "pna_direct_counter", "pna_direct_meter", "pna_idle_timeout", "size", - "add_on_miss"}); + "add_on_miss", "idle_timeout_with_auto_delete", + "default_idle_timeout_for_data_plane_added_entries"}); } else if (arch == "psa") { return new P4::ValidateTableProperties({"psa_implementation", "psa_direct_counter", "psa_direct_meter", "psa_idle_timeout", "size"}); diff --git a/backends/dpdk/spec.cpp b/backends/dpdk/spec.cpp index d3e936af51..9d12200e5e 100644 --- a/backends/dpdk/spec.cpp +++ b/backends/dpdk/spec.cpp @@ -223,7 +223,10 @@ std::ostream &IR::DpdkMirrorStatement::toSpec(std::ostream &out) const { } std::ostream &IR::DpdkLearnStatement::toSpec(std::ostream &out) const { - out << "learn " << action << " " << DPDK::toStr(argument); + out << "learn " << action << " "; + if (argument) + out << DPDK::toStr(argument) << " "; + out << DPDK::toStr(timeout); return out; } @@ -304,6 +307,13 @@ std::ostream &IR::DpdkReturnStatement::toSpec(std::ostream &out) const { return out; } +std::ostream &IR::DpdkRearmStatement::toSpec(std::ostream &out) const { + out << "rearm"; + if (timeout) + out << " " << DPDK::toStr(timeout); + return out; +} + std::ostream &IR::DpdkRecirculateStatement::toSpec(std::ostream &out) const { out << "recirculate"; return out; @@ -449,13 +459,13 @@ std::ostream& IR::DpdkLearner::toSpec(std::ostream& out) const { } else { out << "\tsize " << DEFAULT_LEARNER_TABLE_SIZE << std::endl; } - if (auto size = properties->getProperty("psa_idle_timeout")) { - out << "\ttimeout " << DPDK::toStr(size->value) << "" << std::endl; - } else { - out << "\ttimeout " << DEFAULT_LEARNER_TABLE_TIMEOUT << std::endl; - } - out << "}" << std::endl; + // The initial timeout values + out << "\ttimeout {" << std::endl; + out << "\t\t" << 60 << std::endl; + out << "\t\t" << 120 << std::endl; + out << "\t\t" << 180 << "\n\t\t}"; + out << "\n}" << std::endl; return out; } diff --git a/backends/p4test/CMakeLists.txt b/backends/p4test/CMakeLists.txt index b3239a40ff..65dc3b8247 100644 --- a/backends/p4test/CMakeLists.txt +++ b/backends/p4test/CMakeLists.txt @@ -108,6 +108,9 @@ set (P4_XFAIL_TESTS # These programs uses conditional execution inside action body which is currently # unsupported testdata/p4_16_samples/psa-dpdk-action-jumpOpt.p4 + testdata/p4_16_samples/pna-example-tcp-connection-tracking.p4 + testdata/p4_16_samples/pna-example-tcp-connection-tracking-err-1.p4 + testdata/p4_16_samples/pna-example-tcp-connection-tracking-err.p4 testdata/p4_16_samples/pna-example-pass-2.p4 # These tests are added to check mirror_packet extern invocation with non-constant # arguments and with incorrect number of arguments diff --git a/p4include/pna.p4 b/p4include/pna.p4 index a0624d6e47..afc08ece2c 100644 --- a/p4include/pna.p4 +++ b/p4include/pna.p4 @@ -598,7 +598,8 @@ extern void recirculate(); // entry's initial expire_time_profile_id. extern bool add_entry(string action_name, - in T action_params); + in T action_params, + in ExpireTimeProfileId_t expire_time_profile_id); extern FlowId_t allocate_flow_id(); diff --git a/testdata/p4_16_samples/pna-add-on-miss-err.p4 b/testdata/p4_16_samples/pna-add-on-miss-err.p4 new file mode 100644 index 0000000000..076b1bc013 --- /dev/null +++ b/testdata/p4_16_samples/pna-add-on-miss-err.p4 @@ -0,0 +1,200 @@ +/* +Copyright 2020 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. +*/ + +#include +#include "pna.p4" + + +typedef bit<48> EthernetAddress; + +header ethernet_t { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + bit<32> srcAddr; + bit<32> dstAddr; +} + +struct empty_metadata_t { +} + +// BEGIN:Counter_Example_Part1 +typedef bit<48> ByteCounter_t; +typedef bit<32> PacketCounter_t; +typedef bit<80> PacketByteCounter_t; + +const bit<32> NUM_PORTS = 4; +// END:Counter_Example_Part1 + + +////////////////////////////////////////////////////////////////////// +// Struct types for holding user-defined collections of headers and +// metadata in the P4 developer's program. +// +// Note: The names of these struct types are completely up to the P4 +// developer, as are their member fields, with the only restriction +// being that the structs intended to contain headers should only +// contain members whose types are header, header stack, or +// header_union. +////////////////////////////////////////////////////////////////////// + +struct main_metadata_t { + ExpireTimeProfileId_t timeout; +} + +// User-defined struct containing all of those headers parsed in the +// main parser. +struct headers_t { + ethernet_t ethernet; + ipv4_t ipv4; +} + +control PreControlImpl( + in headers_t hdr, + inout main_metadata_t meta, + in pna_pre_input_metadata_t istd, + inout pna_pre_output_metadata_t ostd) +{ + apply { + // Note: This program does not demonstrate all of the code + // that would be necessary if you were implementing IPsec + // packet decryption. + + // If it did, then this pre control implementation would do + // one or more table lookups in order to determine whether the + // packet was IPsec encapsulated, and if so, whether it is + // part of a security association that was established by the + // control plane software. + + // It would also likely perform anti-replay attack detection + // on the IPsec sequence number, which is in the unencrypted + // part of the packet. + + // Any headers parsed by the pre parser in pre_hdr will be + // forgotten after this point. The main parser will start + // parsing over from the beginning, either on the same packet + // if the inline extern block did nothing, or on the packet as + // modified by the inline extern block. + } +} + +parser MainParserImpl( + packet_in pkt, + out headers_t hdr, + inout main_metadata_t main_meta, + in pna_main_parser_input_metadata_t istd) +{ + state start { + pkt.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + 0x0800: parse_ipv4; + default: accept; + } + } + state parse_ipv4 { + pkt.extract(hdr.ipv4); + transition accept; + } +} + +// BEGIN:Counter_Example_Part2 +control MainControlImpl( + inout headers_t hdr, // from main parser + inout main_metadata_t user_meta, // from main parser, to "next block" + in pna_main_input_metadata_t istd, + inout pna_main_output_metadata_t ostd) +{ + action next_hop(PortId_t vport) { + send_to_port(vport); + } + action add_on_miss_action() { + bit<32> tmp = 0; + add_entry(action_name="next_hop", action_params = tmp, expire_time_profile_id = user_meta.timeout); + } + table ipv4_da { + key = { + hdr.ipv4.dstAddr: exact; + } + actions = { + @tableonly next_hop; + @defaultonly add_on_miss_action; + } + add_on_miss = false; + const default_action = add_on_miss_action; + } + action next_hop2(PortId_t vport, bit<32> newAddr) { + send_to_port(vport); + hdr.ipv4.srcAddr = newAddr; + } + action add_on_miss_action2() { + add_entry(action_name="next_hop2", action_params = {32w0, 32w1234}, expire_time_profile_id = user_meta.timeout); + } + table ipv4_da2 { + key = { + hdr.ipv4.dstAddr: exact; + } + actions = { + @tableonly next_hop2; + @defaultonly add_on_miss_action2; + } + add_on_miss = true; + const default_action = add_on_miss_action2; + } + apply { + if (hdr.ipv4.isValid()) { + ipv4_da.apply(); + ipv4_da2.apply(); + } + } +} +// END:Counter_Example_Part2 + +control MainDeparserImpl( + packet_out pkt, + in headers_t hdr, // from main control + in main_metadata_t user_meta, // from main control + in pna_main_output_metadata_t ostd) +{ + apply { + pkt.emit(hdr.ethernet); + pkt.emit(hdr.ipv4); + } +} + +// BEGIN:Package_Instantiation_Example +PNA_NIC( + MainParserImpl(), + PreControlImpl(), + MainControlImpl(), + MainDeparserImpl() + // Hoping to make this optional parameter later, but not supported + // by p4c yet. + //, PreParserImpl() + ) main; +// END:Package_Instantiation_Example diff --git a/testdata/p4_16_samples/pna-add-on-miss.p4 b/testdata/p4_16_samples/pna-add-on-miss.p4 index 8e29aeaa91..dd3e37c859 100644 --- a/testdata/p4_16_samples/pna-add-on-miss.p4 +++ b/testdata/p4_16_samples/pna-add-on-miss.p4 @@ -66,6 +66,7 @@ const bit<32> NUM_PORTS = 4; struct main_metadata_t { // empty for this skeleton + ExpireTimeProfileId_t timeout; } // User-defined struct containing all of those headers parsed in the @@ -135,7 +136,7 @@ control MainControlImpl( } action add_on_miss_action() { bit<32> tmp = 0; - add_entry(action_name="next_hop", action_params = tmp); + add_entry(action_name="next_hop", action_params = tmp, expire_time_profile_id = user_meta.timeout); } table ipv4_da { key = { @@ -153,7 +154,7 @@ control MainControlImpl( hdr.ipv4.srcAddr = newAddr; } action add_on_miss_action2() { - add_entry(action_name="next_hop", action_params = {32w0, 32w1234}); + add_entry(action_name="next_hop2", action_params = {32w0, 32w1234}, expire_time_profile_id = user_meta.timeout); } table ipv4_da2 { key = { diff --git a/testdata/p4_16_samples/pna-dpdk-parser-state-err.p4 b/testdata/p4_16_samples/pna-dpdk-parser-state-err.p4 index 007f911bac..169dcd5b8a 100644 --- a/testdata/p4_16_samples/pna-dpdk-parser-state-err.p4 +++ b/testdata/p4_16_samples/pna-dpdk-parser-state-err.p4 @@ -81,6 +81,7 @@ struct main_metadata_t { bit<1> rng_result1; bit<16> min1; bit<16> max1; + ExpireTimeProfileId_t timeout; } // User-defined struct containing all of those headers parsed in the @@ -144,7 +145,7 @@ control MainControlImpl( } action add_on_miss_action() { bit<32> tmp = 0; - add_entry(action_name="next_hop", action_params = tmp); + add_entry(action_name="next_hop", action_params = tmp, expire_time_profile_id = user_meta.timeout); } action do_range_checks_1 ( @@ -171,7 +172,7 @@ control MainControlImpl( hdr.ipv4.srcAddr = newAddr; } action add_on_miss_action2() { - add_entry(action_name="next_hop", action_params = {32w0, 32w1234}); + add_entry(action_name="next_hop", action_params = {32w0, 32w1234}, expire_time_profile_id = user_meta.timeout); } table ipv4_da2 { key = { diff --git a/testdata/p4_16_samples/pna-dpdk-table-key-use-annon.p4 b/testdata/p4_16_samples/pna-dpdk-table-key-use-annon.p4 index f40e03a17f..fa58dcd36e 100644 --- a/testdata/p4_16_samples/pna-dpdk-table-key-use-annon.p4 +++ b/testdata/p4_16_samples/pna-dpdk-table-key-use-annon.p4 @@ -66,7 +66,7 @@ const bit<32> NUM_PORTS = 4; struct main_metadata_t { bit<32> key; - // empty for this skeleton + ExpireTimeProfileId_t timeout; } // User-defined struct containing all of those headers parsed in the @@ -136,7 +136,7 @@ control MainControlImpl( } action add_on_miss_action() { bit<32> tmp = 0; - add_entry(action_name="next_hop", action_params = tmp); + add_entry(action_name="next_hop", action_params = tmp, expire_time_profile_id = user_meta.timeout); } table ipv4_da { key = { @@ -154,7 +154,7 @@ control MainControlImpl( hdr.ipv4.srcAddr = newAddr; } action add_on_miss_action2() { - add_entry(action_name="next_hop", action_params = {32w0, 32w1234}); + add_entry(action_name="next_hop", action_params = {32w0, 32w1234}, expire_time_profile_id = user_meta.timeout); } table ipv4_da2 { key = { diff --git a/testdata/p4_16_samples/pna-example-tcp-connection-tracking-err-1.p4 b/testdata/p4_16_samples/pna-example-tcp-connection-tracking-err-1.p4 new file mode 100644 index 0000000000..e69eea4ec2 --- /dev/null +++ b/testdata/p4_16_samples/pna-example-tcp-connection-tracking-err-1.p4 @@ -0,0 +1,341 @@ +/* +Copyright 2021-2022 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. +*/ + +#include +#include "../pna.p4" + + +// Very simple PNA program intended to demonstrate one use of an +// add-on-miss table to do a simple form of TCP connection tracking, +// where the per-entry expiration times can be modified in the data +// plane, without the control plane changing them. + + +typedef bit<48> EthernetAddress; +typedef bit<32> IPv4Address; + +header ethernet_t { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLength; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + IPv4Address srcAddr; + IPv4Address dstAddr; +} + +header tcp_t { + bit<16> srcPort; + bit<16> dstPort; + bit<32> seqNo; + bit<32> ackNo; + bit<4> dataOffset; + bit<4> res; + bit<8> flags; + bit<16> window; + bit<16> checksum; + bit<16> urgentPtr; +} + +// Masks of the bit positions of some bit flags within the TCP flags +// field. +const bit<8> TCP_URG_MASK = 0x20; +const bit<8> TCP_ACK_MASK = 0x10; +const bit<8> TCP_PSH_MASK = 0x08; +const bit<8> TCP_RST_MASK = 0x04; +const bit<8> TCP_SYN_MASK = 0x02; +const bit<8> TCP_FIN_MASK = 0x01; + +// Define names for different expire time profile id values. + +const ExpireTimeProfileId_t EXPIRE_TIME_PROFILE_TCP_NOW = (ExpireTimeProfileId_t) 0; +const ExpireTimeProfileId_t EXPIRE_TIME_PROFILE_TCP_NEW = (ExpireTimeProfileId_t) 1; +const ExpireTimeProfileId_t EXPIRE_TIME_PROFILE_TCP_ESTABLISHED = (ExpireTimeProfileId_t) 2; +const ExpireTimeProfileId_t EXPIRE_TIME_PROFILE_TCP_NEVER = (ExpireTimeProfileId_t) 3; + +////////////////////////////////////////////////////////////////////// +// Struct types for holding user-defined collections of headers and +// metadata in the P4 developer's program. +////////////////////////////////////////////////////////////////////// + +struct metadata_t { +} + +struct headers_t { + ethernet_t eth; + ipv4_t ipv4; + tcp_t tcp; +} + +parser MainParserImpl( + packet_in pkt, + out headers_t hdr, + inout metadata_t meta, + in pna_main_parser_input_metadata_t istd) +{ + state start { + pkt.extract(hdr.eth); + transition select (hdr.eth.etherType) { + 0x0800: parse_ipv4; + default: accept; + } + } + state parse_ipv4 { + pkt.extract(hdr.ipv4); + transition select (hdr.ipv4.protocol) { + 6: parse_tcp; + default: accept; + } + } + state parse_tcp { + pkt.extract(hdr.tcp); + transition accept; + } +} + +control PreControlImpl( + in headers_t hdr, + inout metadata_t meta, + in pna_pre_input_metadata_t istd, + inout pna_pre_output_metadata_t ostd) +{ + apply { + // No IPsec decryption for this example program, so pre + // control does nothing. + } +} + +struct ct_tcp_table_hit_params_t { +} + +control MainControlImpl( + inout headers_t hdr, + inout metadata_t meta, + in pna_main_input_metadata_t istd, + inout pna_main_output_metadata_t ostd) +{ + action drop () { + drop_packet(); + } + + // Inputs from previous tables (or actions, or in general other P4 + // code) that can modify the behavior of actions of ct_tcp_table. + bool do_add_on_miss; + bool update_aging_info; + bool update_expire_time; + ExpireTimeProfileId_t new_expire_time_profile_id; + + // Outputs from actions of ct_tcp_table + bool add_succeeded; + + action tcp_syn_packet () { + do_add_on_miss = true; + update_aging_info = true; + update_expire_time = true; + new_expire_time_profile_id = EXPIRE_TIME_PROFILE_TCP_NEW; + } + action tcp_fin_or_rst_packet () { + update_aging_info = true; + update_expire_time = true; + new_expire_time_profile_id = EXPIRE_TIME_PROFILE_TCP_NOW; + } + action tcp_other_packets () { + update_aging_info = true; + update_expire_time = true; + new_expire_time_profile_id = EXPIRE_TIME_PROFILE_TCP_ESTABLISHED; + } + + table set_ct_options { + key = { + hdr.tcp.flags: ternary; + } + actions = { + tcp_syn_packet; + tcp_fin_or_rst_packet; + tcp_other_packets; + } + const entries = { + TCP_SYN_MASK &&& TCP_SYN_MASK: tcp_syn_packet; + TCP_FIN_MASK &&& TCP_FIN_MASK: tcp_fin_or_rst_packet; + TCP_RST_MASK &&& TCP_RST_MASK: tcp_fin_or_rst_packet; + } + const default_action = tcp_other_packets; + } + + action ct_tcp_table_hit () { +#ifdef AVOID_IF_INSIDE_ACTION + // This extern function update_expire_info has exactly the + // same behavior as the code in the #else part of this #ifdef. + // It is proposed as an extern function included in the + // standard pna.p4 include file specifically as a workaround + // for P4 compilers that do not have full support for if + // statements, such as the BMv2 back end as of 2022-Apr. + + // Another reason to have such an extern function is as a + // convenience to P4 developers. Even if their compiler + // supports if statements inside of actions, if they want the + // behavior of update_expire_info, this is less code to write + // and read. + update_expire_info(update_aging_info, update_expire_time, + new_expire_time_profile_id); +#else + if (update_aging_info) { + if (update_expire_time) { + set_entry_expire_time(new_expire_time_profile_id); + // This is implicit and automatic part of the behavior + // of set_entry_expire_time() call: + //restart_expire_timer(); + } else { + restart_expire_timer(); + } + // a target might also support additional statements here + } else { + // Do nothing here. In particular, DO NOT + // restart_expire_time(). Whatever state the target + // device uses per-entry to represent the last time this + // entry was matched is left UNCHANGED. This can be + // useful in some connection tracking scenarios, + // e.g. where one wishes to "star the timer" when a FIN + // packet arrives, but it should KEEP RUNNING as later + // packets arrive, without being restarted. + + // a target might also support additional statements here + } +#endif // AVOID_IF_INSIDE_ACTION + } + + action ct_tcp_table_miss() { + if (do_add_on_miss) { + // This example does not need to use allocate_flow_id(), + // because no later part of the P4 program uses its return + // value for anything. + add_succeeded = + add_entry(action_name = "ct_tcp_table_hit", // name of action + action_params = (ct_tcp_table_hit_params_t) + {}, + expire_time_profile_id = new_expire_time_profile_id); + } else { + drop_packet(); + } + // a target might also support additional statements here, e.g. + // mirror the packet + // update a counter + // set receive queue + } + + table ct_tcp_table { + /* add_on_miss table is restricted to have all exact match fields */ + key = { + // other key fields also possible, e.g. VRF + SelectByDirection(istd.direction, hdr.ipv4.srcAddr, hdr.ipv4.dstAddr): + exact @name("ipv4_addr_0"); + SelectByDirection(istd.direction, hdr.ipv4.dstAddr, hdr.ipv4.srcAddr): + exact @name("ipv4_addr_1"); + hdr.ipv4.protocol : exact; + SelectByDirection(istd.direction, hdr.tcp.srcPort, hdr.tcp.dstPort): + exact @name("tcp_port_0"); + SelectByDirection(istd.direction, hdr.tcp.dstPort, hdr.tcp.srcPort): + exact @name("tcp_port_1"); + } + actions = { + @tableonly ct_tcp_table_hit; + @defaultonly ct_tcp_table_miss; + } + + // New PNA table property 'add_on_miss = true' indicates that + // this table can use extern function add_entry() in its + // default (i.e. miss) action to add a new entry to the table + // from the data plane. + add_on_miss = true; + + default_idle_timeout_for_data_plane_added_entries = 1; + + // New PNA table property 'idle_timeout_with_auto_delete' is + // similar to 'idle_timeout' in other architectures, except + // that entries that have not been matched for their expire + // time interval will be deleted, without the control plane + // having to delete the entry. + const default_action = ct_tcp_table_miss; + } + + apply { + // The following code is here to give an _example_ similar to + // the desired behavior, but is likely to be implemented in a + // variety of ways, e.g. one or more P4 table lookups. It is + // also likely NOT to be identical to what someone experienced + // at writing TCP connection tracking code actually wants. + + // The important point is that all of these variables: + + // + do_add_on_miss + // + update_expire_time + // + new_expire_time_profile_id + + // are assigned the values we want them to have _before_ + // calling ct_tcp_table.apply() below. The conditions under + // which they are assigned different values depends upon the + // contents of the packet header fields and the direction of + // the packet, and perhaps some earlier P4 table entries + // populated by control plane software, but _not_ upon the + // current entries installed in the ct_tcp_table. + + do_add_on_miss = false; + update_expire_time = false; + if ((istd.direction == PNA_Direction_t.HOST_TO_NET) && + hdr.ipv4.isValid() && hdr.tcp.isValid()) + { + set_ct_options.apply(); + } + + // ct_tcp_table is a bidirectional table + if (hdr.ipv4.isValid() && hdr.tcp.isValid()) { + ct_tcp_table.apply(); + } + } +} + +control MainDeparserImpl( + packet_out pkt, + in headers_t hdr, + in metadata_t meta, + in pna_main_output_metadata_t ostd) +{ + apply { + pkt.emit(hdr.eth); + } +} + +PNA_NIC( + MainParserImpl(), + PreControlImpl(), + MainControlImpl(), + MainDeparserImpl() + // Hoping to make this optional parameter later, but not supported + // by p4c yet. + //, PreParserImpl() + ) main; + diff --git a/testdata/p4_16_samples/pna-example-tcp-connection-tracking-err.p4 b/testdata/p4_16_samples/pna-example-tcp-connection-tracking-err.p4 new file mode 100644 index 0000000000..a0caca3b9b --- /dev/null +++ b/testdata/p4_16_samples/pna-example-tcp-connection-tracking-err.p4 @@ -0,0 +1,342 @@ +/* +Copyright 2021-2022 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. +*/ + +#include +#include "../pna.p4" + + +// Very simple PNA program intended to demonstrate one use of an +// add-on-miss table to do a simple form of TCP connection tracking, +// where the per-entry expiration times can be modified in the data +// plane, without the control plane changing them. + + +typedef bit<48> EthernetAddress; +typedef bit<32> IPv4Address; + +header ethernet_t { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLength; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + IPv4Address srcAddr; + IPv4Address dstAddr; +} + +header tcp_t { + bit<16> srcPort; + bit<16> dstPort; + bit<32> seqNo; + bit<32> ackNo; + bit<4> dataOffset; + bit<4> res; + bit<8> flags; + bit<16> window; + bit<16> checksum; + bit<16> urgentPtr; +} + +// Masks of the bit positions of some bit flags within the TCP flags +// field. +const bit<8> TCP_URG_MASK = 0x20; +const bit<8> TCP_ACK_MASK = 0x10; +const bit<8> TCP_PSH_MASK = 0x08; +const bit<8> TCP_RST_MASK = 0x04; +const bit<8> TCP_SYN_MASK = 0x02; +const bit<8> TCP_FIN_MASK = 0x01; + +// Define names for different expire time profile id values. + +const ExpireTimeProfileId_t EXPIRE_TIME_PROFILE_TCP_NOW = (ExpireTimeProfileId_t) 0; +const ExpireTimeProfileId_t EXPIRE_TIME_PROFILE_TCP_NEW = (ExpireTimeProfileId_t) 1; +const ExpireTimeProfileId_t EXPIRE_TIME_PROFILE_TCP_ESTABLISHED = (ExpireTimeProfileId_t) 2; +const ExpireTimeProfileId_t EXPIRE_TIME_PROFILE_TCP_NEVER = (ExpireTimeProfileId_t) 3; + +////////////////////////////////////////////////////////////////////// +// Struct types for holding user-defined collections of headers and +// metadata in the P4 developer's program. +////////////////////////////////////////////////////////////////////// + +struct metadata_t { +} + +struct headers_t { + ethernet_t eth; + ipv4_t ipv4; + tcp_t tcp; +} + +parser MainParserImpl( + packet_in pkt, + out headers_t hdr, + inout metadata_t meta, + in pna_main_parser_input_metadata_t istd) +{ + state start { + pkt.extract(hdr.eth); + transition select (hdr.eth.etherType) { + 0x0800: parse_ipv4; + default: accept; + } + } + state parse_ipv4 { + pkt.extract(hdr.ipv4); + transition select (hdr.ipv4.protocol) { + 6: parse_tcp; + default: accept; + } + } + state parse_tcp { + pkt.extract(hdr.tcp); + transition accept; + } +} + +control PreControlImpl( + in headers_t hdr, + inout metadata_t meta, + in pna_pre_input_metadata_t istd, + inout pna_pre_output_metadata_t ostd) +{ + apply { + // No IPsec decryption for this example program, so pre + // control does nothing. + } +} + +struct ct_tcp_table_hit_params_t { +} + +control MainControlImpl( + inout headers_t hdr, + inout metadata_t meta, + in pna_main_input_metadata_t istd, + inout pna_main_output_metadata_t ostd) +{ + action drop () { + drop_packet(); + } + + // Inputs from previous tables (or actions, or in general other P4 + // code) that can modify the behavior of actions of ct_tcp_table. + bool do_add_on_miss; + bool update_aging_info; + bool update_expire_time; + ExpireTimeProfileId_t new_expire_time_profile_id; + + // Outputs from actions of ct_tcp_table + bool add_succeeded; + + action tcp_syn_packet () { + do_add_on_miss = true; + update_aging_info = true; + update_expire_time = true; + new_expire_time_profile_id = EXPIRE_TIME_PROFILE_TCP_NEW; + } + action tcp_fin_or_rst_packet () { + update_aging_info = true; + update_expire_time = true; + new_expire_time_profile_id = EXPIRE_TIME_PROFILE_TCP_NOW; + } + action tcp_other_packets () { + update_aging_info = true; + update_expire_time = true; + new_expire_time_profile_id = EXPIRE_TIME_PROFILE_TCP_ESTABLISHED; + } + + table set_ct_options { + key = { + hdr.tcp.flags: ternary; + } + actions = { + tcp_syn_packet; + tcp_fin_or_rst_packet; + tcp_other_packets; + } + const entries = { + TCP_SYN_MASK &&& TCP_SYN_MASK: tcp_syn_packet; + TCP_FIN_MASK &&& TCP_FIN_MASK: tcp_fin_or_rst_packet; + TCP_RST_MASK &&& TCP_RST_MASK: tcp_fin_or_rst_packet; + } + const default_action = tcp_other_packets; + } + + action ct_tcp_table_hit () { +#ifdef AVOID_IF_INSIDE_ACTION + // This extern function update_expire_info has exactly the + // same behavior as the code in the #else part of this #ifdef. + // It is proposed as an extern function included in the + // standard pna.p4 include file specifically as a workaround + // for P4 compilers that do not have full support for if + // statements, such as the BMv2 back end as of 2022-Apr. + + // Another reason to have such an extern function is as a + // convenience to P4 developers. Even if their compiler + // supports if statements inside of actions, if they want the + // behavior of update_expire_info, this is less code to write + // and read. + update_expire_info(update_aging_info, update_expire_time, + new_expire_time_profile_id); +#else + if (update_aging_info) { + if (update_expire_time) { + set_entry_expire_time(new_expire_time_profile_id); + // This is implicit and automatic part of the behavior + // of set_entry_expire_time() call: + //restart_expire_timer(); + } else { + restart_expire_timer(); + } + // a target might also support additional statements here + } else { + // Do nothing here. In particular, DO NOT + // restart_expire_time(). Whatever state the target + // device uses per-entry to represent the last time this + // entry was matched is left UNCHANGED. This can be + // useful in some connection tracking scenarios, + // e.g. where one wishes to "star the timer" when a FIN + // packet arrives, but it should KEEP RUNNING as later + // packets arrive, without being restarted. + + // a target might also support additional statements here + } +#endif // AVOID_IF_INSIDE_ACTION + } + + action ct_tcp_table_miss() { + if (do_add_on_miss) { + // This example does not need to use allocate_flow_id(), + // because no later part of the P4 program uses its return + // value for anything. + add_succeeded = + add_entry(action_name = "ct_tcp_table_hit", // name of action + action_params = (ct_tcp_table_hit_params_t) + {}, + expire_time_profile_id = new_expire_time_profile_id); + } else { + drop_packet(); + } + // a target might also support additional statements here, e.g. + // mirror the packet + // update a counter + // set receive queue + } + + table ct_tcp_table { + /* add_on_miss table is restricted to have all exact match fields */ + key = { + // other key fields also possible, e.g. VRF + SelectByDirection(istd.direction, hdr.ipv4.srcAddr, hdr.ipv4.dstAddr): + exact @name("ipv4_addr_0"); + SelectByDirection(istd.direction, hdr.ipv4.dstAddr, hdr.ipv4.srcAddr): + exact @name("ipv4_addr_1"); + hdr.ipv4.protocol : exact; + SelectByDirection(istd.direction, hdr.tcp.srcPort, hdr.tcp.dstPort): + exact @name("tcp_port_0"); + SelectByDirection(istd.direction, hdr.tcp.dstPort, hdr.tcp.srcPort): + exact @name("tcp_port_1"); + } + actions = { + @tableonly ct_tcp_table_hit; + @defaultonly ct_tcp_table_miss; + } + + // New PNA table property 'add_on_miss = true' indicates that + // this table can use extern function add_entry() in its + // default (i.e. miss) action to add a new entry to the table + // from the data plane. + add_on_miss = true; + + default_idle_timeout_for_data_plane_added_entries = 1; + + // New PNA table property 'idle_timeout_with_auto_delete' is + // similar to 'idle_timeout' in other architectures, except + // that entries that have not been matched for their expire + // time interval will be deleted, without the control plane + // having to delete the entry. + idle_timeout_with_auto_delete = false; + const default_action = ct_tcp_table_miss; + } + + apply { + // The following code is here to give an _example_ similar to + // the desired behavior, but is likely to be implemented in a + // variety of ways, e.g. one or more P4 table lookups. It is + // also likely NOT to be identical to what someone experienced + // at writing TCP connection tracking code actually wants. + + // The important point is that all of these variables: + + // + do_add_on_miss + // + update_expire_time + // + new_expire_time_profile_id + + // are assigned the values we want them to have _before_ + // calling ct_tcp_table.apply() below. The conditions under + // which they are assigned different values depends upon the + // contents of the packet header fields and the direction of + // the packet, and perhaps some earlier P4 table entries + // populated by control plane software, but _not_ upon the + // current entries installed in the ct_tcp_table. + + do_add_on_miss = false; + update_expire_time = false; + if ((istd.direction == PNA_Direction_t.HOST_TO_NET) && + hdr.ipv4.isValid() && hdr.tcp.isValid()) + { + set_ct_options.apply(); + } + + // ct_tcp_table is a bidirectional table + if (hdr.ipv4.isValid() && hdr.tcp.isValid()) { + ct_tcp_table.apply(); + } + } +} + +control MainDeparserImpl( + packet_out pkt, + in headers_t hdr, + in metadata_t meta, + in pna_main_output_metadata_t ostd) +{ + apply { + pkt.emit(hdr.eth); + } +} + +PNA_NIC( + MainParserImpl(), + PreControlImpl(), + MainControlImpl(), + MainDeparserImpl() + // Hoping to make this optional parameter later, but not supported + // by p4c yet. + //, PreParserImpl() + ) main; + diff --git a/testdata/p4_16_samples/pna-example-tcp-connection-tracking.p4 b/testdata/p4_16_samples/pna-example-tcp-connection-tracking.p4 new file mode 100644 index 0000000000..7db94b4fc1 --- /dev/null +++ b/testdata/p4_16_samples/pna-example-tcp-connection-tracking.p4 @@ -0,0 +1,342 @@ +/* +Copyright 2021-2022 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. +*/ + +#include +#include "../pna.p4" + + +// Very simple PNA program intended to demonstrate one use of an +// add-on-miss table to do a simple form of TCP connection tracking, +// where the per-entry expiration times can be modified in the data +// plane, without the control plane changing them. + + +typedef bit<48> EthernetAddress; +typedef bit<32> IPv4Address; + +header ethernet_t { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLength; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + IPv4Address srcAddr; + IPv4Address dstAddr; +} + +header tcp_t { + bit<16> srcPort; + bit<16> dstPort; + bit<32> seqNo; + bit<32> ackNo; + bit<4> dataOffset; + bit<4> res; + bit<8> flags; + bit<16> window; + bit<16> checksum; + bit<16> urgentPtr; +} + +// Masks of the bit positions of some bit flags within the TCP flags +// field. +const bit<8> TCP_URG_MASK = 0x20; +const bit<8> TCP_ACK_MASK = 0x10; +const bit<8> TCP_PSH_MASK = 0x08; +const bit<8> TCP_RST_MASK = 0x04; +const bit<8> TCP_SYN_MASK = 0x02; +const bit<8> TCP_FIN_MASK = 0x01; + +// Define names for different expire time profile id values. + +const ExpireTimeProfileId_t EXPIRE_TIME_PROFILE_TCP_NOW = (ExpireTimeProfileId_t) 0; +const ExpireTimeProfileId_t EXPIRE_TIME_PROFILE_TCP_NEW = (ExpireTimeProfileId_t) 1; +const ExpireTimeProfileId_t EXPIRE_TIME_PROFILE_TCP_ESTABLISHED = (ExpireTimeProfileId_t) 2; +const ExpireTimeProfileId_t EXPIRE_TIME_PROFILE_TCP_NEVER = (ExpireTimeProfileId_t) 3; + +////////////////////////////////////////////////////////////////////// +// Struct types for holding user-defined collections of headers and +// metadata in the P4 developer's program. +////////////////////////////////////////////////////////////////////// + +struct metadata_t { +} + +struct headers_t { + ethernet_t eth; + ipv4_t ipv4; + tcp_t tcp; +} + +parser MainParserImpl( + packet_in pkt, + out headers_t hdr, + inout metadata_t meta, + in pna_main_parser_input_metadata_t istd) +{ + state start { + pkt.extract(hdr.eth); + transition select (hdr.eth.etherType) { + 0x0800: parse_ipv4; + default: accept; + } + } + state parse_ipv4 { + pkt.extract(hdr.ipv4); + transition select (hdr.ipv4.protocol) { + 6: parse_tcp; + default: accept; + } + } + state parse_tcp { + pkt.extract(hdr.tcp); + transition accept; + } +} + +control PreControlImpl( + in headers_t hdr, + inout metadata_t meta, + in pna_pre_input_metadata_t istd, + inout pna_pre_output_metadata_t ostd) +{ + apply { + // No IPsec decryption for this example program, so pre + // control does nothing. + } +} + +struct ct_tcp_table_hit_params_t { +} + +control MainControlImpl( + inout headers_t hdr, + inout metadata_t meta, + in pna_main_input_metadata_t istd, + inout pna_main_output_metadata_t ostd) +{ + action drop () { + drop_packet(); + } + + // Inputs from previous tables (or actions, or in general other P4 + // code) that can modify the behavior of actions of ct_tcp_table. + bool do_add_on_miss; + bool update_aging_info; + bool update_expire_time; + ExpireTimeProfileId_t new_expire_time_profile_id; + + // Outputs from actions of ct_tcp_table + bool add_succeeded; + + action tcp_syn_packet () { + do_add_on_miss = true; + update_aging_info = true; + update_expire_time = true; + new_expire_time_profile_id = EXPIRE_TIME_PROFILE_TCP_NEW; + } + action tcp_fin_or_rst_packet () { + update_aging_info = true; + update_expire_time = true; + new_expire_time_profile_id = EXPIRE_TIME_PROFILE_TCP_NOW; + } + action tcp_other_packets () { + update_aging_info = true; + update_expire_time = true; + new_expire_time_profile_id = EXPIRE_TIME_PROFILE_TCP_ESTABLISHED; + } + + table set_ct_options { + key = { + hdr.tcp.flags: ternary; + } + actions = { + tcp_syn_packet; + tcp_fin_or_rst_packet; + tcp_other_packets; + } + const entries = { + TCP_SYN_MASK &&& TCP_SYN_MASK: tcp_syn_packet; + TCP_FIN_MASK &&& TCP_FIN_MASK: tcp_fin_or_rst_packet; + TCP_RST_MASK &&& TCP_RST_MASK: tcp_fin_or_rst_packet; + } + const default_action = tcp_other_packets; + } + + action ct_tcp_table_hit () { +#ifdef AVOID_IF_INSIDE_ACTION + // This extern function update_expire_info has exactly the + // same behavior as the code in the #else part of this #ifdef. + // It is proposed as an extern function included in the + // standard pna.p4 include file specifically as a workaround + // for P4 compilers that do not have full support for if + // statements, such as the BMv2 back end as of 2022-Apr. + + // Another reason to have such an extern function is as a + // convenience to P4 developers. Even if their compiler + // supports if statements inside of actions, if they want the + // behavior of update_expire_info, this is less code to write + // and read. + update_expire_info(update_aging_info, update_expire_time, + new_expire_time_profile_id); +#else + if (update_aging_info) { + if (update_expire_time) { + set_entry_expire_time(new_expire_time_profile_id); + // This is implicit and automatic part of the behavior + // of set_entry_expire_time() call: + //restart_expire_timer(); + } else { + restart_expire_timer(); + } + // a target might also support additional statements here + } else { + // Do nothing here. In particular, DO NOT + // restart_expire_time(). Whatever state the target + // device uses per-entry to represent the last time this + // entry was matched is left UNCHANGED. This can be + // useful in some connection tracking scenarios, + // e.g. where one wishes to "star the timer" when a FIN + // packet arrives, but it should KEEP RUNNING as later + // packets arrive, without being restarted. + + // a target might also support additional statements here + } +#endif // AVOID_IF_INSIDE_ACTION + } + + action ct_tcp_table_miss() { + if (do_add_on_miss) { + // This example does not need to use allocate_flow_id(), + // because no later part of the P4 program uses its return + // value for anything. + add_succeeded = + add_entry(action_name = "ct_tcp_table_hit", // name of action + action_params = (ct_tcp_table_hit_params_t) + {}, + expire_time_profile_id = new_expire_time_profile_id); + } else { + drop_packet(); + } + // a target might also support additional statements here, e.g. + // mirror the packet + // update a counter + // set receive queue + } + + table ct_tcp_table { + /* add_on_miss table is restricted to have all exact match fields */ + key = { + // other key fields also possible, e.g. VRF + SelectByDirection(istd.direction, hdr.ipv4.srcAddr, hdr.ipv4.dstAddr): + exact @name("ipv4_addr_0"); + SelectByDirection(istd.direction, hdr.ipv4.dstAddr, hdr.ipv4.srcAddr): + exact @name("ipv4_addr_1"); + hdr.ipv4.protocol : exact; + SelectByDirection(istd.direction, hdr.tcp.srcPort, hdr.tcp.dstPort): + exact @name("tcp_port_0"); + SelectByDirection(istd.direction, hdr.tcp.dstPort, hdr.tcp.srcPort): + exact @name("tcp_port_1"); + } + actions = { + @tableonly ct_tcp_table_hit; + @defaultonly ct_tcp_table_miss; + } + + // New PNA table property 'add_on_miss = true' indicates that + // this table can use extern function add_entry() in its + // default (i.e. miss) action to add a new entry to the table + // from the data plane. + add_on_miss = true; + + default_idle_timeout_for_data_plane_added_entries = 1; + + // New PNA table property 'idle_timeout_with_auto_delete' is + // similar to 'idle_timeout' in other architectures, except + // that entries that have not been matched for their expire + // time interval will be deleted, without the control plane + // having to delete the entry. + idle_timeout_with_auto_delete = true; + const default_action = ct_tcp_table_miss; + } + + apply { + // The following code is here to give an _example_ similar to + // the desired behavior, but is likely to be implemented in a + // variety of ways, e.g. one or more P4 table lookups. It is + // also likely NOT to be identical to what someone experienced + // at writing TCP connection tracking code actually wants. + + // The important point is that all of these variables: + + // + do_add_on_miss + // + update_expire_time + // + new_expire_time_profile_id + + // are assigned the values we want them to have _before_ + // calling ct_tcp_table.apply() below. The conditions under + // which they are assigned different values depends upon the + // contents of the packet header fields and the direction of + // the packet, and perhaps some earlier P4 table entries + // populated by control plane software, but _not_ upon the + // current entries installed in the ct_tcp_table. + + do_add_on_miss = false; + update_expire_time = false; + if ((istd.direction == PNA_Direction_t.HOST_TO_NET) && + hdr.ipv4.isValid() && hdr.tcp.isValid()) + { + set_ct_options.apply(); + } + + // ct_tcp_table is a bidirectional table + if (hdr.ipv4.isValid() && hdr.tcp.isValid()) { + ct_tcp_table.apply(); + } + } +} + +control MainDeparserImpl( + packet_out pkt, + in headers_t hdr, + in metadata_t meta, + in pna_main_output_metadata_t ostd) +{ + apply { + pkt.emit(hdr.eth); + } +} + +PNA_NIC( + MainParserImpl(), + PreControlImpl(), + MainControlImpl(), + MainDeparserImpl() + // Hoping to make this optional parameter later, but not supported + // by p4c yet. + //, PreParserImpl() + ) main; + diff --git a/testdata/p4_16_samples/pna-mux-dismantle.p4 b/testdata/p4_16_samples/pna-mux-dismantle.p4 index b221eef6e2..5560ad62d5 100644 --- a/testdata/p4_16_samples/pna-mux-dismantle.p4 +++ b/testdata/p4_16_samples/pna-mux-dismantle.p4 @@ -81,6 +81,7 @@ struct main_metadata_t { bit<1> rng_result1; bit<1> val1; bit<1> val2; + ExpireTimeProfileId_t timeout; } // User-defined struct containing all of those headers parsed in the @@ -142,7 +143,7 @@ control MainControlImpl( } action add_on_miss_action() { bit<32> tmp = 0; - add_entry(action_name="next_hop", action_params = tmp); + add_entry(action_name="next_hop", action_params = tmp, expire_time_profile_id = user_meta.timeout); } action do_range_checks_1 ( @@ -169,7 +170,7 @@ control MainControlImpl( hdr.ipv4.srcAddr = newAddr; } action add_on_miss_action2() { - add_entry(action_name="next_hop", action_params = {32w0, 32w1234}); + add_entry(action_name="next_hop", action_params = {32w0, 32w1234}, expire_time_profile_id = user_meta.timeout); } table ipv4_da2 { key = { diff --git a/testdata/p4_16_samples_outputs/pna-add-on-miss-err-first.p4 b/testdata/p4_16_samples_outputs/pna-add-on-miss-err-first.p4 new file mode 100644 index 0000000000..3b16e52b24 --- /dev/null +++ b/testdata/p4_16_samples_outputs/pna-add-on-miss-err-first.p4 @@ -0,0 +1,114 @@ +#include +#include + +typedef bit<48> EthernetAddress; +header ethernet_t { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + bit<32> srcAddr; + bit<32> dstAddr; +} + +struct empty_metadata_t { +} + +typedef bit<48> ByteCounter_t; +typedef bit<32> PacketCounter_t; +typedef bit<80> PacketByteCounter_t; +const bit<32> NUM_PORTS = 32w4; +struct main_metadata_t { + ExpireTimeProfileId_t timeout; +} + +struct headers_t { + ethernet_t ethernet; + ipv4_t ipv4; +} + +control PreControlImpl(in headers_t hdr, inout main_metadata_t meta, in pna_pre_input_metadata_t istd, inout pna_pre_output_metadata_t ostd) { + apply { + } +} + +parser MainParserImpl(packet_in pkt, out headers_t hdr, inout main_metadata_t main_meta, in pna_main_parser_input_metadata_t istd) { + state start { + pkt.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + 16w0x800: parse_ipv4; + default: accept; + } + } + state parse_ipv4 { + pkt.extract(hdr.ipv4); + transition accept; + } +} + +control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in pna_main_input_metadata_t istd, inout pna_main_output_metadata_t ostd) { + action next_hop(PortId_t vport) { + send_to_port(vport); + } + action add_on_miss_action() { + bit<32> tmp = 32w0; + add_entry>(action_name = "next_hop", action_params = tmp, expire_time_profile_id = user_meta.timeout); + } + table ipv4_da { + key = { + hdr.ipv4.dstAddr: exact @name("hdr.ipv4.dstAddr") ; + } + actions = { + @tableonly next_hop(); + @defaultonly add_on_miss_action(); + } + add_on_miss = false; + const default_action = add_on_miss_action(); + } + action next_hop2(PortId_t vport, bit<32> newAddr) { + send_to_port(vport); + hdr.ipv4.srcAddr = newAddr; + } + action add_on_miss_action2() { + add_entry, bit<32>>>(action_name = "next_hop2", action_params = { 32w0, 32w1234 }, expire_time_profile_id = user_meta.timeout); + } + table ipv4_da2 { + key = { + hdr.ipv4.dstAddr: exact @name("hdr.ipv4.dstAddr") ; + } + actions = { + @tableonly next_hop2(); + @defaultonly add_on_miss_action2(); + } + add_on_miss = true; + const default_action = add_on_miss_action2(); + } + apply { + if (hdr.ipv4.isValid()) { + ipv4_da.apply(); + ipv4_da2.apply(); + } + } +} + +control MainDeparserImpl(packet_out pkt, in headers_t hdr, in main_metadata_t user_meta, in pna_main_output_metadata_t ostd) { + apply { + pkt.emit(hdr.ethernet); + pkt.emit(hdr.ipv4); + } +} + +PNA_NIC(MainParserImpl(), PreControlImpl(), MainControlImpl(), MainDeparserImpl()) main; + diff --git a/testdata/p4_16_samples_outputs/pna-add-on-miss-err-frontend.p4 b/testdata/p4_16_samples_outputs/pna-add-on-miss-err-frontend.p4 new file mode 100644 index 0000000000..dd8c8ba606 --- /dev/null +++ b/testdata/p4_16_samples_outputs/pna-add-on-miss-err-frontend.p4 @@ -0,0 +1,111 @@ +#include +#include + +typedef bit<48> EthernetAddress; +header ethernet_t { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + bit<32> srcAddr; + bit<32> dstAddr; +} + +struct empty_metadata_t { +} + +struct main_metadata_t { + ExpireTimeProfileId_t timeout; +} + +struct headers_t { + ethernet_t ethernet; + ipv4_t ipv4; +} + +control PreControlImpl(in headers_t hdr, inout main_metadata_t meta, in pna_pre_input_metadata_t istd, inout pna_pre_output_metadata_t ostd) { + apply { + } +} + +parser MainParserImpl(packet_in pkt, out headers_t hdr, inout main_metadata_t main_meta, in pna_main_parser_input_metadata_t istd) { + state start { + pkt.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + 16w0x800: parse_ipv4; + default: accept; + } + } + state parse_ipv4 { + pkt.extract(hdr.ipv4); + transition accept; + } +} + +control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in pna_main_input_metadata_t istd, inout pna_main_output_metadata_t ostd) { + @name("MainControlImpl.tmp") bit<32> tmp_0; + @name("MainControlImpl.next_hop") action next_hop(@name("vport") PortId_t vport) { + send_to_port(vport); + } + @name("MainControlImpl.add_on_miss_action") action add_on_miss_action() { + tmp_0 = 32w0; + add_entry>(action_name = "next_hop", action_params = tmp_0, expire_time_profile_id = user_meta.timeout); + } + @name("MainControlImpl.ipv4_da") table ipv4_da_0 { + key = { + hdr.ipv4.dstAddr: exact @name("hdr.ipv4.dstAddr") ; + } + actions = { + @tableonly next_hop(); + @defaultonly add_on_miss_action(); + } + add_on_miss = false; + const default_action = add_on_miss_action(); + } + @name("MainControlImpl.next_hop2") action next_hop2(@name("vport") PortId_t vport_2, @name("newAddr") bit<32> newAddr) { + send_to_port(vport_2); + hdr.ipv4.srcAddr = newAddr; + } + @name("MainControlImpl.add_on_miss_action2") action add_on_miss_action2() { + add_entry, bit<32>>>(action_name = "next_hop2", action_params = { 32w0, 32w1234 }, expire_time_profile_id = user_meta.timeout); + } + @name("MainControlImpl.ipv4_da2") table ipv4_da2_0 { + key = { + hdr.ipv4.dstAddr: exact @name("hdr.ipv4.dstAddr") ; + } + actions = { + @tableonly next_hop2(); + @defaultonly add_on_miss_action2(); + } + add_on_miss = true; + const default_action = add_on_miss_action2(); + } + apply { + if (hdr.ipv4.isValid()) { + ipv4_da_0.apply(); + ipv4_da2_0.apply(); + } + } +} + +control MainDeparserImpl(packet_out pkt, in headers_t hdr, in main_metadata_t user_meta, in pna_main_output_metadata_t ostd) { + apply { + pkt.emit(hdr.ethernet); + pkt.emit(hdr.ipv4); + } +} + +PNA_NIC(MainParserImpl(), PreControlImpl(), MainControlImpl(), MainDeparserImpl()) main; + diff --git a/testdata/p4_16_samples_outputs/pna-add-on-miss-err-midend.p4 b/testdata/p4_16_samples_outputs/pna-add-on-miss-err-midend.p4 new file mode 100644 index 0000000000..8d8a53c059 --- /dev/null +++ b/testdata/p4_16_samples_outputs/pna-add-on-miss-err-midend.p4 @@ -0,0 +1,123 @@ +#include +#include + +typedef bit<48> EthernetAddress; +header ethernet_t { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + bit<32> srcAddr; + bit<32> dstAddr; +} + +struct empty_metadata_t { +} + +struct main_metadata_t { + ExpireTimeProfileId_t timeout; +} + +struct headers_t { + ethernet_t ethernet; + ipv4_t ipv4; +} + +control PreControlImpl(in headers_t hdr, inout main_metadata_t meta, in pna_pre_input_metadata_t istd, inout pna_pre_output_metadata_t ostd) { + apply { + } +} + +parser MainParserImpl(packet_in pkt, out headers_t hdr, inout main_metadata_t main_meta, in pna_main_parser_input_metadata_t istd) { + state start { + pkt.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + 16w0x800: parse_ipv4; + default: accept; + } + } + state parse_ipv4 { + pkt.extract(hdr.ipv4); + transition accept; + } +} + +struct tuple_0 { + bit<32> f0; + bit<32> f1; +} + +control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in pna_main_input_metadata_t istd, inout pna_main_output_metadata_t ostd) { + @name("MainControlImpl.next_hop") action next_hop(@name("vport") PortId_t vport) { + send_to_port(vport); + } + @name("MainControlImpl.add_on_miss_action") action add_on_miss_action() { + add_entry>(action_name = "next_hop", action_params = 32w0, expire_time_profile_id = user_meta.timeout); + } + @name("MainControlImpl.ipv4_da") table ipv4_da_0 { + key = { + hdr.ipv4.dstAddr: exact @name("hdr.ipv4.dstAddr") ; + } + actions = { + @tableonly next_hop(); + @defaultonly add_on_miss_action(); + } + add_on_miss = false; + const default_action = add_on_miss_action(); + } + @name("MainControlImpl.next_hop2") action next_hop2(@name("vport") PortId_t vport_2, @name("newAddr") bit<32> newAddr) { + send_to_port(vport_2); + hdr.ipv4.srcAddr = newAddr; + } + @name("MainControlImpl.add_on_miss_action2") action add_on_miss_action2() { + add_entry(action_name = "next_hop2", action_params = (tuple_0){f0 = 32w0,f1 = 32w1234}, expire_time_profile_id = user_meta.timeout); + } + @name("MainControlImpl.ipv4_da2") table ipv4_da2_0 { + key = { + hdr.ipv4.dstAddr: exact @name("hdr.ipv4.dstAddr") ; + } + actions = { + @tableonly next_hop2(); + @defaultonly add_on_miss_action2(); + } + add_on_miss = true; + const default_action = add_on_miss_action2(); + } + apply { + if (hdr.ipv4.isValid()) { + ipv4_da_0.apply(); + ipv4_da2_0.apply(); + } + } +} + +control MainDeparserImpl(packet_out pkt, in headers_t hdr, in main_metadata_t user_meta, in pna_main_output_metadata_t ostd) { + @hidden action pnaaddonmisserr185() { + pkt.emit(hdr.ethernet); + pkt.emit(hdr.ipv4); + } + @hidden table tbl_pnaaddonmisserr185 { + actions = { + pnaaddonmisserr185(); + } + const default_action = pnaaddonmisserr185(); + } + apply { + tbl_pnaaddonmisserr185.apply(); + } +} + +PNA_NIC(MainParserImpl(), PreControlImpl(), MainControlImpl(), MainDeparserImpl()) main; + diff --git a/testdata/p4_16_samples_outputs/pna-add-on-miss-err.p4 b/testdata/p4_16_samples_outputs/pna-add-on-miss-err.p4 new file mode 100644 index 0000000000..93e81cdd86 --- /dev/null +++ b/testdata/p4_16_samples_outputs/pna-add-on-miss-err.p4 @@ -0,0 +1,114 @@ +#include +#include + +typedef bit<48> EthernetAddress; +header ethernet_t { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + bit<32> srcAddr; + bit<32> dstAddr; +} + +struct empty_metadata_t { +} + +typedef bit<48> ByteCounter_t; +typedef bit<32> PacketCounter_t; +typedef bit<80> PacketByteCounter_t; +const bit<32> NUM_PORTS = 4; +struct main_metadata_t { + ExpireTimeProfileId_t timeout; +} + +struct headers_t { + ethernet_t ethernet; + ipv4_t ipv4; +} + +control PreControlImpl(in headers_t hdr, inout main_metadata_t meta, in pna_pre_input_metadata_t istd, inout pna_pre_output_metadata_t ostd) { + apply { + } +} + +parser MainParserImpl(packet_in pkt, out headers_t hdr, inout main_metadata_t main_meta, in pna_main_parser_input_metadata_t istd) { + state start { + pkt.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + 0x800: parse_ipv4; + default: accept; + } + } + state parse_ipv4 { + pkt.extract(hdr.ipv4); + transition accept; + } +} + +control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in pna_main_input_metadata_t istd, inout pna_main_output_metadata_t ostd) { + action next_hop(PortId_t vport) { + send_to_port(vport); + } + action add_on_miss_action() { + bit<32> tmp = 0; + add_entry(action_name = "next_hop", action_params = tmp, expire_time_profile_id = user_meta.timeout); + } + table ipv4_da { + key = { + hdr.ipv4.dstAddr: exact; + } + actions = { + @tableonly next_hop; + @defaultonly add_on_miss_action; + } + add_on_miss = false; + const default_action = add_on_miss_action; + } + action next_hop2(PortId_t vport, bit<32> newAddr) { + send_to_port(vport); + hdr.ipv4.srcAddr = newAddr; + } + action add_on_miss_action2() { + add_entry(action_name = "next_hop2", action_params = { 32w0, 32w1234 }, expire_time_profile_id = user_meta.timeout); + } + table ipv4_da2 { + key = { + hdr.ipv4.dstAddr: exact; + } + actions = { + @tableonly next_hop2; + @defaultonly add_on_miss_action2; + } + add_on_miss = true; + const default_action = add_on_miss_action2; + } + apply { + if (hdr.ipv4.isValid()) { + ipv4_da.apply(); + ipv4_da2.apply(); + } + } +} + +control MainDeparserImpl(packet_out pkt, in headers_t hdr, in main_metadata_t user_meta, in pna_main_output_metadata_t ostd) { + apply { + pkt.emit(hdr.ethernet); + pkt.emit(hdr.ipv4); + } +} + +PNA_NIC(MainParserImpl(), PreControlImpl(), MainControlImpl(), MainDeparserImpl()) main; + diff --git a/testdata/p4_16_samples_outputs/pna-add-on-miss-err.p4-stderr b/testdata/p4_16_samples_outputs/pna-add-on-miss-err.p4-stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/testdata/p4_16_samples_outputs/pna-add-on-miss-first.p4 b/testdata/p4_16_samples_outputs/pna-add-on-miss-first.p4 index b40b7ae583..2ac037dd82 100644 --- a/testdata/p4_16_samples_outputs/pna-add-on-miss-first.p4 +++ b/testdata/p4_16_samples_outputs/pna-add-on-miss-first.p4 @@ -31,6 +31,7 @@ typedef bit<32> PacketCounter_t; typedef bit<80> PacketByteCounter_t; const bit<32> NUM_PORTS = 32w4; struct main_metadata_t { + ExpireTimeProfileId_t timeout; } struct headers_t { @@ -63,7 +64,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in } action add_on_miss_action() { bit<32> tmp = 32w0; - add_entry>(action_name = "next_hop", action_params = tmp); + add_entry>(action_name = "next_hop", action_params = tmp, expire_time_profile_id = user_meta.timeout); } table ipv4_da { key = { @@ -81,7 +82,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in hdr.ipv4.srcAddr = newAddr; } action add_on_miss_action2() { - add_entry, bit<32>>>(action_name = "next_hop", action_params = { 32w0, 32w1234 }); + add_entry, bit<32>>>(action_name = "next_hop2", action_params = { 32w0, 32w1234 }, expire_time_profile_id = user_meta.timeout); } table ipv4_da2 { key = { diff --git a/testdata/p4_16_samples_outputs/pna-add-on-miss-frontend.p4 b/testdata/p4_16_samples_outputs/pna-add-on-miss-frontend.p4 index fdb5115b10..c13b0f2f07 100644 --- a/testdata/p4_16_samples_outputs/pna-add-on-miss-frontend.p4 +++ b/testdata/p4_16_samples_outputs/pna-add-on-miss-frontend.p4 @@ -27,6 +27,7 @@ struct empty_metadata_t { } struct main_metadata_t { + ExpireTimeProfileId_t timeout; } struct headers_t { @@ -60,7 +61,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in } @name("MainControlImpl.add_on_miss_action") action add_on_miss_action() { tmp_0 = 32w0; - add_entry>(action_name = "next_hop", action_params = tmp_0); + add_entry>(action_name = "next_hop", action_params = tmp_0, expire_time_profile_id = user_meta.timeout); } @name("MainControlImpl.ipv4_da") table ipv4_da_0 { key = { @@ -78,7 +79,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in hdr.ipv4.srcAddr = newAddr; } @name("MainControlImpl.add_on_miss_action2") action add_on_miss_action2() { - add_entry, bit<32>>>(action_name = "next_hop", action_params = { 32w0, 32w1234 }); + add_entry, bit<32>>>(action_name = "next_hop2", action_params = { 32w0, 32w1234 }, expire_time_profile_id = user_meta.timeout); } @name("MainControlImpl.ipv4_da2") table ipv4_da2_0 { key = { diff --git a/testdata/p4_16_samples_outputs/pna-add-on-miss-midend.p4 b/testdata/p4_16_samples_outputs/pna-add-on-miss-midend.p4 index 2c7fd56faf..5bd909d8bb 100644 --- a/testdata/p4_16_samples_outputs/pna-add-on-miss-midend.p4 +++ b/testdata/p4_16_samples_outputs/pna-add-on-miss-midend.p4 @@ -27,6 +27,7 @@ struct empty_metadata_t { } struct main_metadata_t { + ExpireTimeProfileId_t timeout; } struct headers_t { @@ -63,7 +64,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in send_to_port(vport); } @name("MainControlImpl.add_on_miss_action") action add_on_miss_action() { - add_entry>(action_name = "next_hop", action_params = 32w0); + add_entry>(action_name = "next_hop", action_params = 32w0, expire_time_profile_id = user_meta.timeout); } @name("MainControlImpl.ipv4_da") table ipv4_da_0 { key = { @@ -81,7 +82,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in hdr.ipv4.srcAddr = newAddr; } @name("MainControlImpl.add_on_miss_action2") action add_on_miss_action2() { - add_entry(action_name = "next_hop", action_params = (tuple_0){f0 = 32w0,f1 = 32w1234}); + add_entry(action_name = "next_hop2", action_params = (tuple_0){f0 = 32w0,f1 = 32w1234}, expire_time_profile_id = user_meta.timeout); } @name("MainControlImpl.ipv4_da2") table ipv4_da2_0 { key = { @@ -103,18 +104,18 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in } control MainDeparserImpl(packet_out pkt, in headers_t hdr, in main_metadata_t user_meta, in pna_main_output_metadata_t ostd) { - @hidden action pnaaddonmiss185() { + @hidden action pnaaddonmiss186() { pkt.emit(hdr.ethernet); pkt.emit(hdr.ipv4); } - @hidden table tbl_pnaaddonmiss185 { + @hidden table tbl_pnaaddonmiss186 { actions = { - pnaaddonmiss185(); + pnaaddonmiss186(); } - const default_action = pnaaddonmiss185(); + const default_action = pnaaddonmiss186(); } apply { - tbl_pnaaddonmiss185.apply(); + tbl_pnaaddonmiss186.apply(); } } diff --git a/testdata/p4_16_samples_outputs/pna-add-on-miss.p4 b/testdata/p4_16_samples_outputs/pna-add-on-miss.p4 index 9f9728a835..4127fdae14 100644 --- a/testdata/p4_16_samples_outputs/pna-add-on-miss.p4 +++ b/testdata/p4_16_samples_outputs/pna-add-on-miss.p4 @@ -31,6 +31,7 @@ typedef bit<32> PacketCounter_t; typedef bit<80> PacketByteCounter_t; const bit<32> NUM_PORTS = 4; struct main_metadata_t { + ExpireTimeProfileId_t timeout; } struct headers_t { @@ -63,7 +64,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in } action add_on_miss_action() { bit<32> tmp = 0; - add_entry(action_name = "next_hop", action_params = tmp); + add_entry(action_name = "next_hop", action_params = tmp, expire_time_profile_id = user_meta.timeout); } table ipv4_da { key = { @@ -81,7 +82,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in hdr.ipv4.srcAddr = newAddr; } action add_on_miss_action2() { - add_entry(action_name = "next_hop", action_params = { 32w0, 32w1234 }); + add_entry(action_name = "next_hop2", action_params = { 32w0, 32w1234 }, expire_time_profile_id = user_meta.timeout); } table ipv4_da2 { key = { diff --git a/testdata/p4_16_samples_outputs/pna-add-on-miss.p4.spec b/testdata/p4_16_samples_outputs/pna-add-on-miss.p4.spec index 51ab47a287..9c2ff3aa8a 100644 --- a/testdata/p4_16_samples_outputs/pna-add-on-miss.p4.spec +++ b/testdata/p4_16_samples_outputs/pna-add-on-miss.p4.spec @@ -29,6 +29,7 @@ struct next_hop_arg_t { struct main_metadata_t { bit<32> pna_main_input_metadata_input_port + bit<8> local_metadata_timeout bit<32> pna_main_output_metadata_output_port bit<32> MainControlT_tmp bit<32> MainControlT_tmp_0 @@ -48,7 +49,7 @@ action next_hop args instanceof next_hop_arg_t { action add_on_miss_action args none { mov m.learnArg 0x0 - learn next_hop m.learnArg + learn next_hop m.learnArg m.local_metadata_timeout return } @@ -61,7 +62,7 @@ action next_hop2 args instanceof next_hop2_arg_t { action add_on_miss_action2 args none { mov m.MainControlT_tmp 0x0 mov m.MainControlT_tmp_0 0x4d2 - learn next_hop m.MainControlT_tmp + learn next_hop2 m.MainControlT_tmp m.local_metadata_timeout return } @@ -75,7 +76,11 @@ learner ipv4_da { } default_action add_on_miss_action args none size 65536 - timeout 120 + timeout { + 60 + 120 + 180 + } } learner ipv4_da2 { @@ -88,7 +93,11 @@ learner ipv4_da2 { } default_action add_on_miss_action2 args none size 65536 - timeout 120 + timeout { + 60 + 120 + 180 + } } apply { diff --git a/testdata/p4_16_samples_outputs/pna-dpdk-parser-state-err-first.p4 b/testdata/p4_16_samples_outputs/pna-dpdk-parser-state-err-first.p4 index a3271eb046..b3b52a06df 100644 --- a/testdata/p4_16_samples_outputs/pna-dpdk-parser-state-err-first.p4 +++ b/testdata/p4_16_samples_outputs/pna-dpdk-parser-state-err-first.p4 @@ -45,9 +45,10 @@ typedef bit<32> PacketCounter_t; typedef bit<80> PacketByteCounter_t; const bit<32> NUM_PORTS = 32w4; struct main_metadata_t { - bit<1> rng_result1; - bit<16> min1; - bit<16> max1; + bit<1> rng_result1; + bit<16> min1; + bit<16> max1; + ExpireTimeProfileId_t timeout; } struct headers_t { @@ -89,7 +90,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in } action add_on_miss_action() { bit<32> tmp = 32w0; - add_entry>(action_name = "next_hop", action_params = tmp); + add_entry>(action_name = "next_hop", action_params = tmp, expire_time_profile_id = user_meta.timeout); } action do_range_checks_1(bit<16> min1, bit<16> max1) { user_meta.rng_result1 = (bit<1>)(min1 <= hdr.tcp.srcPort && hdr.tcp.srcPort <= max1); @@ -110,7 +111,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in hdr.ipv4.srcAddr = newAddr; } action add_on_miss_action2() { - add_entry, bit<32>>>(action_name = "next_hop", action_params = { 32w0, 32w1234 }); + add_entry, bit<32>>>(action_name = "next_hop", action_params = { 32w0, 32w1234 }, expire_time_profile_id = user_meta.timeout); } table ipv4_da2 { key = { diff --git a/testdata/p4_16_samples_outputs/pna-dpdk-parser-state-err-frontend.p4 b/testdata/p4_16_samples_outputs/pna-dpdk-parser-state-err-frontend.p4 index f42d49088c..023745557c 100644 --- a/testdata/p4_16_samples_outputs/pna-dpdk-parser-state-err-frontend.p4 +++ b/testdata/p4_16_samples_outputs/pna-dpdk-parser-state-err-frontend.p4 @@ -41,9 +41,10 @@ struct empty_metadata_t { } struct main_metadata_t { - bit<1> rng_result1; - bit<16> min1; - bit<16> max1; + bit<1> rng_result1; + bit<16> min1; + bit<16> max1; + ExpireTimeProfileId_t timeout; } struct headers_t { @@ -100,7 +101,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in } @name("MainControlImpl.add_on_miss_action") action add_on_miss_action() { tmp_0 = 32w0; - add_entry>(action_name = "next_hop", action_params = tmp_0); + add_entry>(action_name = "next_hop", action_params = tmp_0, expire_time_profile_id = user_meta.timeout); } @name("MainControlImpl.do_range_checks_1") action do_range_checks_2(@name("min1") bit<16> min1_3, @name("max1") bit<16> max1_3) { user_meta.rng_result1 = (bit<1>)(min1_3 <= hdr.tcp.srcPort && hdr.tcp.srcPort <= max1_3); @@ -121,7 +122,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in hdr.ipv4.srcAddr = newAddr; } @name("MainControlImpl.add_on_miss_action2") action add_on_miss_action2() { - add_entry, bit<32>>>(action_name = "next_hop", action_params = { 32w0, 32w1234 }); + add_entry, bit<32>>>(action_name = "next_hop", action_params = { 32w0, 32w1234 }, expire_time_profile_id = user_meta.timeout); } @name("MainControlImpl.ipv4_da2") table ipv4_da2_0 { key = { diff --git a/testdata/p4_16_samples_outputs/pna-dpdk-parser-state-err-midend.p4 b/testdata/p4_16_samples_outputs/pna-dpdk-parser-state-err-midend.p4 index 000e549863..f598b2ad98 100644 --- a/testdata/p4_16_samples_outputs/pna-dpdk-parser-state-err-midend.p4 +++ b/testdata/p4_16_samples_outputs/pna-dpdk-parser-state-err-midend.p4 @@ -41,9 +41,10 @@ struct empty_metadata_t { } struct main_metadata_t { - bit<1> rng_result1; - bit<16> min1; - bit<16> max1; + bit<1> rng_result1; + bit<16> min1; + bit<16> max1; + ExpireTimeProfileId_t timeout; } struct headers_t { @@ -88,7 +89,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in send_to_port(vport); } @name("MainControlImpl.add_on_miss_action") action add_on_miss_action() { - add_entry>(action_name = "next_hop", action_params = 32w0); + add_entry>(action_name = "next_hop", action_params = 32w0, expire_time_profile_id = user_meta.timeout); } @name("MainControlImpl.do_range_checks_1") action do_range_checks_2(@name("min1") bit<16> min1_3, @name("max1") bit<16> max1_3) { user_meta.rng_result1 = (bit<1>)(min1_3 <= hdr.tcp.srcPort && hdr.tcp.srcPort <= max1_3); @@ -109,7 +110,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in hdr.ipv4.srcAddr = newAddr; } @name("MainControlImpl.add_on_miss_action2") action add_on_miss_action2() { - add_entry(action_name = "next_hop", action_params = (tuple_0){f0 = 32w0,f1 = 32w1234}); + add_entry(action_name = "next_hop", action_params = (tuple_0){f0 = 32w0,f1 = 32w1234}, expire_time_profile_id = user_meta.timeout); } @name("MainControlImpl.ipv4_da2") table ipv4_da2_0 { key = { @@ -124,17 +125,17 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in add_on_miss = true; const default_action = add_on_miss_action2(); } - @hidden action pnadpdkparserstateerr190() { + @hidden action pnadpdkparserstateerr191() { user_meta.rng_result1 = (bit<1>)(16w100 <= hdr.tcp.srcPort && hdr.tcp.srcPort <= 16w200); } - @hidden table tbl_pnadpdkparserstateerr190 { + @hidden table tbl_pnadpdkparserstateerr191 { actions = { - pnadpdkparserstateerr190(); + pnadpdkparserstateerr191(); } - const default_action = pnadpdkparserstateerr190(); + const default_action = pnadpdkparserstateerr191(); } apply { - tbl_pnadpdkparserstateerr190.apply(); + tbl_pnadpdkparserstateerr191.apply(); if (hdr.ipv4.isValid()) { ipv4_da_0.apply(); ipv4_da2_0.apply(); @@ -143,18 +144,18 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in } control MainDeparserImpl(packet_out pkt, in headers_t hdr, in main_metadata_t user_meta, in pna_main_output_metadata_t ostd) { - @hidden action pnadpdkparserstateerr205() { + @hidden action pnadpdkparserstateerr206() { pkt.emit(hdr.ethernet); pkt.emit(hdr.ipv4); } - @hidden table tbl_pnadpdkparserstateerr205 { + @hidden table tbl_pnadpdkparserstateerr206 { actions = { - pnadpdkparserstateerr205(); + pnadpdkparserstateerr206(); } - const default_action = pnadpdkparserstateerr205(); + const default_action = pnadpdkparserstateerr206(); } apply { - tbl_pnadpdkparserstateerr205.apply(); + tbl_pnadpdkparserstateerr206.apply(); } } diff --git a/testdata/p4_16_samples_outputs/pna-dpdk-parser-state-err.p4 b/testdata/p4_16_samples_outputs/pna-dpdk-parser-state-err.p4 index aaf532db6a..3b5fc7522a 100644 --- a/testdata/p4_16_samples_outputs/pna-dpdk-parser-state-err.p4 +++ b/testdata/p4_16_samples_outputs/pna-dpdk-parser-state-err.p4 @@ -45,9 +45,10 @@ typedef bit<32> PacketCounter_t; typedef bit<80> PacketByteCounter_t; const bit<32> NUM_PORTS = 4; struct main_metadata_t { - bit<1> rng_result1; - bit<16> min1; - bit<16> max1; + bit<1> rng_result1; + bit<16> min1; + bit<16> max1; + ExpireTimeProfileId_t timeout; } struct headers_t { @@ -89,7 +90,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in } action add_on_miss_action() { bit<32> tmp = 0; - add_entry(action_name = "next_hop", action_params = tmp); + add_entry(action_name = "next_hop", action_params = tmp, expire_time_profile_id = user_meta.timeout); } action do_range_checks_1(bit<16> min1, bit<16> max1) { user_meta.rng_result1 = (bit<1>)(min1 <= hdr.tcp.srcPort && hdr.tcp.srcPort <= max1); @@ -110,7 +111,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in hdr.ipv4.srcAddr = newAddr; } action add_on_miss_action2() { - add_entry(action_name = "next_hop", action_params = { 32w0, 32w1234 }); + add_entry(action_name = "next_hop", action_params = { 32w0, 32w1234 }, expire_time_profile_id = user_meta.timeout); } table ipv4_da2 { key = { diff --git a/testdata/p4_16_samples_outputs/pna-dpdk-parser-state-err.p4.spec b/testdata/p4_16_samples_outputs/pna-dpdk-parser-state-err.p4.spec index 7228cd5256..80a41f2d0d 100644 --- a/testdata/p4_16_samples_outputs/pna-dpdk-parser-state-err.p4.spec +++ b/testdata/p4_16_samples_outputs/pna-dpdk-parser-state-err.p4.spec @@ -53,6 +53,7 @@ struct main_metadata_t { bit<32> local_metadata_rng_result1 bit<16> local_metadata_min1 bit<16> local_metadata_max1 + bit<8> local_metadata_timeout bit<32> pna_main_output_metadata_output_port bit<32> MainParserT_parser_tmp bit<32> MainControlT_tmp @@ -87,7 +88,7 @@ action next_hop args instanceof next_hop_arg_t { action add_on_miss_action args none { mov m.learnArg 0x0 - learn next_hop m.learnArg + learn next_hop m.learnArg m.local_metadata_timeout return } @@ -110,7 +111,7 @@ action next_hop2 args instanceof next_hop2_arg_t { action add_on_miss_action2 args none { mov m.MainControlT_tmp 0x0 mov m.MainControlT_tmp_0 0x4d2 - learn next_hop m.MainControlT_tmp + learn next_hop m.MainControlT_tmp m.local_metadata_timeout return } @@ -124,7 +125,11 @@ learner ipv4_da { } default_action add_on_miss_action args none size 65536 - timeout 120 + timeout { + 60 + 120 + 180 + } } learner ipv4_da2 { @@ -139,7 +144,11 @@ learner ipv4_da2 { } default_action add_on_miss_action2 args none size 65536 - timeout 120 + timeout { + 60 + 120 + 180 + } } apply { diff --git a/testdata/p4_16_samples_outputs/pna-dpdk-table-key-use-annon-first.p4 b/testdata/p4_16_samples_outputs/pna-dpdk-table-key-use-annon-first.p4 index 2227c736e9..59a1cc9080 100644 --- a/testdata/p4_16_samples_outputs/pna-dpdk-table-key-use-annon-first.p4 +++ b/testdata/p4_16_samples_outputs/pna-dpdk-table-key-use-annon-first.p4 @@ -31,7 +31,8 @@ typedef bit<32> PacketCounter_t; typedef bit<80> PacketByteCounter_t; const bit<32> NUM_PORTS = 32w4; struct main_metadata_t { - bit<32> key; + bit<32> key; + ExpireTimeProfileId_t timeout; } struct headers_t { @@ -64,7 +65,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in } action add_on_miss_action() { bit<32> tmp = 32w0; - add_entry>(action_name = "next_hop", action_params = tmp); + add_entry>(action_name = "next_hop", action_params = tmp, expire_time_profile_id = user_meta.timeout); } table ipv4_da { key = { @@ -82,7 +83,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in hdr.ipv4.srcAddr = newAddr; } action add_on_miss_action2() { - add_entry, bit<32>>>(action_name = "next_hop", action_params = { 32w0, 32w1234 }); + add_entry, bit<32>>>(action_name = "next_hop", action_params = { 32w0, 32w1234 }, expire_time_profile_id = user_meta.timeout); } table ipv4_da2 { key = { diff --git a/testdata/p4_16_samples_outputs/pna-dpdk-table-key-use-annon-frontend.p4 b/testdata/p4_16_samples_outputs/pna-dpdk-table-key-use-annon-frontend.p4 index 2c2e4ad20e..27e9a9d2fc 100644 --- a/testdata/p4_16_samples_outputs/pna-dpdk-table-key-use-annon-frontend.p4 +++ b/testdata/p4_16_samples_outputs/pna-dpdk-table-key-use-annon-frontend.p4 @@ -27,7 +27,8 @@ struct empty_metadata_t { } struct main_metadata_t { - bit<32> key; + bit<32> key; + ExpireTimeProfileId_t timeout; } struct headers_t { @@ -61,7 +62,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in } @name("MainControlImpl.add_on_miss_action") action add_on_miss_action() { tmp_0 = 32w0; - add_entry>(action_name = "next_hop", action_params = tmp_0); + add_entry>(action_name = "next_hop", action_params = tmp_0, expire_time_profile_id = user_meta.timeout); } @name("MainControlImpl.ipv4_da") table ipv4_da_0 { key = { @@ -79,7 +80,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in hdr.ipv4.srcAddr = newAddr; } @name("MainControlImpl.add_on_miss_action2") action add_on_miss_action2() { - add_entry, bit<32>>>(action_name = "next_hop", action_params = { 32w0, 32w1234 }); + add_entry, bit<32>>>(action_name = "next_hop", action_params = { 32w0, 32w1234 }, expire_time_profile_id = user_meta.timeout); } @name("MainControlImpl.ipv4_da2") table ipv4_da2_0 { key = { diff --git a/testdata/p4_16_samples_outputs/pna-dpdk-table-key-use-annon-midend.p4 b/testdata/p4_16_samples_outputs/pna-dpdk-table-key-use-annon-midend.p4 index 919d7c8dd2..120b821df9 100644 --- a/testdata/p4_16_samples_outputs/pna-dpdk-table-key-use-annon-midend.p4 +++ b/testdata/p4_16_samples_outputs/pna-dpdk-table-key-use-annon-midend.p4 @@ -27,7 +27,8 @@ struct empty_metadata_t { } struct main_metadata_t { - bit<32> key; + bit<32> key; + ExpireTimeProfileId_t timeout; } struct headers_t { @@ -64,7 +65,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in send_to_port(vport); } @name("MainControlImpl.add_on_miss_action") action add_on_miss_action() { - add_entry>(action_name = "next_hop", action_params = 32w0); + add_entry>(action_name = "next_hop", action_params = 32w0, expire_time_profile_id = user_meta.timeout); } @name("MainControlImpl.ipv4_da") table ipv4_da_0 { key = { @@ -82,7 +83,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in hdr.ipv4.srcAddr = newAddr; } @name("MainControlImpl.add_on_miss_action2") action add_on_miss_action2() { - add_entry(action_name = "next_hop", action_params = (tuple_0){f0 = 32w0,f1 = 32w1234}); + add_entry(action_name = "next_hop", action_params = (tuple_0){f0 = 32w0,f1 = 32w1234}, expire_time_profile_id = user_meta.timeout); } @name("MainControlImpl.ipv4_da2") table ipv4_da2_0 { key = { diff --git a/testdata/p4_16_samples_outputs/pna-dpdk-table-key-use-annon.p4 b/testdata/p4_16_samples_outputs/pna-dpdk-table-key-use-annon.p4 index 59423ed786..c8a05ebea8 100644 --- a/testdata/p4_16_samples_outputs/pna-dpdk-table-key-use-annon.p4 +++ b/testdata/p4_16_samples_outputs/pna-dpdk-table-key-use-annon.p4 @@ -31,7 +31,8 @@ typedef bit<32> PacketCounter_t; typedef bit<80> PacketByteCounter_t; const bit<32> NUM_PORTS = 4; struct main_metadata_t { - bit<32> key; + bit<32> key; + ExpireTimeProfileId_t timeout; } struct headers_t { @@ -64,7 +65,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in } action add_on_miss_action() { bit<32> tmp = 0; - add_entry(action_name = "next_hop", action_params = tmp); + add_entry(action_name = "next_hop", action_params = tmp, expire_time_profile_id = user_meta.timeout); } table ipv4_da { key = { @@ -82,7 +83,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in hdr.ipv4.srcAddr = newAddr; } action add_on_miss_action2() { - add_entry(action_name = "next_hop", action_params = { 32w0, 32w1234 }); + add_entry(action_name = "next_hop", action_params = { 32w0, 32w1234 }, expire_time_profile_id = user_meta.timeout); } table ipv4_da2 { key = { diff --git a/testdata/p4_16_samples_outputs/pna-dpdk-table-key-use-annon.p4.spec b/testdata/p4_16_samples_outputs/pna-dpdk-table-key-use-annon.p4.spec index da7d00e63f..8387341e4b 100644 --- a/testdata/p4_16_samples_outputs/pna-dpdk-table-key-use-annon.p4.spec +++ b/testdata/p4_16_samples_outputs/pna-dpdk-table-key-use-annon.p4.spec @@ -30,6 +30,7 @@ struct next_hop_arg_t { struct main_metadata_t { bit<32> pna_main_input_metadata_input_port bit<32> local_metadata_key + bit<8> local_metadata_timeout bit<32> pna_main_output_metadata_output_port bit<32> MainControlT_tmp bit<32> MainControlT_tmp_0 @@ -49,7 +50,7 @@ action next_hop args instanceof next_hop_arg_t { action add_on_miss_action args none { mov m.learnArg 0x0 - learn next_hop m.learnArg + learn next_hop m.learnArg m.local_metadata_timeout return } @@ -62,7 +63,7 @@ action next_hop2 args instanceof next_hop2_arg_t { action add_on_miss_action2 args none { mov m.MainControlT_tmp 0x0 mov m.MainControlT_tmp_0 0x4d2 - learn next_hop m.MainControlT_tmp + learn next_hop m.MainControlT_tmp m.local_metadata_timeout return } @@ -76,7 +77,11 @@ learner ipv4_da { } default_action add_on_miss_action args none size 65536 - timeout 120 + timeout { + 60 + 120 + 180 + } } learner ipv4_da2 { @@ -89,7 +94,11 @@ learner ipv4_da2 { } default_action add_on_miss_action2 args none size 65536 - timeout 120 + timeout { + 60 + 120 + 180 + } } apply { diff --git a/testdata/p4_16_samples_outputs/pna-example-tcp-connection-tracking.p4-error b/testdata/p4_16_samples_outputs/pna-example-tcp-connection-tracking.p4-error new file mode 100644 index 0000000000..e21173d680 --- /dev/null +++ b/testdata/p4_16_samples_outputs/pna-example-tcp-connection-tracking.p4-error @@ -0,0 +1,10 @@ +pna-example-tcp-connection-tracking.p4(206): [--Wwarn=uninitialized_use] warning: update_aging_info may be uninitialized + if (update_aging_info) { + ^^^^^^^^^^^^^^^^^ +pna-example-tcp-connection-tracking.p4(208): [--Wwarn=uninitialized_use] warning: new_expire_time_profile_id may not be completely initialized + set_entry_expire_time(new_expire_time_profile_id); + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +pna-example-tcp-connection-tracking.p4(240): [--Wwarn=uninitialized_use] warning: new_expire_time_profile_id may not be completely initialized + expire_time_profile_id = new_expire_time_profile_id); + ^^^^^^^^^^^^^^^^^^^^^^^^^^ +[--Wwarn=mismatch] warning: Mismatched header/metadata struct for key elements in table ct_tcp_table. Copying all match fields to metadata diff --git a/testdata/p4_16_samples_outputs/pna-example-tcp-connection-tracking.p4.bfrt.json b/testdata/p4_16_samples_outputs/pna-example-tcp-connection-tracking.p4.bfrt.json new file mode 100644 index 0000000000..246cce5389 --- /dev/null +++ b/testdata/p4_16_samples_outputs/pna-example-tcp-connection-tracking.p4.bfrt.json @@ -0,0 +1,164 @@ +{ + "schema_version" : "1.0.0", + "tables" : [ + { + "name" : "pipe.MainControlImpl.set_ct_options", + "id" : 48249440, + "table_type" : "MatchAction_Direct", + "size" : 1024, + "annotations" : [], + "depends_on" : [], + "has_const_default_action" : true, + "key" : [ + { + "id" : 1, + "name" : "hdr.tcp.flags", + "repeated" : false, + "annotations" : [], + "mandatory" : false, + "match_type" : "Ternary", + "type" : { + "type" : "bytes", + "width" : 8 + } + }, + { + "id" : 65537, + "name" : "$MATCH_PRIORITY", + "repeated" : false, + "annotations" : [], + "mandatory" : false, + "match_type" : "Exact", + "type" : { + "type" : "uint32" + } + } + ], + "action_specs" : [ + { + "id" : 23677896, + "name" : "MainControlImpl.tcp_syn_packet", + "action_scope" : "TableAndDefault", + "annotations" : [], + "data" : [] + }, + { + "id" : 27056431, + "name" : "MainControlImpl.tcp_fin_or_rst_packet", + "action_scope" : "TableAndDefault", + "annotations" : [], + "data" : [] + }, + { + "id" : 23970644, + "name" : "MainControlImpl.tcp_other_packets", + "action_scope" : "TableAndDefault", + "annotations" : [], + "data" : [] + } + ], + "data" : [], + "supported_operations" : [], + "attributes" : ["EntryScope", "ConstTable"] + }, + { + "name" : "pipe.MainControlImpl.ct_tcp_table", + "id" : 35731637, + "table_type" : "MatchAction_Direct", + "size" : 1024, + "annotations" : [], + "depends_on" : [], + "has_const_default_action" : true, + "key" : [ + { + "id" : 1, + "name" : "ipv4_addr_0", + "repeated" : false, + "annotations" : [], + "mandatory" : false, + "match_type" : "Exact", + "type" : { + "type" : "bytes", + "width" : 32 + } + }, + { + "id" : 2, + "name" : "ipv4_addr_1", + "repeated" : false, + "annotations" : [], + "mandatory" : false, + "match_type" : "Exact", + "type" : { + "type" : "bytes", + "width" : 32 + } + }, + { + "id" : 3, + "name" : "hdr.ipv4.protocol", + "repeated" : false, + "annotations" : [], + "mandatory" : false, + "match_type" : "Exact", + "type" : { + "type" : "bytes", + "width" : 8 + } + }, + { + "id" : 4, + "name" : "tcp_port_0", + "repeated" : false, + "annotations" : [], + "mandatory" : false, + "match_type" : "Exact", + "type" : { + "type" : "bytes", + "width" : 16 + } + }, + { + "id" : 5, + "name" : "tcp_port_1", + "repeated" : false, + "annotations" : [], + "mandatory" : false, + "match_type" : "Exact", + "type" : { + "type" : "bytes", + "width" : 16 + } + } + ], + "action_specs" : [ + { + "id" : 17749373, + "name" : "MainControlImpl.ct_tcp_table_hit", + "action_scope" : "TableOnly", + "annotations" : [ + { + "name" : "@tableonly" + } + ], + "data" : [] + }, + { + "id" : 22853387, + "name" : "MainControlImpl.ct_tcp_table_miss", + "action_scope" : "DefaultOnly", + "annotations" : [ + { + "name" : "@defaultonly" + } + ], + "data" : [] + } + ], + "data" : [], + "supported_operations" : [], + "attributes" : ["EntryScope"] + } + ], + "learn_filters" : [] +} \ No newline at end of file diff --git a/testdata/p4_16_samples_outputs/pna-example-tcp-connection-tracking.p4.spec b/testdata/p4_16_samples_outputs/pna-example-tcp-connection-tracking.p4.spec new file mode 100644 index 0000000000..b88fa0bd4a --- /dev/null +++ b/testdata/p4_16_samples_outputs/pna-example-tcp-connection-tracking.p4.spec @@ -0,0 +1,195 @@ + +struct ethernet_t { + bit<48> dstAddr + bit<48> srcAddr + bit<16> etherType +} + +struct ipv4_t { + bit<8> version_ihl + bit<8> diffserv + bit<16> totalLength + bit<16> identification + bit<16> flags_fragOffset + bit<8> ttl + bit<8> protocol + bit<16> hdrChecksum + bit<32> srcAddr + bit<32> dstAddr +} + +struct tcp_t { + bit<16> srcPort + bit<16> dstPort + bit<32> seqNo + bit<32> ackNo + bit<8> dataOffset_res + bit<8> flags + bit<16> window + bit<16> checksum + bit<16> urgentPtr +} + +struct metadata_t { + bit<32> pna_main_input_metadata_direction + bit<32> pna_main_input_metadata_input_port + bit<32> pna_main_output_metadata_output_port + bit<8> MainControlImpl_ct_tcp_table_ipv4_protocol + bit<8> MainControlT_do_add_on_miss + bit<8> MainControlT_update_aging_info + bit<8> MainControlT_update_expire_time + bit<8> MainControlT_new_expire_time_profile_id + bit<32> MainControlT_key + bit<32> MainControlT_key_0 + bit<16> MainControlT_key_1 + bit<16> MainControlT_key_2 + bit<32> reg_read_tmp + bit<32> left_shift_tmp +} +metadata instanceof metadata_t + +header eth instanceof ethernet_t +header ipv4 instanceof ipv4_t +header tcp instanceof tcp_t + +regarray network_port_mask size 0x1 initval 0 + +action tcp_syn_packet args none { + mov m.MainControlT_do_add_on_miss 1 + mov m.MainControlT_update_aging_info 1 + mov m.MainControlT_update_expire_time 1 + mov m.MainControlT_new_expire_time_profile_id 0x1 + return +} + +action tcp_fin_or_rst_packet args none { + mov m.MainControlT_update_aging_info 1 + mov m.MainControlT_update_expire_time 1 + mov m.MainControlT_new_expire_time_profile_id 0x0 + return +} + +action tcp_other_packets args none { + mov m.MainControlT_update_aging_info 1 + mov m.MainControlT_update_expire_time 1 + mov m.MainControlT_new_expire_time_profile_id 0x2 + return +} + +action ct_tcp_table_hit args none { + jmpneq LABEL_END_5 m.MainControlT_update_aging_info 0x1 + jmpneq LABEL_FALSE_2 m.MainControlT_update_expire_time 0x1 + rearm m.MainControlT_new_expire_time_profile_id + jmp LABEL_END_5 + LABEL_FALSE_2 : rearm + LABEL_END_5 : return +} + +action ct_tcp_table_miss args none { + jmpneq LABEL_FALSE_3 m.MainControlT_do_add_on_miss 0x1 + learn ct_tcp_table_hit m.MainControlT_new_expire_time_profile_id + jmp LABEL_END_7 + LABEL_FALSE_3 : drop + LABEL_END_7 : return +} + +table set_ct_options { + key { + h.tcp.flags wildcard + } + actions { + tcp_syn_packet + tcp_fin_or_rst_packet + tcp_other_packets + } + default_action tcp_other_packets args none const + size 0x10000 +} + + +learner ct_tcp_table { + key { + m.MainControlT_key + m.MainControlT_key_0 + m.MainControlImpl_ct_tcp_table_ipv4_protocol + m.MainControlT_key_1 + m.MainControlT_key_2 + } + actions { + ct_tcp_table_hit @tableonly + ct_tcp_table_miss @defaultonly + } + default_action ct_tcp_table_miss args none + size 65536 + timeout { + 60 + 120 + 180 + } +} + +apply { + rx m.pna_main_input_metadata_input_port + extract h.eth + jmpeq MAINPARSERIMPL_PARSE_IPV4 h.eth.etherType 0x800 + jmp MAINPARSERIMPL_ACCEPT + MAINPARSERIMPL_PARSE_IPV4 : extract h.ipv4 + jmpeq MAINPARSERIMPL_PARSE_TCP h.ipv4.protocol 0x6 + jmp MAINPARSERIMPL_ACCEPT + MAINPARSERIMPL_PARSE_TCP : extract h.tcp + MAINPARSERIMPL_ACCEPT : mov m.MainControlT_do_add_on_miss 0 + mov m.MainControlT_update_expire_time 0 + regrd m.reg_read_tmp network_port_mask 0x0 + mov m.left_shift_tmp 0x1 + shl m.left_shift_tmp m.pna_main_input_metadata_input_port + mov m.pna_main_input_metadata_direction m.reg_read_tmp + and m.pna_main_input_metadata_direction m.left_shift_tmp + jmpneq LABEL_END m.pna_main_input_metadata_direction 0x1 + jmpnv LABEL_END h.ipv4 + jmpnv LABEL_END h.tcp + table set_ct_options + LABEL_END : jmpnv LABEL_END_0 h.ipv4 + jmpnv LABEL_END_0 h.tcp + regrd m.reg_read_tmp network_port_mask 0x0 + mov m.left_shift_tmp 0x1 + shl m.left_shift_tmp m.pna_main_input_metadata_input_port + mov m.pna_main_input_metadata_direction m.reg_read_tmp + and m.pna_main_input_metadata_direction m.left_shift_tmp + jmpeq LABEL_TRUE_1 m.pna_main_input_metadata_direction 0x0 + mov m.MainControlT_key h.ipv4.dstAddr + jmp LABEL_END_1 + LABEL_TRUE_1 : mov m.MainControlT_key h.ipv4.srcAddr + LABEL_END_1 : regrd m.reg_read_tmp network_port_mask 0x0 + mov m.left_shift_tmp 0x1 + shl m.left_shift_tmp m.pna_main_input_metadata_input_port + mov m.pna_main_input_metadata_direction m.reg_read_tmp + and m.pna_main_input_metadata_direction m.left_shift_tmp + jmpeq LABEL_TRUE_2 m.pna_main_input_metadata_direction 0x0 + mov m.MainControlT_key_0 h.ipv4.srcAddr + jmp LABEL_END_2 + LABEL_TRUE_2 : mov m.MainControlT_key_0 h.ipv4.dstAddr + LABEL_END_2 : regrd m.reg_read_tmp network_port_mask 0x0 + mov m.left_shift_tmp 0x1 + shl m.left_shift_tmp m.pna_main_input_metadata_input_port + mov m.pna_main_input_metadata_direction m.reg_read_tmp + and m.pna_main_input_metadata_direction m.left_shift_tmp + jmpeq LABEL_TRUE_3 m.pna_main_input_metadata_direction 0x0 + mov m.MainControlT_key_1 h.tcp.dstPort + jmp LABEL_END_3 + LABEL_TRUE_3 : mov m.MainControlT_key_1 h.tcp.srcPort + LABEL_END_3 : regrd m.reg_read_tmp network_port_mask 0x0 + mov m.left_shift_tmp 0x1 + shl m.left_shift_tmp m.pna_main_input_metadata_input_port + mov m.pna_main_input_metadata_direction m.reg_read_tmp + and m.pna_main_input_metadata_direction m.left_shift_tmp + jmpeq LABEL_TRUE_4 m.pna_main_input_metadata_direction 0x0 + mov m.MainControlT_key_2 h.tcp.srcPort + jmp LABEL_END_4 + LABEL_TRUE_4 : mov m.MainControlT_key_2 h.tcp.dstPort + LABEL_END_4 : mov m.MainControlImpl_ct_tcp_table_ipv4_protocol h.ipv4.protocol + table ct_tcp_table + LABEL_END_0 : emit h.eth + tx m.pna_main_output_metadata_output_port +} + + diff --git a/testdata/p4_16_samples_outputs/pna-mux-dismantle-first.p4 b/testdata/p4_16_samples_outputs/pna-mux-dismantle-first.p4 index 93b5c90656..e0bf3a4567 100644 --- a/testdata/p4_16_samples_outputs/pna-mux-dismantle-first.p4 +++ b/testdata/p4_16_samples_outputs/pna-mux-dismantle-first.p4 @@ -45,9 +45,10 @@ typedef bit<32> PacketCounter_t; typedef bit<80> PacketByteCounter_t; const bit<32> NUM_PORTS = 32w4; struct main_metadata_t { - bit<1> rng_result1; - bit<1> val1; - bit<1> val2; + bit<1> rng_result1; + bit<1> val1; + bit<1> val2; + ExpireTimeProfileId_t timeout; } struct headers_t { @@ -87,7 +88,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in } action add_on_miss_action() { bit<32> tmp = 32w0; - add_entry>(action_name = "next_hop", action_params = tmp); + add_entry>(action_name = "next_hop", action_params = tmp, expire_time_profile_id = user_meta.timeout); } action do_range_checks_1(bit<16> min1, bit<16> max1) { user_meta.rng_result1 = (min1 <= hdr.tcp.srcPort && hdr.tcp.srcPort <= max1 ? (16w50 <= hdr.tcp.srcPort && hdr.tcp.srcPort <= 16w100 ? user_meta.val1 : user_meta.val2) : user_meta.val1); @@ -108,7 +109,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in hdr.ipv4.srcAddr = newAddr; } action add_on_miss_action2() { - add_entry, bit<32>>>(action_name = "next_hop", action_params = { 32w0, 32w1234 }); + add_entry, bit<32>>>(action_name = "next_hop", action_params = { 32w0, 32w1234 }, expire_time_profile_id = user_meta.timeout); } table ipv4_da2 { key = { diff --git a/testdata/p4_16_samples_outputs/pna-mux-dismantle-frontend.p4 b/testdata/p4_16_samples_outputs/pna-mux-dismantle-frontend.p4 index d3689de8de..90db0ed772 100644 --- a/testdata/p4_16_samples_outputs/pna-mux-dismantle-frontend.p4 +++ b/testdata/p4_16_samples_outputs/pna-mux-dismantle-frontend.p4 @@ -41,9 +41,10 @@ struct empty_metadata_t { } struct main_metadata_t { - bit<1> rng_result1; - bit<1> val1; - bit<1> val2; + bit<1> rng_result1; + bit<1> val1; + bit<1> val2; + ExpireTimeProfileId_t timeout; } struct headers_t { @@ -100,7 +101,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in } @name("MainControlImpl.add_on_miss_action") action add_on_miss_action() { tmp = 32w0; - add_entry>(action_name = "next_hop", action_params = tmp); + add_entry>(action_name = "next_hop", action_params = tmp, expire_time_profile_id = user_meta.timeout); } @name("MainControlImpl.do_range_checks_1") action do_range_checks_2(@name("min1") bit<16> min1_3, @name("max1") bit<16> max1_3) { if (min1_3 <= hdr.tcp.srcPort && hdr.tcp.srcPort <= max1_3) { @@ -131,7 +132,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in hdr.ipv4.srcAddr = newAddr; } @name("MainControlImpl.add_on_miss_action2") action add_on_miss_action2() { - add_entry, bit<32>>>(action_name = "next_hop", action_params = { 32w0, 32w1234 }); + add_entry, bit<32>>>(action_name = "next_hop", action_params = { 32w0, 32w1234 }, expire_time_profile_id = user_meta.timeout); } @name("MainControlImpl.ipv4_da2") table ipv4_da2_0 { key = { diff --git a/testdata/p4_16_samples_outputs/pna-mux-dismantle-midend.p4 b/testdata/p4_16_samples_outputs/pna-mux-dismantle-midend.p4 index 4098fb1d1b..2d07318221 100644 --- a/testdata/p4_16_samples_outputs/pna-mux-dismantle-midend.p4 +++ b/testdata/p4_16_samples_outputs/pna-mux-dismantle-midend.p4 @@ -41,9 +41,10 @@ struct empty_metadata_t { } struct main_metadata_t { - bit<1> rng_result1; - bit<1> val1; - bit<1> val2; + bit<1> rng_result1; + bit<1> val1; + bit<1> val2; + ExpireTimeProfileId_t timeout; } struct headers_t { @@ -87,7 +88,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in send_to_port(vport); } @name("MainControlImpl.add_on_miss_action") action add_on_miss_action() { - add_entry>(action_name = "next_hop", action_params = 32w0); + add_entry>(action_name = "next_hop", action_params = 32w0, expire_time_profile_id = user_meta.timeout); } @name("MainControlImpl.do_range_checks_1") action do_range_checks_2(@name("min1") bit<16> min1_3, @name("max1") bit<16> max1_3) { tmp_1 = (min1_3 <= hdr.tcp.srcPort && hdr.tcp.srcPort <= max1_3 ? (16w50 <= hdr.tcp.srcPort && hdr.tcp.srcPort <= 16w100 ? user_meta.val1 : user_meta.val2) : tmp_1); @@ -109,7 +110,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in hdr.ipv4.srcAddr = newAddr; } @name("MainControlImpl.add_on_miss_action2") action add_on_miss_action2() { - add_entry(action_name = "next_hop", action_params = (tuple_0){f0 = 32w0,f1 = 32w1234}); + add_entry(action_name = "next_hop", action_params = (tuple_0){f0 = 32w0,f1 = 32w1234}, expire_time_profile_id = user_meta.timeout); } @name("MainControlImpl.ipv4_da2") table ipv4_da2_0 { key = { @@ -124,17 +125,17 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in add_on_miss = true; const default_action = add_on_miss_action2(); } - @hidden action pnamuxdismantle188() { + @hidden action pnamuxdismantle189() { user_meta.rng_result1 = (bit<1>)(16w100 <= hdr.tcp.srcPort && hdr.tcp.srcPort <= 16w200); } - @hidden table tbl_pnamuxdismantle188 { + @hidden table tbl_pnamuxdismantle189 { actions = { - pnamuxdismantle188(); + pnamuxdismantle189(); } - const default_action = pnamuxdismantle188(); + const default_action = pnamuxdismantle189(); } apply { - tbl_pnamuxdismantle188.apply(); + tbl_pnamuxdismantle189.apply(); if (hdr.ipv4.isValid()) { ipv4_da_0.apply(); ipv4_da2_0.apply(); @@ -143,18 +144,18 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in } control MainDeparserImpl(packet_out pkt, in headers_t hdr, in main_metadata_t user_meta, in pna_main_output_metadata_t ostd) { - @hidden action pnamuxdismantle203() { + @hidden action pnamuxdismantle204() { pkt.emit(hdr.ethernet); pkt.emit(hdr.ipv4); } - @hidden table tbl_pnamuxdismantle203 { + @hidden table tbl_pnamuxdismantle204 { actions = { - pnamuxdismantle203(); + pnamuxdismantle204(); } - const default_action = pnamuxdismantle203(); + const default_action = pnamuxdismantle204(); } apply { - tbl_pnamuxdismantle203.apply(); + tbl_pnamuxdismantle204.apply(); } } diff --git a/testdata/p4_16_samples_outputs/pna-mux-dismantle.p4 b/testdata/p4_16_samples_outputs/pna-mux-dismantle.p4 index 4571395c5e..6cd36b9daa 100644 --- a/testdata/p4_16_samples_outputs/pna-mux-dismantle.p4 +++ b/testdata/p4_16_samples_outputs/pna-mux-dismantle.p4 @@ -45,9 +45,10 @@ typedef bit<32> PacketCounter_t; typedef bit<80> PacketByteCounter_t; const bit<32> NUM_PORTS = 4; struct main_metadata_t { - bit<1> rng_result1; - bit<1> val1; - bit<1> val2; + bit<1> rng_result1; + bit<1> val1; + bit<1> val2; + ExpireTimeProfileId_t timeout; } struct headers_t { @@ -87,7 +88,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in } action add_on_miss_action() { bit<32> tmp = 0; - add_entry(action_name = "next_hop", action_params = tmp); + add_entry(action_name = "next_hop", action_params = tmp, expire_time_profile_id = user_meta.timeout); } action do_range_checks_1(bit<16> min1, bit<16> max1) { user_meta.rng_result1 = (min1 <= hdr.tcp.srcPort && hdr.tcp.srcPort <= max1 ? (16w50 <= hdr.tcp.srcPort && hdr.tcp.srcPort <= 16w100 ? user_meta.val1 : user_meta.val2) : user_meta.val1); @@ -108,7 +109,7 @@ control MainControlImpl(inout headers_t hdr, inout main_metadata_t user_meta, in hdr.ipv4.srcAddr = newAddr; } action add_on_miss_action2() { - add_entry(action_name = "next_hop", action_params = { 32w0, 32w1234 }); + add_entry(action_name = "next_hop", action_params = { 32w0, 32w1234 }, expire_time_profile_id = user_meta.timeout); } table ipv4_da2 { key = { diff --git a/testdata/p4_16_samples_outputs/pna-mux-dismantle.p4.spec b/testdata/p4_16_samples_outputs/pna-mux-dismantle.p4.spec index 832884e711..8cb8dabfd3 100644 --- a/testdata/p4_16_samples_outputs/pna-mux-dismantle.p4.spec +++ b/testdata/p4_16_samples_outputs/pna-mux-dismantle.p4.spec @@ -53,6 +53,7 @@ struct main_metadata_t { bit<32> local_metadata_rng_result1 bit<32> local_metadata_val1 bit<32> local_metadata_val2 + bit<8> local_metadata_timeout bit<32> pna_main_output_metadata_output_port bit<32> MainControlT_tmp bit<32> MainControlT_tmp_0 @@ -87,7 +88,7 @@ action next_hop args instanceof next_hop_arg_t { action add_on_miss_action args none { mov m.learnArg 0x0 - learn next_hop m.learnArg + learn next_hop m.learnArg m.local_metadata_timeout return } @@ -115,7 +116,7 @@ action next_hop2 args instanceof next_hop2_arg_t { action add_on_miss_action2 args none { mov m.MainControlT_tmp 0x0 mov m.MainControlT_tmp_0 0x4d2 - learn next_hop m.MainControlT_tmp + learn next_hop m.MainControlT_tmp m.local_metadata_timeout return } @@ -129,7 +130,11 @@ learner ipv4_da { } default_action add_on_miss_action args none size 65536 - timeout 120 + timeout { + 60 + 120 + 180 + } } learner ipv4_da2 { @@ -144,7 +149,11 @@ learner ipv4_da2 { } default_action add_on_miss_action2 args none size 65536 - timeout 120 + timeout { + 60 + 120 + 180 + } } apply {