diff --git a/backends/dpdk/backend.cpp b/backends/dpdk/backend.cpp index f38b12a084e..0756ed66a26 100644 --- a/backends/dpdk/backend.cpp +++ b/backends/dpdk/backend.cpp @@ -43,7 +43,7 @@ void DpdkBackend::convert(const IR::ToplevelBlock *tlb) { auto program = tlb->getProgram(); std::set invokedInKey; - auto convertToDpdk = new ConvertToDpdkProgram(refMap, typeMap, &structure); + auto convertToDpdk = new ConvertToDpdkProgram(refMap, typeMap, &structure, main); auto genContextJson = new DpdkContextGenerator(refMap, typeMap, &structure, options); PassManager simplify = { @@ -109,18 +109,24 @@ void DpdkBackend::convert(const IR::ToplevelBlock *tlb) { program = program->apply(simplify); dpdk_program = convertToDpdk->getDpdkProgram(); - if (!dpdk_program) + if (dpdk_program.empty()) return; PassManager post_code_gen = { new EliminateUnusedAction(), new DpdkAsmOptimization, }; + for_each (dpdk_program.begin(), dpdk_program.end(), [&post_code_gen](const IR::DpdkAsmProgram* &dpdk_asm_program) { + dpdk_asm_program = dpdk_asm_program->apply(post_code_gen)->to(); + } + ); +} - dpdk_program = dpdk_program->apply(post_code_gen)->to(); +void DpdkBackend::codegen(const IR::DpdkAsmProgram* dpdk_asm_program, std::ostream &out) const { + dpdk_asm_program->toSpec(out) << std::endl; } -void DpdkBackend::codegen(std::ostream &out) const { - dpdk_program->toSpec(out) << std::endl; +std::vector DpdkBackend::getDpdkProgram() { + return dpdk_program; } } // namespace DPDK diff --git a/backends/dpdk/backend.h b/backends/dpdk/backend.h index 373aefdd26b..5208d3d8c97 100644 --- a/backends/dpdk/backend.h +++ b/backends/dpdk/backend.h @@ -38,7 +38,7 @@ class DpdkBackend { P4::TypeMap* typeMap; P4::ConvertEnums::EnumMapping *enumMap; - const IR::DpdkAsmProgram *dpdk_program = nullptr; + std::vector dpdk_program;; const IR::ToplevelBlock* toplevel = nullptr; public: @@ -47,7 +47,8 @@ class DpdkBackend { P4::TypeMap *typeMap, P4::ConvertEnums::EnumMapping *enumMap) : options(options), refMap(refMap), typeMap(typeMap), enumMap(enumMap) {} - void codegen(std::ostream &) const; + void codegen(const IR::DpdkAsmProgram *, std::ostream &) const; + std::vector getDpdkProgram(); }; } // namespace DPDK diff --git a/backends/dpdk/dpdk.def b/backends/dpdk/dpdk.def index c83830c5cbc..e6e0b9c8ed6 100644 --- a/backends/dpdk/dpdk.def +++ b/backends/dpdk/dpdk.def @@ -79,6 +79,7 @@ class DpdkLearner { // Toplevel Assembly representation class DpdkAsmProgram { + inline cstring pipeline_name; inline IndexedVector headerType; inline IndexedVector structType; inline IndexedVector externDeclarations; diff --git a/backends/dpdk/dpdkProgram.cpp b/backends/dpdk/dpdkProgram.cpp index ffe1ad60df0..e8b083e5ac0 100644 --- a/backends/dpdk/dpdkProgram.cpp +++ b/backends/dpdk/dpdkProgram.cpp @@ -67,6 +67,23 @@ IR::IndexedVector ConvertToDpdkProgram::UpdateHeaderMetadata return structType; } +ordered_set ConvertToDpdkProgram::getPipelineNames() { + ordered_set pipenames; + auto cparams = main->getConstructorParameters(); + int index = -1; + for (auto param : main->constantValue) { + index++; + if (!param.second) continue; + auto pipe = param.second; + if (!pipe->is()) + continue; + auto idxParam = cparams->getParameter(index); + auto pipeName = idxParam->name; + pipenames.insert(pipeName); + } + return pipenames; +} + IR::IndexedVector ConvertToDpdkProgram::create_pna_preamble() { IR::IndexedVector instr; instr.push_back(new IR::DpdkRxStatement( @@ -74,13 +91,24 @@ IR::IndexedVector ConvertToDpdkProgram::create_pna_preambl return instr; } -IR::IndexedVector ConvertToDpdkProgram::create_psa_preamble() { +IR::IndexedVector ConvertToDpdkProgram::create_psa_preamble(cstring pipeName) { IR::IndexedVector instr; - instr.push_back(new IR::DpdkRxStatement( - new IR::Member(new IR::PathExpression("m"), "psa_ingress_input_metadata_ingress_port"))); - instr.push_back(new IR::DpdkMovStatement( - new IR::Member(new IR::PathExpression("m"), "psa_ingress_output_metadata_drop"), - new IR::Constant(0))); + auto pipenames = getPipelineNames(); + BUG_CHECK(pipenames.count(pipeName), "invalid pipeName : %s", pipeName); + if (pipeName == "ingress") { + instr.push_back(new IR::DpdkRxStatement( + new IR::Member(new IR::PathExpression("m"), "psa_ingress_input_metadata_ingress_port"))); + instr.push_back(new IR::DpdkMovStatement( + new IR::Member(new IR::PathExpression("m"), "psa_ingress_output_metadata_drop"), + new IR::Constant(0))); + } + else if (pipeName == "egress") { + instr.push_back(new IR::DpdkRxStatement( + new IR::Member(new IR::PathExpression("m"), "psa_egress_input_metadata_egress_port"))); + instr.push_back(new IR::DpdkMovStatement( + new IR::Member(new IR::PathExpression("m"), "psa_egress_output_metadata_drop"), + new IR::Constant(0))); + } return instr; } @@ -91,18 +119,29 @@ IR::IndexedVector ConvertToDpdkProgram::create_pna_postamb return instr; } -IR::IndexedVector ConvertToDpdkProgram::create_psa_postamble() { +IR::IndexedVector ConvertToDpdkProgram::create_psa_postamble(cstring pipeName) { IR::IndexedVector instr; - instr.push_back(new IR::DpdkTxStatement( - new IR::Member(new IR::PathExpression("m"), "psa_ingress_output_metadata_egress_port"))); - instr.push_back(new IR::DpdkLabelStatement("label_drop")); - instr.push_back(new IR::DpdkDropStatement()); + auto pipenames = getPipelineNames(); + BUG_CHECK(pipenames.count(pipeName), "invalid pipeName : %s", pipeName); + + if (pipeName == "ingress") { + instr.push_back(new IR::DpdkTxStatement( + new IR::Member(new IR::PathExpression("m"), "psa_ingress_output_metadata_egress_port"))); + instr.push_back(new IR::DpdkLabelStatement("label_drop")); + instr.push_back(new IR::DpdkDropStatement()); + } + else if (pipeName == "egress") { + instr.push_back(new IR::DpdkTxStatement( + new IR::Member(new IR::PathExpression("m"), "psa_egress_deparser_input_metadata_egress_port"))); + instr.push_back(new IR::DpdkLabelStatement("label_drop")); + instr.push_back(new IR::DpdkDropStatement()); + } return instr; } - -const IR::DpdkAsmProgram *ConvertToDpdkProgram::create(IR::P4Program *prog) { +std::vector ConvertToDpdkProgram::create(IR::P4Program *prog) { IR::Type_Struct *metadataStruct = nullptr; + std::vector dpdk_program; for (auto obj : prog->objects) { if (auto s = obj->to()) { @@ -112,8 +151,10 @@ const IR::DpdkAsmProgram *ConvertToDpdkProgram::create(IR::P4Program *prog) { } } } - IR::IndexedVector statements; + IR::IndexedVector statements_ingress; + IR::IndexedVector statements_egress; + bool is_ingress_empty = false, is_egress_empty = false; auto ingress_parser_converter = new ConvertToDpdkParser(refmap, typemap, structure, metadataStruct); @@ -145,40 +186,55 @@ const IR::DpdkAsmProgram *ConvertToDpdkProgram::create(IR::P4Program *prog) { else BUG("Unknown control block %s", kv.second->name); } - auto ingress_deparser_converter = - new ConvertToDpdkControl(refmap, typemap, structure, true); - auto egress_deparser_converter = - new ConvertToDpdkControl(refmap, typemap, structure); + ConvertToDpdkControl* ingress_deparser_converter = nullptr; + ConvertToDpdkControl* egress_deparser_converter = nullptr; for (auto kv : structure->deparsers) { - if (kv.first == "IngressDeparser") + if (kv.first == "IngressDeparser") { + ingress_deparser_converter = new ConvertToDpdkControl(refmap, typemap, structure, true, "ingress"); kv.second->apply(*ingress_deparser_converter); - else if (kv.first == "EgressDeparser") + } + else if (kv.first == "EgressDeparser") { + egress_deparser_converter = new ConvertToDpdkControl(refmap, typemap, structure, true, "egress"); kv.second->apply(*egress_deparser_converter); - else if (kv.first == "MainDeparserT") + } + else if (kv.first == "MainDeparserT") { + ingress_deparser_converter = new ConvertToDpdkControl(refmap, typemap, structure, true); kv.second->apply(*ingress_deparser_converter); + } else BUG("Unknown deparser block %s", kv.second->name); } IR::IndexedVector instr; - if (structure->isPNA()) + IR::IndexedVector instr_egress; + IR::IndexedVector instr_ingress; + if (structure->isPNA()) { instr.append(create_pna_preamble()); - else if (structure->isPSA()) - instr.append(create_psa_preamble()); - - instr.append(ingress_parser_converter->getInstructions()); - instr.append(ingress_converter->getInstructions()); - instr.append(ingress_deparser_converter->getInstructions()); - instr.append(egress_parser_converter->getInstructions()); - instr.append(egress_converter->getInstructions()); - instr.append(egress_deparser_converter->getInstructions()); - - if (structure->isPNA()) + instr.append(ingress_parser_converter->getInstructions()); + instr.append(ingress_converter->getInstructions()); + instr.append(ingress_deparser_converter->getInstructions()); instr.append(create_pna_postamble()); - else if (structure->isPSA()) - instr.append(create_psa_postamble()); - - statements.push_back(new IR::DpdkListStatement(instr)); + statements.push_back(new IR::DpdkListStatement(instr)); + } + else if (structure->isPSA()) { + instr_ingress.append(create_psa_preamble("ingress")); + is_ingress_empty = + ingress_converter->getInstructions().size() == 0 + && ingress_deparser_converter->getInstructions().size() == 0; + + instr_ingress.append(ingress_parser_converter->getInstructions()); + instr_ingress.append(ingress_converter->getInstructions()); + instr_ingress.append(ingress_deparser_converter->getInstructions()); + instr_ingress.append(create_psa_postamble("ingress")); + is_egress_empty = + egress_converter->getInstructions().size() == 0 + && egress_deparser_converter->getInstructions().size() == 0; + instr_egress.append(create_psa_preamble("egress")); + instr_egress.append(egress_parser_converter->getInstructions()); + instr_egress.append(egress_converter->getInstructions()); + instr_egress.append(egress_deparser_converter->getInstructions()); + instr_egress.append(create_psa_postamble("egress")); + } IR::IndexedVector headerType; for (auto kv : structure->header_types) { @@ -187,7 +243,6 @@ const IR::DpdkAsmProgram *ConvertToDpdkProgram::create(IR::P4Program *prog) { h->fields); headerType.push_back(ht); } - IR::IndexedVector structType; IR::IndexedVector updatedHeaderMetadataStructs = UpdateHeaderMetadata(prog, metadataStruct); @@ -232,27 +287,47 @@ const IR::DpdkAsmProgram *ConvertToDpdkProgram::create(IR::P4Program *prog) { } structType.append(updatedHeaderMetadataStructs); + + IR::IndexedVector dpdkExternDecls; for (auto ed : structure->externDecls) { auto st = new IR::DpdkExternDeclaration(ed->name, ed->annotations, ed->type, ed->arguments); dpdkExternDecls.push_back(st); } - auto tables = ingress_converter->getTables(); - tables.append(egress_converter->getTables()); + if (structure->isPNA()) { + auto tables = ingress_converter->getTables(); + auto actions = ingress_converter->getActions(); + auto selectors = ingress_converter->getSelectors(); + auto learners = ingress_converter->getLearners(); + dpdk_program.push_back(new IR::DpdkAsmProgram("", + headerType, structType, dpdkExternDecls, actions, tables, selectors, + learners, statements, structure->get_globals())); + } + else if (structure->isPSA()) { + statements_ingress.push_back(new IR::DpdkListStatement(instr_ingress)); + statements_egress.push_back(new IR::DpdkListStatement(instr_egress)); + + auto tables_ingress = ingress_converter->getTables(); + auto tables_egress = egress_converter->getTables(); - auto actions = ingress_converter->getActions(); - actions.append(egress_converter->getActions()); + auto actions_ingress = ingress_converter->getActions(); + auto actions_egress = egress_converter->getActions(); - auto selectors = ingress_converter->getSelectors(); - selectors.append(egress_converter->getSelectors()); + auto selectors_ingress = ingress_converter->getSelectors(); + auto selectors_egress = egress_converter->getSelectors(); - auto learners = ingress_converter->getLearners(); - learners.append(egress_converter->getLearners()); + auto learners_ingress = ingress_converter->getLearners(); + auto learners_egress = egress_converter->getLearners(); - return new IR::DpdkAsmProgram( - headerType, structType, dpdkExternDecls, actions, tables, selectors, learners, - statements, structure->get_globals()); + if (!is_ingress_empty) + dpdk_program.push_back(new IR::DpdkAsmProgram("ingress", headerType, structType, dpdkExternDecls, actions_ingress, tables_ingress, + selectors_ingress, learners_ingress, statements_ingress, structure->get_globals())); + if (!is_egress_empty) + dpdk_program.push_back(new IR::DpdkAsmProgram("egress", headerType, structType, dpdkExternDecls, actions_egress, tables_egress, + selectors_egress, learners_egress, statements_egress, structure->get_globals())); + } + return dpdk_program; } const IR::Node *ConvertToDpdkProgram::preorder(IR::P4Program *prog) { @@ -647,9 +722,15 @@ bool ConvertToDpdkControl::preorder(const IR::P4Control *c) { helper->setCalledBy(this); c->body->apply(*helper); if (deparser && structure->isPSA()) { - add_inst(new IR::DpdkJmpNotEqualStatement("LABEL_DROP", - new IR::Member(new IR::PathExpression("m"), "psa_ingress_output_metadata_drop"), - new IR::Constant(0))); } + if (pipeline_name == "ingress") + add_inst(new IR::DpdkJmpNotEqualStatement("LABEL_DROP", + new IR::Member(new IR::PathExpression("m"), "psa_ingress_output_metadata_drop"), + new IR::Constant(0))); + else if (pipeline_name =="egress") + add_inst(new IR::DpdkJmpNotEqualStatement("LABEL_DROP", + new IR::Member(new IR::PathExpression("m"), "psa_egress_output_metadata_drop"), + new IR::Constant(0))); + } for (auto i : helper->get_instr()) { add_inst(i); diff --git a/backends/dpdk/dpdkProgram.h b/backends/dpdk/dpdkProgram.h index 37863f654a5..8a22a4e5931 100644 --- a/backends/dpdk/dpdkProgram.h +++ b/backends/dpdk/dpdkProgram.h @@ -40,20 +40,21 @@ class ConvertToDpdkProgram : public Transform { P4::TypeMap *typemap; P4::ReferenceMap *refmap; DpdkProgramStructure *structure; - const IR::DpdkAsmProgram *dpdk_program; - + std::vector dpdk_program; + const IR::PackageBlock* main; public: ConvertToDpdkProgram(P4::ReferenceMap *refmap, P4::TypeMap *typemap, - DpdkProgramStructure *structure) - : typemap(typemap), refmap(refmap), structure(structure) { } + DpdkProgramStructure *structure, const IR::PackageBlock* main) + : typemap(typemap), refmap(refmap), structure(structure), main(main) { } - const IR::DpdkAsmProgram *create(IR::P4Program *prog); + std::vector create(IR::P4Program *prog); IR::IndexedVector create_pna_preamble(); - IR::IndexedVector create_psa_preamble(); + IR::IndexedVector create_psa_preamble(cstring pipeName); IR::IndexedVector create_pna_postamble(); - IR::IndexedVector create_psa_postamble(); + IR::IndexedVector create_psa_postamble(cstring pipeName); + ordered_set getPipelineNames(); const IR::Node *preorder(IR::P4Program *p) override; - const IR::DpdkAsmProgram *getDpdkProgram() { return dpdk_program; } + std::vector getDpdkProgram() { return dpdk_program; } IR::IndexedVector UpdateHeaderMetadata( IR::P4Program *prog, IR::Type_Struct *metadata); }; @@ -99,13 +100,15 @@ class ConvertToDpdkControl : public Inspector { IR::IndexedVector actions; std::set unique_actions; bool deparser; + cstring pipeline_name; public: ConvertToDpdkControl( P4::ReferenceMap *refmap, P4::TypeMap *typemap, DpdkProgramStructure *structure, - bool deparser = false) - : typemap(typemap), refmap(refmap), structure(structure), deparser(deparser) {} + bool deparser = false, cstring pipeline_name = "") + : typemap(typemap), refmap(refmap), structure(structure), deparser(deparser), + pipeline_name(pipeline_name) {} IR::IndexedVector &getTables() { return tables; } IR::IndexedVector &getSelectors() { return selectors; } diff --git a/backends/dpdk/main.cpp b/backends/dpdk/main.cpp index 3463acc7685..ac24a9923df 100644 --- a/backends/dpdk/main.cpp +++ b/backends/dpdk/main.cpp @@ -139,12 +139,17 @@ int main(int argc, char *const argv[]) { return 1; if (!options.outputFile.isNullOrEmpty()) { - std::ostream *out = openFile(options.outputFile, false); - if (out != nullptr) { - backend->codegen(*out); - out->flush(); - } + cstring outputFile = options.outputFile.substr(0, options.outputFile.size() - 5 /* size of ".spec" extension */); + auto dpdk_program = backend->getDpdkProgram(); + for_each (dpdk_program.begin(), dpdk_program.end(), + [outputFile, backend] (const IR::DpdkAsmProgram* dpdk_asm_program) { + std::ostream *out = openFile(outputFile + (dpdk_asm_program->pipeline_name == "" ? "" : ".") + + dpdk_asm_program->pipeline_name + ".spec", false); + if (out != nullptr) { + backend->codegen(dpdk_asm_program, *out); + out->flush(); + } + }); } - return ::errorCount() > 0; }