Skip to content

Commit

Permalink
Handle p4-14 intrinsic_metadata (#1704)
Browse files Browse the repository at this point in the history
* Handle p4-14 intrinsic_metadata
  • Loading branch information
Mihai Budiu authored Apr 25, 2019
1 parent bd6f231 commit ae6fb22
Show file tree
Hide file tree
Showing 97 changed files with 4,182 additions and 2,697 deletions.
4 changes: 2 additions & 2 deletions backends/ebpf/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ const IR::ToplevelBlock* MidEnd::run(EbpfOptions& options, const IR::P4Program*
new P4::OrPolicy(
new P4::IsValid(&refMap, &typeMap),
new P4::IsLikeLeftValue())),
new P4::RemoveExits(&refMap, &typeMap),
new P4::RemoveExits(&refMap, &typeMap),
new P4::ConstantFolding(&refMap, &typeMap),
new P4::SimplifySelectCases(&refMap, &typeMap, false), // accept non-constant keysets
new P4::SimplifySelectCases(&refMap, &typeMap, false), // accept non-constant keysets
new P4::HandleNoMatch(&refMap),
new P4::SimplifyParsers(&refMap),
new P4::StrengthReduction(&refMap, &typeMap),
Expand Down
114 changes: 110 additions & 4 deletions frontends/p4/fromv1.0/converters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1223,9 +1223,9 @@ class InsertCompilerGeneratedStartState: public Transform {
}
};

// Handle @packet_entry pragma in P4-14. A P4-14 program may be extended to
// support multiple entry points to the parser. This feature does not comply
// with P4-14 specification, but it is useful in certain use cases.
/// Handle @packet_entry pragma in P4-14. A P4-14 program may be extended to
/// support multiple entry points to the parser. This feature does not comply
/// with P4-14 specification, but it is useful in certain use cases.
class FixMultiEntryPoint : public PassManager {
public:
explicit FixMultiEntryPoint(ProgramStructure* structure) {
Expand All @@ -1235,9 +1235,114 @@ class FixMultiEntryPoint : public PassManager {
}
};

} // namespace
/**
If the user metadata structure has a fields called
"intrinsic_metadata" or "queueing_metadata" move all their fields
to the standard_metadata Change all references appropriately. We
do this because the intrinsic_metadata and queueing_metadata are
handled specially in P4-14 programs - much more like
standard_metadata.
*/
class MoveIntrinsicMetadata : public Transform {
ProgramStructure* structure;
const IR::Type_Struct* stdType = nullptr;
const IR::Type_Struct* userType = nullptr;
const IR::Type_Struct* intrType = nullptr;
const IR::Type_Struct* queueType = nullptr;
const IR::StructField* intrField = nullptr;
const IR::StructField* queueField = nullptr;

public:
explicit MoveIntrinsicMetadata(ProgramStructure* structure): structure(structure)
{ CHECK_NULL(structure); setName("MoveIntrinsicMetadata"); }
const IR::Node* preorder(IR::P4Program* program) override {
stdType = program->getDeclsByName(
structure->v1model.standardMetadataType.name)->single()->to<IR::Type_Struct>();
userType = program->getDeclsByName(
structure->v1model.metadataType.name)->single()->to<IR::Type_Struct>();
CHECK_NULL(stdType);
CHECK_NULL(userType);
intrField = userType->getField(structure->v1model.intrinsicMetadata.name);
if (intrField != nullptr) {
auto intrTypeName = intrField->type;
auto tn = intrTypeName->to<IR::Type_Name>();
BUG_CHECK(tn, "%1%: expected a Type_Name", intrTypeName);
auto nt = program->getDeclsByName(tn->path->name)->nextOrDefault();
if (nt == nullptr || !nt->is<IR::Type_Struct>()) {
::error("%1%: expected a structure", tn);
return program;
}
intrType = nt->to<IR::Type_Struct>();
LOG2("Intrinsic metadata type " << intrType);
}

queueField = userType->getField(structure->v1model.queueingMetadata.name);
if (queueField != nullptr) {
auto queueTypeName = queueField->type;
auto tn = queueTypeName->to<IR::Type_Name>();
BUG_CHECK(tn, "%1%: expected a Type_Name", queueTypeName);
auto nt = program->getDeclsByName(tn->path->name)->nextOrDefault();
if (nt == nullptr || !nt->is<IR::Type_Struct>()) {
::error("%1%: expected a structure", tn);
return program;
}
queueType = nt->to<IR::Type_Struct>();
LOG2("Queueing metadata type " << queueType);
}
return program;
}

const IR::Node* postorder(IR::Type_Struct* type) override {
if (getOriginal() == stdType) {
if (intrType != nullptr) {
for (auto f : intrType->fields) {
if (type->fields.getDeclaration(f->name) == nullptr) {
::error("%1%: no such field in standard_metadata", f->name);
LOG2("standard_metadata: " << type);
}
}
}
if (queueType != nullptr) {
for (auto f : queueType->fields) {
if (type->fields.getDeclaration(f->name) == nullptr) {
::error("%1%: no such field in standard_metadata", f->name);
LOG2("standard_metadata: " << type);
}
}
}
}
return type;
}

const IR::Node* postorder(IR::StructField* field) override {
if (getOriginal() == intrField || getOriginal() == queueField)
// delete it from its parent
return nullptr;
return field;
}

const IR::Node* postorder(IR::Member* member) override {
// We rewrite expressions like meta.intrinsic_metadata.x as
// standard_metadata.x. We know that these parameter names
// are always the same.
if (member->member != structure->v1model.intrinsicMetadata.name &&
member->member != structure->v1model.queueingMetadata.name)
return member;
auto pe = member->expr->to<IR::PathExpression>();
if (pe == nullptr || pe->path->absolute)
return member;
if (pe->path->name == structure->v1model.parser.metadataParam.name) {
LOG2("Renaming reference " << member);
return new IR::PathExpression(
new IR::Path(member->expr->srcInfo,
IR::ID(pe->path->name.srcInfo,
structure->v1model.standardMetadata.name)));
}
return member;
}
};

} // namespace

///////////////////////////////////////////////////////////////

Expand Down Expand Up @@ -1265,6 +1370,7 @@ Converter::Converter() {
passes.emplace_back(new Rewriter(structure));
passes.emplace_back(new FixExtracts(structure));
passes.emplace_back(new FixMultiEntryPoint(structure));
passes.emplace_back(new MoveIntrinsicMetadata(structure));
}

Visitor::profile_t Converter::init_apply(const IR::Node* node) {
Expand Down
2 changes: 1 addition & 1 deletion frontends/p4/fromv1.0/programStructure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ void ProgramStructure::checkHeaderType(const IR::Type_StructLike* hdr, bool meta
}

cstring ProgramStructure::createType(const IR::Type_StructLike* type, bool header,
std::unordered_set<const IR::Type*> *converted) {
std::unordered_set<const IR::Type*> *converted) {
if (converted->count(type))
return type->name;
converted->emplace(type);
Expand Down
5 changes: 5 additions & 0 deletions frontends/p4/fromv1.0/v1model.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,9 @@ class V1Model : public ::Model::Model {
V1Model() :
Model::Model("0.1"), file("v1model.p4"),
standardMetadata("standard_metadata"),
// The following 2 are not really docmented in the P4-14 spec.
intrinsicMetadata("intrinsic_metadata"),
queueingMetadata("queueing_metadata"),
headersType("headers"),
metadataType("metadata"),
standardMetadataType("standard_metadata_t"),
Expand All @@ -266,6 +269,8 @@ class V1Model : public ::Model::Model {
public:
::Model::Elem file;
::Model::Elem standardMetadata;
::Model::Elem intrinsicMetadata;
::Model::Elem queueingMetadata;
::Model::Type_Model headersType;
::Model::Type_Model metadataType;
StandardMetadataType_Model standardMetadataType;
Expand Down
1 change: 1 addition & 0 deletions frontends/p4/toP4/toP4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ void ToP4::end_apply(const IR::Node*) {

// Try to guess whether a file is a "system" file
bool ToP4::isSystemFile(cstring file) {
if (noIncludes) return false;
if (file.startsWith(p4includePath)) return true;
return false;
}
Expand Down
10 changes: 6 additions & 4 deletions frontends/p4/toP4/toP4.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ This pass converts a P4-16 IR into a P4 source (text) program.
It can optionally emit as comments a representation of the program IR.
*/
class ToP4 : public Inspector {
int expressionPrecedence; // precedence of current IR::Operation
bool isDeclaration; // current type is a declaration
bool showIR; // if true dump IR as comments
bool withinArgument; // if true we are within a method call argument
int expressionPrecedence; /// precedence of current IR::Operation
bool isDeclaration; /// current type is a declaration
bool showIR; /// if true dump IR as comments
bool withinArgument; /// if true we are within a method call argument
bool noIncludes = false; /// If true do not generate #include statements.
/// Used for debugging.

struct VecPrint {
cstring separator;
Expand Down
4 changes: 2 additions & 2 deletions ir/v1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ const IR::Type *IR::Primitive::inferOperandType(int operand) const {
}

IR::V1Program::V1Program() {
// This should be kept in sync with v1model.p4
// This is used to typecheck P4-14 programs
auto *standard_metadata_t = new IR::Type_Struct("standard_metadata_t", {
new IR::StructField("ingress_port", IR::Type::Bits::get(9)),
new IR::StructField("packet_length", IR::Type::Bits::get(32)),
Expand All @@ -179,7 +179,7 @@ IR::V1Program::V1Program() {
new IR::StructField("egress_instance", IR::Type::Bits::get(16)),
new IR::StructField("instance_type", IR::Type::Bits::get(32)),
new IR::StructField("parser_status", IR::Type::Bits::get(8)),
new IR::StructField("parser_error_location", IR::Type::Bits::get(8)),
new IR::StructField("parser_error_location", IR::Type::Bits::get(8))
});
scope.add("standard_metadata_t", new IR::v1HeaderType(standard_metadata_t));
scope.add("standard_metadata", new IR::Metadata("standard_metadata", standard_metadata_t));
Expand Down
44 changes: 32 additions & 12 deletions p4include/v1model.p4
Original file line number Diff line number Diff line change
Expand Up @@ -56,23 +56,43 @@ struct standard_metadata_t {
//
// flattening fields that exist in bmv2-ss
// queueing metadata
@alias("queueing_metadata.enq_timestamp") bit<32> enq_timestamp;
@alias("queueing_metadata.enq_qdepth") bit<19> enq_qdepth;
@alias("queueing_metadata.deq_timedelta") bit<32> deq_timedelta;
@alias("queueing_metadata.deq_qdepth") bit<19> deq_qdepth;
@alias("queueing_metadata.enq_timestamp")
bit<32> enq_timestamp;
@alias("queueing_metadata.enq_qdepth")
bit<19> enq_qdepth;
@alias("queueing_metadata.deq_timedelta")
bit<32> deq_timedelta;
/// queue depth at the packet dequeue time.
@alias("queueing_metadata.deq_qdepth")
bit<19> deq_qdepth;

// intrinsic metadata
@alias("intrinsic_metadata.ingress_global_timestamp") bit<48> ingress_global_timestamp;
@alias("intrinsic_metadata.egress_global_timestamp") bit<48> egress_global_timestamp;
@alias("intrinsic_metadata.lf_field_list") bit<32> lf_field_list;
@alias("intrinsic_metadata.mcast_grp") bit<16> mcast_grp;
@alias("intrinsic_metadata.resubmit_flag") bit<32> resubmit_flag;
@alias("intrinsic_metadata.egress_rid") bit<16> egress_rid;
@alias("intrinsic_metadata.ingress_global_timestamp")
bit<48> ingress_global_timestamp;
@alias("intrinsic_metadata.egress_global_timestamp")
bit<48> egress_global_timestamp;
/// Learn filter field list
@alias("intrinsic_metadata.lf_field_list")
bit<32> lf_field_list;
/// multicast group id (key for the mcast replication table)
@alias("intrinsic_metadata.mcast_grp")
bit<16> mcast_grp;
/// resubmit metadata field list id, or 0 if no resubmit operation has been performed
@alias("intrinsic_metadata.resubmit_flag")
bit<32> resubmit_flag;
/// Replication ID for multicast
@alias("intrinsic_metadata.egress_rid")
bit<16> egress_rid;
@alias("intrinsic_metadata.recirculate_flag")
bit<32> recirculate_flag;
/// Indicates that a verify_checksum() method has failed.
// 1 if a checksum error was found, otherwise 0.
/// 1 if a checksum error was found, otherwise 0.
bit<1> checksum_error;
@alias("intrinsic_metadata.recirculate_flag") bit<32> recirculate_flag;
/// Error produced by parsing
error parser_error;
/// set packet priority
@alias("intrinsic_metadata.priority")
bit<3> priority;
}

enum CounterType {
Expand Down
Loading

0 comments on commit ae6fb22

Please sign in to comment.