diff --git a/backends/ebpf/psa/externs/ebpfPsaDigest.h b/backends/ebpf/psa/externs/ebpfPsaDigest.h index a7cdc22475f..7a196eb780b 100644 --- a/backends/ebpf/psa/externs/ebpfPsaDigest.h +++ b/backends/ebpf/psa/externs/ebpfPsaDigest.h @@ -28,7 +28,6 @@ class EBPFDigestPSA : public EBPFObject { private: cstring instanceName; const EBPFProgram *program; - EBPFType *valueType; cstring valueTypeName; const IR::Declaration_Instance *declaration; /// arbitrary value for max queue size @@ -36,6 +35,7 @@ class EBPFDigestPSA : public EBPFObject { int maxDigestQueueSize = 128; public: + EBPFType *valueType; EBPFDigestPSA(const EBPFProgram *program, const IR::Declaration_Instance *di); void emitTypes(CodeBuilder *builder); @@ -43,9 +43,9 @@ class EBPFDigestPSA : public EBPFObject { void processMethod(CodeBuilder *builder, cstring method, const IR::MethodCallExpression *expr, DeparserBodyTranslatorPSA *visitor); - void emitPushElement(CodeBuilder *builder, const IR::Expression *elem, - Inspector *codegen) const; - void emitPushElement(CodeBuilder *builder, cstring elem) const; + virtual void emitPushElement(CodeBuilder *builder, const IR::Expression *elem, + Inspector *codegen) const; + virtual void emitPushElement(CodeBuilder *builder, cstring elem) const; }; } // namespace EBPF diff --git a/backends/tc/backend.cpp b/backends/tc/backend.cpp index 59b9bc12886..4550d8cb1a5 100644 --- a/backends/tc/backend.cpp +++ b/backends/tc/backend.cpp @@ -841,7 +841,8 @@ safe_vector ConvertToBackendIR::processExternConstructor( } else { /* If a parameter is not annoated by tc_init or tc_numel then it is emitted as constructor parameters.*/ - IR::TCKey *key = new IR::TCKey(0, parameter->type->width_bits(), + cstring ptype = absl::StrCat("bit", parameter->type->width_bits()); + IR::TCKey *key = new IR::TCKey(0, parameter->type->width_bits(), ptype, parameter->toString(), "param"_cs, false); keys.push_back(key); if (exp->is()) { @@ -910,8 +911,9 @@ safe_vector ConvertToBackendIR::processCounterControlPathKeys auto temp_keys = HandleTypeNameStructField(field, extn, decl, kId, annoName); keys.insert(keys.end(), temp_keys.begin(), temp_keys.end()); } else { - IR::TCKey *key = - new IR::TCKey(kId++, field->type->width_bits(), field->toString(), annoName, true); + cstring ptype = absl::StrCat("bit", field->type->width_bits()); + IR::TCKey *key = new IR::TCKey(kId++, field->type->width_bits(), ptype, + field->toString(), annoName, true); keys.push_back(key); } } @@ -942,8 +944,9 @@ safe_vector ConvertToBackendIR::processExternControlPath( auto temp_keys = HandleTypeNameStructField(field, extn, decl, kId, annoName); keys.insert(keys.end(), temp_keys.begin(), temp_keys.end()); } else { - IR::TCKey *key = new IR::TCKey(kId++, field->type->width_bits(), field->toString(), - annoName, true); + cstring ptype = absl::StrCat("bit", field->type->width_bits()); + IR::TCKey *key = new IR::TCKey(kId++, field->type->width_bits(), ptype, + field->toString(), annoName, true); keys.push_back(key); } } @@ -965,13 +968,27 @@ safe_vector ConvertToBackendIR::HandleTypeNameStructField( /* If 'T' is of Type_Struct, extract all fields of structure*/ if (auto param_struct = param_val->to()) { for (auto f : param_struct->fields) { - IR::TCKey *key = - new IR::TCKey(kId++, f->type->width_bits(), f->toString(), annoName, true); + cstring ptype = absl::StrCat("bit", f->type->width_bits()); + if (auto anno = f->getAnnotations()->getSingle(ParseTCAnnotations::tcType)) { + auto expr = anno->expr[0]; + if (auto typeLiteral = expr->to()) { + ptype = typeLiteral->value; + } + } + IR::TCKey *key = new IR::TCKey(kId++, f->type->width_bits(), ptype, + f->toString(), annoName, true); keys.push_back(key); } } else { - IR::TCKey *key = new IR::TCKey(kId++, param_val->width_bits(), field->toString(), - annoName, true); + cstring ptype = absl::StrCat("bit", param_val->width_bits()); + if (auto anno = field->getAnnotations()->getSingle(ParseTCAnnotations::tcType)) { + auto expr = anno->expr[0]; + if (auto typeLiteral = expr->to()) { + ptype = typeLiteral->value; + } + } + IR::TCKey *key = new IR::TCKey(kId++, param_val->width_bits(), ptype, + field->toString(), annoName, true); keys.push_back(key); } break; @@ -1025,6 +1042,10 @@ void ConvertToBackendIR::postorder(const IR::Declaration_Instance *decl) { eb->externId = "0x1A000000"_cs; } else if (eName == "Counter") { eb->externId = "0x19000000"_cs; + } else if (eName == "Digest") { + eb->externId = "0x05000000"_cs; + instance->is_num_elements = true; + instance->num_elements = 0; } else { externCount += 1; std::stringstream value; diff --git a/backends/tc/ebpfCodeGen.cpp b/backends/tc/ebpfCodeGen.cpp index 2ac207bb6ff..dfa13401eb2 100644 --- a/backends/tc/ebpfCodeGen.cpp +++ b/backends/tc/ebpfCodeGen.cpp @@ -160,7 +160,6 @@ void PNAEbpfGenerator::emitP4TCActionParam(EBPF::CodeBuilder *builder) const { void PNAEbpfGenerator::emitPipelineInstances(EBPF::CodeBuilder *builder) const { pipeline->parser->emitValueSetInstances(builder); - pipeline->deparser->emitDigestInstances(builder); builder->target->emitTableDecl(builder, "hdr_md_cpumap"_cs, EBPF::TablePerCPUArray, "u32"_cs, "struct hdr_md"_cs, 2); @@ -1185,7 +1184,7 @@ void IngressDeparserPNA::emitPreDeparser(EBPF::CodeBuilder *builder) { void IngressDeparserPNA::emit(EBPF::CodeBuilder *builder) { codeGen->setBuilder(builder); - + emitExternDefinition(builder); for (auto a : controlBlock->container->controlLocals) { if (a->is()) { auto vd = a->to(); @@ -1324,7 +1323,7 @@ bool ConvertToEbpfPipelineTC::preorder(const IR::PackageBlock *block) { CHECK_NULL(pipeline->control); auto deparser_converter = new ConvertToEBPFDeparserPNA( - pipeline, pipeline->parser->headers, pipeline->control->outputStandardMetadata); + pipeline, pipeline->parser->headers, pipeline->control->outputStandardMetadata, tcIR); deparserBlock->apply(*deparser_converter); pipeline->deparser = deparser_converter->getEBPFDeparser(); CHECK_NULL(pipeline->deparser); @@ -1516,8 +1515,9 @@ bool ConvertToEBPFDeparserPNA::preorder(const IR::Declaration_Instance *di) { auto baseType = typeSpec->baseType; auto typeName = baseType->to()->path->name.name; if (typeName == "Digest") { + deparser->addExternDeclaration = true; cstring instance = EBPF::EBPFObject::externalName(di); - auto digest = new EBPF::EBPFDigestPSA(program, di); + auto digest = new EBPFDigestPNA(program, di, typeName, tcIR); deparser->digests.emplace(instance, digest); } } diff --git a/backends/tc/ebpfCodeGen.h b/backends/tc/ebpfCodeGen.h index 9d4b47cc93b..31a23bb8fea 100644 --- a/backends/tc/ebpfCodeGen.h +++ b/backends/tc/ebpfCodeGen.h @@ -186,11 +186,18 @@ class IngressDeparserPNA : public EBPF::EBPFDeparserPSA { const IR::Parameter *parserHeaders, const IR::Parameter *istd) : EBPF::EBPFDeparserPSA(program, control, parserHeaders, istd) {} + bool addExternDeclaration = false; bool build() override; void emit(EBPF::CodeBuilder *builder) override; void emitPreDeparser(EBPF::CodeBuilder *builder) override; void emitDeclaration(EBPF::CodeBuilder *builder, const IR::Declaration *decl) override; + void emitExternDefinition(EBPF::CodeBuilder *builder) { + if (addExternDeclaration) { + builder->emitIndent(); + builder->appendLine("struct p4tc_ext_bpf_params ext_params = {};"); + } + } DECLARE_TYPEINFO(IngressDeparserPNA, EBPF::EBPFDeparserPSA); }; @@ -329,12 +336,17 @@ class ConvertToEBPFDeparserPNA : public Inspector { EBPF::EBPFProgram *program; const IR::Parameter *parserHeaders; const IR::Parameter *istd; + const ConvertToBackendIR *tcIR; TC::IngressDeparserPNA *deparser; public: ConvertToEBPFDeparserPNA(EBPF::EBPFProgram *program, const IR::Parameter *parserHeaders, - const IR::Parameter *istd) - : program(program), parserHeaders(parserHeaders), istd(istd), deparser(nullptr) {} + const IR::Parameter *istd, const ConvertToBackendIR *tcIR) + : program(program), + parserHeaders(parserHeaders), + istd(istd), + tcIR(tcIR), + deparser(nullptr) {} bool preorder(const IR::ControlBlock *) override; bool preorder(const IR::Declaration_Instance *) override; diff --git a/backends/tc/introspection.cpp b/backends/tc/introspection.cpp index de240b5e314..99ce2fec14e 100644 --- a/backends/tc/introspection.cpp +++ b/backends/tc/introspection.cpp @@ -168,7 +168,7 @@ void IntrospectionGenerator::collectExternInfo() { keyField->id = control_field->keyID; keyField->name = control_field->keyName; keyField->attribute = control_field->keyAttribute; - keyField->type = "bit" + Util::toString(control_field->bitwidth); + keyField->type = control_field->type; keyField->bitwidth = control_field->bitwidth; externInstanceInfo->keyFields.push_back(keyField); } diff --git a/backends/tc/runtime/pna.h b/backends/tc/runtime/pna.h index 6eaff839d07..627900b3742 100644 --- a/backends/tc/runtime/pna.h +++ b/backends/tc/runtime/pna.h @@ -393,6 +393,14 @@ extern int xdp_p4tc_extern_md_write(struct xdp_md *xdp_ctx, struct p4tc_ext_bpf_val *val, const u32 val__sz) __ksym; +int bpf_p4tc_extern_digest_pack(struct __sk_buff *skb, + struct p4tc_ext_bpf_params *params, + const u32 params__sz) __ksym; + +int xdp_p4tc_extern_digest_pack(struct xdp_md *xdp_ctx, + struct p4tc_ext_bpf_params *params, + const u32 params__sz) __ksym; + /* Timestamp PNA extern */ static inline u64 bpf_p4tc_extern_timestamp() { return bpf_ktime_get_ns(); diff --git a/backends/tc/tc.def b/backends/tc/tc.def index 1c3d884414f..4268e1af6c0 100644 --- a/backends/tc/tc.def +++ b/backends/tc/tc.def @@ -16,6 +16,8 @@ and limitations under the License. #emit #include "backends/tc/tc_defines.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" #end class TCKernelMetadata { @@ -24,19 +26,19 @@ class TCKernelMetadata { std::string metaName = "kernel."; switch (metaField) { case TC::SKBREDIR: { - metaName += "skbredir"; + absl::StrAppend(&metaName, "skbredir"); break; } case TC::SKBIIF: { - metaName += "skbiif"; + absl::StrAppend(&metaName, "skbiif"); break; } case TC::SKBTSTAMP: { - metaName += "skbtstamp"; + absl::StrAppend(&metaName, "skbtstamp"); break; } case TC::SKBPRIO: { - metaName += "skbprio"; + absl::StrAppend(&metaName, "skbprio"); break; } } @@ -79,61 +81,58 @@ class TCActionParam { std::string paramType = ""; switch(dataType) { case TC::BIT_TYPE : - paramType += "__u" + Util::toString(bitSize); + paramType = absl::StrCat("__u", bitSize); break; case TC::DEV_TYPE : - paramType += "dev"; + paramType = "dev"; break; case TC::MACADDR_TYPE : - paramType += "macaddr"; + paramType = "macaddr"; break; case TC::IPV4_TYPE : - paramType += "ipv4"; + paramType = "ipv4"; break; case TC::IPV6_TYPE : - paramType += "ipv6"; + paramType = "ipv6"; break; case TC::BE16_TYPE : - paramType += "__be16"; + paramType = "__be16"; break; case TC::BE32_TYPE : - paramType += "__be32"; + paramType = "__be32"; break; case TC::BE64_TYPE : - paramType += "__be64"; + paramType = "__be64"; break; } return paramType; } toString { - std::string tcActionParam = ""; - tcActionParam += "\n\tparam "; - tcActionParam += paramName; - tcActionParam += " type "; + std::string tcActionParam = absl::StrCat("\n\tparam ", paramName.string_view(), " type "); switch(dataType) { case TC::BIT_TYPE : - tcActionParam += "bit" + Util::toString(bitSize); + absl::StrAppend(&tcActionParam, "bit", bitSize); break; case TC::DEV_TYPE : - tcActionParam += "dev"; + absl::StrAppend(&tcActionParam, "dev"); break; case TC::MACADDR_TYPE : - tcActionParam += "macaddr"; + absl::StrAppend(&tcActionParam, "macaddr"); break; case TC::IPV4_TYPE : - tcActionParam += "ipv4"; + absl::StrAppend(&tcActionParam, "ipv4"); break; case TC::IPV6_TYPE : - tcActionParam += "ipv6"; + absl::StrAppend(&tcActionParam, "ipv6"); break; case TC::BE16_TYPE : - tcActionParam += "be16"; + absl::StrAppend(&tcActionParam, "be16"); break; case TC::BE32_TYPE : - tcActionParam += "be32"; + absl::StrAppend(&tcActionParam, "be32"); break; case TC::BE64_TYPE : - tcActionParam += "be64"; + absl::StrAppend(&tcActionParam, "be64"); break; } return tcActionParam; @@ -155,10 +154,9 @@ class TCDefaultActionParam { defaultValue = nullptr; } toString { - std::string tcActionParam = ""; - tcActionParam += " " + paramDetail->paramName; + std::string tcActionParam = absl::StrCat(" ", paramDetail->paramName.string_view()); if (defaultValue != nullptr) - tcActionParam += " " + defaultValue; + absl::StrAppend(&tcActionParam, " ", defaultValue.string_view()); return tcActionParam; } dbprint { out << toString(); } @@ -173,8 +171,7 @@ class TCAction { if (actionName == "NoAction") { return actionName; } - std::string tcAction = pipelineName.string(); - tcAction += "/" + actionName; + std::string tcAction = absl::StrCat(pipelineName.string_view(), "/", actionName.string_view()); return tcAction; } cstring getActionName() const { @@ -195,22 +192,16 @@ class TCAction { actId = 0; } toString { - std::string tcAction = ""; - tcAction += "\n$TC p4template create action/"; - tcAction += pipelineName; - tcAction += "/" + actionName; + std::string tcAction = absl::StrCat("\n$TC p4template create action/", pipelineName.string_view(), "/", actionName.string_view()); if (actId != 0) { - tcAction += " actid " + Util::toString(actId); + absl::StrAppend(&tcAction, " actid ", actId); } if (!actionParams.empty()) { for (auto actParam : actionParams) { - tcAction += " \\"; - tcAction += actParam->toString(); + absl::StrAppend(&tcAction, " \\", actParam->toString().string_view()); } } - tcAction += "\n$TC p4template update action/"; - tcAction += pipelineName; - tcAction += "/" + actionName + " state active"; + absl::StrAppend(&tcAction, "\n$TC p4template update action/", pipelineName.string_view(), "/", actionName.string_view(), " state active"); return tcAction; } @@ -226,7 +217,7 @@ class TCEntry { toString { std::string tcEntry = ""; for(auto k : keys) { - tcEntry += " " + k.first + " " + k.second; + tcEntry = absl::StrJoin({tcEntry, k.first.string(), k.second.string()}, " "); } return tcEntry; } @@ -348,76 +339,73 @@ class TCTable { isDirectCounter = false; } toString { - std::string tcTable = ""; - tcTable += "\n$TC p4template create table/"; - tcTable += pipelineName + "/" + controlName + "/" + tableName + " \\"; - tcTable += "\n\ttblid " + Util::toString(tableID) + " \\"; - tcTable += "\n\ttype " + printMatchType(matchType) + " \\"; - tcTable += "\n\tkeysz " + Util::toString(keySize); - tcTable += " nummasks " + Util::toString(numMask); - tcTable += " permissions " + Util::toString(permissions); - tcTable += " tentries " + Util::toString(tableEntriesCount); + std::string tcTable = absl::StrCat("\n$TC p4template create table/", + pipelineName.string_view(), "/", controlName.string_view(), "/", tableName.string_view(), " \\", + "\n\ttblid ", tableID, " \\", + "\n\ttype ", printMatchType(matchType).string_view(), " \\", + "\n\tkeysz ", keySize, + " nummasks ", numMask, + " permissions ", permissions.string_view(), + " tentries ", tableEntriesCount); if (isTableAddOnMiss && timerProfiles > defaultTimerProfiles) { - tcTable += " num_timer_profiles " + Util::toString(timerProfiles); + absl::StrAppend(&tcTable, " num_timer_profiles ", timerProfiles); } if (isDirectCounter) { - tcTable += " \\\n\tpna_direct_counter DirectCounter/" + directCounterInstance; + absl::StrAppend(&tcTable, " \\\n\tpna_direct_counter DirectCounter/", directCounterInstance.string_view()); } if (!actionList.empty()) { - tcTable += " \\"; - tcTable += "\n\ttable_acts "; + absl::StrAppend(&tcTable, " \\", "\n\ttable_acts "); for (auto iter = actionList.begin(); iter != actionList.end(); iter++) { - tcTable += "act name " + iter->first->getName(); + absl::StrAppend(&tcTable, "act name ", iter->first->getName().string_view()); if (iter->second == TC::TABLEONLY) { - tcTable += " flags tableonly"; + absl::StrAppend(&tcTable, " flags tableonly"); } else if (iter->second == TC::DEFAULTONLY) { - tcTable += " flags defaultonly"; + absl::StrAppend(&tcTable, " flags defaultonly"); } if (std::next(iter) != actionList.end()) { - tcTable += " \\"; - tcTable += "\n\t"; + absl::StrAppend(&tcTable, " \\", "\n\t"); } } } if (defaultHitAction != nullptr) { - tcTable += "\n$TC p4template update table/" + pipelineName - + "/" + controlName + "/" + tableName - + " default_hit_action"; + absl::StrAppend(&tcTable, "\n$TC p4template update table/", pipelineName.string_view(), + "/", controlName.string_view(), "/", tableName.string_view(), + " default_hit_action"); if (isDefaultHitConst) { - tcTable += " permissions 0x1024"; + absl::StrAppend(&tcTable, " permissions 0x1024"); } - tcTable += " action " + defaultHitAction->getName(); + absl::StrAppend(&tcTable, " action ", defaultHitAction->getName().string_view()); if (!defaultHitActionParams.empty()) - tcTable += " param"; + absl::StrAppend(&tcTable, " param"); for (auto param : defaultHitActionParams) - tcTable += param->toString(); + absl::StrAppend(&tcTable, param->toString().string_view()); if (isTcMayOverrideHit) - tcTable += " flags runtime"; + absl::StrAppend(&tcTable, " flags runtime"); } if (defaultMissAction != nullptr) { - tcTable += "\n$TC p4template update table/" + pipelineName - + "/" + controlName + "/" + tableName - + " default_miss_action"; + absl::StrAppend(&tcTable, "\n$TC p4template update table/", pipelineName.string_view(), + "/", controlName.string_view(), "/", tableName.string_view(), + " default_miss_action"); if (isDefaultMissConst) { - tcTable += " permissions 0x1024"; + absl::StrAppend(&tcTable, " permissions 0x1024"); } - tcTable += " action " + defaultMissAction->getName(); + absl::StrAppend(&tcTable, " action ", defaultMissAction->getName().string_view()); if (!defaultMissActionParams.empty()) - tcTable += " param"; + absl::StrAppend(&tcTable, " param"); for (auto param : defaultMissActionParams) - tcTable += param->toString(); + absl::StrAppend(&tcTable, param->toString().string_view()); if (isTcMayOverrideMiss) - tcTable += " flags runtime"; + absl::StrAppend(&tcTable, " flags runtime"); } if (const_entries.size() != 0) { for (auto entry : const_entries) { - tcTable += "\n$TC p4template create table/" + pipelineName - + "/" + controlName + "/" + tableName - + " entry" + entry->toString(); - tcTable += " permissions 0x1024"; - tcTable += " action " + pipelineName - + "/" + controlName + "/" + entry->getActionName(); + absl::StrAppend(&tcTable, "\n$TC p4template create table/", pipelineName.string_view(), + "/", controlName.string_view(), "/", tableName.string_view(), + " entry", entry->toString().string_view(), + " permissions 0x1024", + " action ", pipelineName.string_view(), + "/", controlName.string_view(), "/", entry->getActionName().string_view()); } } return tcTable; @@ -428,14 +416,16 @@ class TCTable { class TCKey { unsigned keyID; unsigned bitwidth; + cstring type; cstring keyName; cstring keyAttribute; bool emitID; bool emitValue; unsigned value; - TCKey(unsigned id, unsigned width, cstring name, cstring attr, bool isID) { + TCKey(unsigned id, unsigned width, cstring ptype, cstring name, cstring attr, bool isID) { keyID = id; bitwidth = width; + type = ptype; keyName = name; keyAttribute = attr; emitID = isID; @@ -446,12 +436,12 @@ class TCKey { emitValue = true; } toString { - std::string tckeyInstance = " " + keyAttribute + " " + keyName + " ptype bit" + Util::toString(bitwidth); + std::string tckeyInstance = absl::StrCat(" ", keyAttribute.string_view(), " ", keyName.string_view(), " ptype ", type.string_view()); if (emitID) { - tckeyInstance += " id " + Util::toString(keyID); + absl::StrAppend(&tckeyInstance, " id ", keyID); } if (emitValue) { - tckeyInstance += " " + Util::toString(value); + absl::StrAppend(&tckeyInstance, " ", value); } return tckeyInstance; } @@ -498,28 +488,24 @@ class TCExternInstance { numelemns = ne; } toString { - std::string tcExternInstance = ""; - tcExternInstance += instanceName + " instid " + Util::toString(instanceID) + " \\"; - + std::string tcExternInstance = absl::StrCat(instanceName.string_view(), " instid ", instanceID, " \\"); if (isNumelemns) { - tcExternInstance += "\ntc_numel " + Util::toString(numelemns); - tcExternInstance += " \\"; + absl::StrAppend(&tcExternInstance, "\ntc_numel ", numelemns, " \\"); } if (isTablBindable) { - tcExternInstance += "\ntbl_bindable"; - tcExternInstance += " \\"; + absl::StrAppend(&tcExternInstance, "\ntbl_bindable", " \\"); } if (isConstructorKeys) { - tcExternInstance += "\nconstructor"; + absl::StrAppend(&tcExternInstance, "\nconstructor"); for (auto field : constructorKeys) { - tcExternInstance += field->toString(); + absl::StrAppend(&tcExternInstance, field->toString().string_view()); } - tcExternInstance += " \\"; + absl::StrAppend(&tcExternInstance, " \\"); } if (isControlPath) { - tcExternInstance += "\ncontrol_path"; + absl::StrAppend(&tcExternInstance, "\ncontrol_path"); for (auto field : controlKeys) { - tcExternInstance += field->toString(); + absl::StrAppend(&tcExternInstance, field->toString().string_view()); } } return tcExternInstance; @@ -555,20 +541,16 @@ class TCExtern { return nullptr; } toString { - std::string tcExtern = ""; - tcExtern += "\n$TC p4template create extern/"; - tcExtern += "root/" + externName; - tcExtern += " extid " + externID; - tcExtern += " numinstances " + Util::toString(numinstances); - tcExtern += " tc_acl " + acl_permisson; + std::string tcExtern = absl::StrCat("\n$TC p4template create extern/", "root/", externName.string_view(), + " extid ", externID.string_view(), " numinstances ", numinstances, " tc_acl " + acl_permisson); if (has_exec_method) { - tcExtern += " has_exec_method"; + absl::StrAppend(&tcExtern, " has_exec_method"); } for (unsigned iter = 0; iter < numinstances; iter++) { - tcExtern += "\n\n$TC p4template create extern_inst/" + pipelineName - + "/" + externName + "/"; + absl::StrAppend(&tcExtern, "\n\n$TC p4template create extern_inst/", pipelineName.string_view(), + "/", externName.string_view(), "/"); if (externInstances.size() > iter) - tcExtern += externInstances[iter]->toString(); + absl::StrAppend(&tcExtern, externInstances[iter]->toString().string_view()); } return tcExtern; } @@ -622,38 +604,36 @@ class TCPipeline { pipelineName = nullptr; } toString { - std::string tcCode = "#!/bin/bash -x\n"; - tcCode += "\nset -e\n"; - tcCode += "\nTC=\"tc\""; - tcCode += "\n$TC p4template create pipeline/" + pipelineName; - tcCode += " numtables "; - tcCode += Util::toString(numTables); + std::string tcCode = absl::StrCat("#!/bin/bash -x\n", + "\nset -e\n", "\nTC=\"tc\"", + "\n$TC p4template create pipeline/", pipelineName.string_view(), + " numtables ", numTables); if (!actionDefs.empty()) { for (auto a : actionDefs) { - tcCode += "\n" + a->toString(); + absl::StrAppend(&tcCode, "\n", a->toString().string_view()); } } if (!externDefs.empty()) { for (auto e : externDefs) { - tcCode += "\n" + e->toString(); + absl::StrAppend(&tcCode, "\n", e->toString().string_view()); } } if (!tableDefs.empty()) { for (auto t : tableDefs) { - tcCode += "\n" + t->toString(); + absl::StrAppend(&tcCode, "\n", t->toString().string_view()); } } if (preaction != nullptr) { - tcCode += "\n" + preaction->toString(); - tcCode += "\n$TC p4template update pipeline/" + pipelineName - + " preactions action " + pipelineName + "/preaction"; + absl::StrAppend(&tcCode, "\n", preaction->toString().string_view(), + "\n$TC p4template update pipeline/", pipelineName.string_view(), + " preactions action ", pipelineName.string_view(), "/preaction"); } if (postaction != nullptr) { - tcCode += "\n" + postaction->toString(); - tcCode += "\n$TC p4template update pipeline/" + pipelineName - + " postactions action " + pipelineName + "/postaction"; + absl::StrAppend(&tcCode, "\n", postaction->toString().string_view(), + "\n$TC p4template update pipeline/", pipelineName.string_view(), + " postactions action ", pipelineName.string_view(), "/postaction"); } - tcCode += "\n$TC p4template update pipeline/" + pipelineName + " state ready"; + absl::StrAppend(&tcCode, "\n$TC p4template update pipeline/", pipelineName.string_view(), " state ready"); return tcCode; } dbprint { out << toString(); } diff --git a/backends/tc/tcExterns.cpp b/backends/tc/tcExterns.cpp index d77b4bf3371..906e2ff3e1d 100644 --- a/backends/tc/tcExterns.cpp +++ b/backends/tc/tcExterns.cpp @@ -433,4 +433,49 @@ cstring InternetChecksumAlgorithmPNA::getConvertByteOrderFunction(unsigned width return emit; } +void EBPFDigestPNA::emitInitializer(EBPF::CodeBuilder *builder) const { + builder->newline(); + builder->emitIndent(); + builder->appendLine("__builtin_memset(&ext_params, 0, sizeof(struct p4tc_ext_bpf_params));"); + builder->emitIndent(); + builder->appendLine("ext_params.pipe_id = p4tc_filter_fields.pipeid;"); + builder->emitIndent(); + auto extId = tcIR->getExternId(externName); + BUG_CHECK(!extId.isNullOrEmpty(), "Extern ID not found"); + builder->appendFormat("ext_params.ext_id = %s;", extId); + builder->newline(); + builder->emitIndent(); + auto instId = tcIR->getExternInstanceId(externName, instanceName); + BUG_CHECK(instId != 0, "Extern instance ID not found"); + builder->appendFormat("ext_params.inst_id = %d;", instId); + builder->newline(); +} + +void EBPFDigestPNA::emitPushElement(EBPF::CodeBuilder *builder, const IR::Expression *elem, + Inspector *codegen) const { + emitInitializer(builder); + builder->newline(); + builder->emitIndent(); + builder->append("__builtin_memcpy(ext_params.in_params, &"); + codegen->visit(elem); + builder->append(", sizeof("); + this->valueType->declare(builder, cstring::empty, false); + builder->append("));"); + builder->newline(); + builder->emitIndent(); + builder->append("bpf_p4tc_extern_digest_pack(skb, &ext_params, sizeof(ext_params))"); +} + +void EBPFDigestPNA::emitPushElement(EBPF::CodeBuilder *builder, cstring elem) const { + emitInitializer(builder); + builder->newline(); + builder->emitIndent(); + builder->appendFormat("__builtin_memcpy(ext_params.in_params, &%s, sizeof(", elem); + this->valueType->declare(builder, cstring::empty, false); + builder->append("));"); + builder->newline(); + builder->emitIndent(); + builder->append("bpf_p4tc_extern_digest_pack(skb, &ext_params, sizeof(ext_params));"); +} + } // namespace TC diff --git a/backends/tc/tcExterns.h b/backends/tc/tcExterns.h index a70388215f5..95490ee6b0d 100644 --- a/backends/tc/tcExterns.h +++ b/backends/tc/tcExterns.h @@ -177,6 +177,25 @@ class EBPFInternetChecksumPNA : public EBPFChecksumPNA { const IR::MethodCallExpression *expr, Visitor *visitor) override; }; +class EBPFDigestPNA : public EBPF::EBPFDigestPSA { + const ConvertToBackendIR *tcIR; + cstring externName; + cstring instanceName; + + public: + EBPFDigestPNA(const EBPF::EBPFProgram *program, const IR::Declaration_Instance *di, + cstring externName, const ConvertToBackendIR *tcIR) + : EBPF::EBPFDigestPSA(program, di) { + this->tcIR = tcIR; + this->externName = externName; + this->instanceName = di->toString(); + } + void emitInitializer(EBPF::CodeBuilder *builder) const; + void emitPushElement(EBPF::CodeBuilder *builder, const IR::Expression *elem, + Inspector *codegen) const; + void emitPushElement(EBPF::CodeBuilder *builder, cstring elem) const; +}; + } // namespace TC #endif /* BACKENDS_TC_TCEXTERNS_H_ */ diff --git a/p4include/tc/pna.p4 b/p4include/tc/pna.p4 index e7cb518ce8a..01dad6a2099 100644 --- a/p4include/tc/pna.p4 +++ b/p4include/tc/pna.p4 @@ -554,10 +554,15 @@ extern ActionSelector { // BEGIN:Digest_extern extern Digest { Digest(); /// define a digest stream to the control plane - void pack(in T data); /// emit data into the stream + @tc_md_exec void pack(in T data); /// emit data into the stream } // END:Digest_extern +struct tc_ControlPath_Digest { + @tc_key bit<32> index; + @tc_data T data; +} + enum PNA_Source_t { FROM_HOST, FROM_NET diff --git a/testdata/p4tc_samples/digest.p4 b/testdata/p4tc_samples/digest.p4 new file mode 100644 index 00000000000..66effa8b9cf --- /dev/null +++ b/testdata/p4tc_samples/digest.p4 @@ -0,0 +1,154 @@ +/* -*- P4_16 -*- */ + +#include +#include + +#define L3_TABLE_SIZE 2048 + +/* + * CONST VALUES FOR TYPES + */ +const bit<8> IP_PROTO_TCP = 0x06; +const bit<16> ETHERTYPE_IPV4 = 0x0800; + +/* + * Standard ethernet header + */ +header ethernet_t { + @tc_type("macaddr") bit<48> dstAddr; + @tc_type("macaddr") bit<48> 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; + @tc_type("ipv4") bit<32> srcAddr; + @tc_type("ipv4") bit<32> dstAddr; +} + +struct my_ingress_headers_t { + ethernet_t ethernet; + ipv4_t ipv4; +} + + /****** G L O B A L I N G R E S S M E T A D A T A *********/ + +struct my_ingress_metadata_t { + @tc_type("dev") PortId_t ingress_port; + bool send_digest; +} + + /*********************** P A R S E R **************************/ +parser Ingress_Parser( + packet_in pkt, + out my_ingress_headers_t hdr, + inout my_ingress_metadata_t meta, + in pna_main_parser_input_metadata_t istd) +{ + + state start { + transition parse_ethernet; + } + + state parse_ethernet { + pkt.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + ETHERTYPE_IPV4: parse_ipv4; + default: reject; + } + } + state parse_ipv4 { + pkt.extract(hdr.ipv4); + transition select(hdr.ipv4.protocol) { + IP_PROTO_TCP : accept; + default: reject; + } + } +} + +struct mac_learn_digest_t { + @tc_type("macaddr") bit<48> srcAddr; + @tc_type("dev") PortId_t ingress_port; +}; + +/***************** M A T C H - A C T I O N *********************/ + +control ingress( + inout my_ingress_headers_t hdr, + inout my_ingress_metadata_t meta, + in pna_main_input_metadata_t istd, + inout pna_main_output_metadata_t ostd +) +{ + action send_nh(@tc_type("dev") PortId_t port, @tc_type("macaddr") bit<48> srcMac, @tc_type("macaddr") bit<48> dstMac) { + hdr.ethernet.srcAddr = srcMac; + hdr.ethernet.dstAddr = dstMac; + meta.ingress_port = istd.input_port; + meta.send_digest = true; + send_to_port(port); + } + + action drop() { + drop_packet(); + } + + table nh_table { + key = { + hdr.ipv4.dstAddr : exact @tc_type("ipv4") @name("dstAddr"); + } + actions = { + send_nh; + drop; + } + size = L3_TABLE_SIZE; + const default_action = drop; + } + + apply { + meta.send_digest = false; + + if (hdr.ipv4.isValid()) { + nh_table.apply(); + } + } +} + + /********************* D E P A R S E R ************************/ + +control Ingress_Deparser( + packet_out pkt, + inout my_ingress_headers_t hdr, + in my_ingress_metadata_t meta, + in pna_main_output_metadata_t ostd) +{ + Digest() digest_inst; + + apply { + if (meta.send_digest) { + mac_learn_digest_t mac_learn_digest; + mac_learn_digest.srcAddr = hdr.ethernet.srcAddr; + mac_learn_digest.ingress_port = meta.ingress_port; + digest_inst.pack(mac_learn_digest); + } + + pkt.emit(hdr.ethernet); + pkt.emit(hdr.ipv4); + } +} + +/************ F I N A L P A C K A G E ******************************/ + +PNA_NIC( + Ingress_Parser(), + ingress(), + Ingress_Deparser() +) main; \ No newline at end of file diff --git a/testdata/p4tc_samples/digest_01.p4 b/testdata/p4tc_samples/digest_01.p4 new file mode 100644 index 00000000000..4e3812ae2e3 --- /dev/null +++ b/testdata/p4tc_samples/digest_01.p4 @@ -0,0 +1,151 @@ +/* -*- P4_16 -*- */ + +#include +#include + +#define L3_TABLE_SIZE 2048 + +/* + * CONST VALUES FOR TYPES + */ +const bit<8> IP_PROTO_TCP = 0x06; +const bit<16> ETHERTYPE_IPV4 = 0x0800; + +/* + * Standard ethernet header + */ +header ethernet_t { + @tc_type("macaddr") bit<48> dstAddr; + @tc_type("macaddr") bit<48> 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; + @tc_type("ipv4") bit<32> srcAddr; + @tc_type("ipv4") bit<32> dstAddr; +} + +struct my_ingress_headers_t { + ethernet_t ethernet; + ipv4_t ipv4; +} + + /****** G L O B A L I N G R E S S M E T A D A T A *********/ + +struct my_ingress_metadata_t { + @tc_type("dev") PortId_t ingress_port; + bool send_digest; +} + + /*********************** P A R S E R **************************/ +parser Ingress_Parser( + packet_in pkt, + out my_ingress_headers_t hdr, + inout my_ingress_metadata_t meta, + in pna_main_parser_input_metadata_t istd) +{ + + state start { + transition parse_ethernet; + } + + state parse_ethernet { + pkt.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + ETHERTYPE_IPV4: parse_ipv4; + default: reject; + } + } + state parse_ipv4 { + pkt.extract(hdr.ipv4); + transition select(hdr.ipv4.protocol) { + IP_PROTO_TCP : accept; + default: reject; + } + } +} + +struct mac_learn_digest_t { + @tc_type("macaddr") bit<48> srcAddr; + @tc_type("dev") PortId_t ingress_port; +}; + +/***************** M A T C H - A C T I O N *********************/ + +control ingress( + inout my_ingress_headers_t hdr, + inout my_ingress_metadata_t meta, + in pna_main_input_metadata_t istd, + inout pna_main_output_metadata_t ostd +) +{ + action send_nh(@tc_type("dev") PortId_t port, @tc_type("macaddr") bit<48> srcMac, @tc_type("macaddr") bit<48> dstMac) { + hdr.ethernet.srcAddr = srcMac; + hdr.ethernet.dstAddr = dstMac; + meta.ingress_port = istd.input_port; + meta.send_digest = true; + send_to_port(port); + } + + action drop() { + drop_packet(); + } + + table nh_table { + key = { + hdr.ipv4.dstAddr : exact @tc_type("ipv4") @name("dstAddr"); + } + actions = { + send_nh; + drop; + } + size = L3_TABLE_SIZE; + const default_action = drop; + } + + apply { + meta.send_digest = false; + + if (hdr.ipv4.isValid()) { + nh_table.apply(); + } + } +} + + /********************* D E P A R S E R ************************/ + +control Ingress_Deparser( + packet_out pkt, + inout my_ingress_headers_t hdr, + in my_ingress_metadata_t meta, + in pna_main_output_metadata_t ostd) +{ + Digest>() digest_inst; + + apply { + if (meta.send_digest) { + digest_inst.pack(16); + } + + pkt.emit(hdr.ethernet); + pkt.emit(hdr.ipv4); + } +} + +/************ F I N A L P A C K A G E ******************************/ + +PNA_NIC( + Ingress_Parser(), + ingress(), + Ingress_Deparser() +) main; \ No newline at end of file diff --git a/testdata/p4tc_samples_outputs/digest.json b/testdata/p4tc_samples_outputs/digest.json new file mode 100644 index 00000000000..fde39a76894 --- /dev/null +++ b/testdata/p4tc_samples_outputs/digest.json @@ -0,0 +1,98 @@ +{ + "schema_version" : "1.0.0", + "pipeline_name" : "digest", + "externs" : [ + { + "name" : "Digest", + "id" : "0x05000000", + "permissions" : "0x19b6", + "instances" : [ + { + "inst_name" : "Ingress_Deparser.digest_inst", + "inst_id" : 1, + "params" : [ + { + "id" : 1, + "name" : "index", + "type" : "bit32", + "attr" : "tc_key", + "bitwidth" : 32 + }, + { + "id" : 2, + "name" : "srcAddr", + "type" : "macaddr", + "attr" : "param", + "bitwidth" : 48 + }, + { + "id" : 3, + "name" : "ingress_port", + "type" : "dev", + "attr" : "param", + "bitwidth" : 32 + } + ] + } + ] + } + ], + "tables" : [ + { + "name" : "ingress/nh_table", + "id" : 1, + "tentries" : 2048, + "permissions" : "0x3da4", + "nummask" : 8, + "keysize" : 32, + "keyfields" : [ + { + "id" : 1, + "name" : "dstAddr", + "type" : "ipv4", + "match_type" : "exact", + "bitwidth" : 32 + } + ], + "actions" : [ + { + "id" : 1, + "name" : "ingress/send_nh", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [ + { + "id" : 1, + "name" : "port", + "type" : "dev", + "bitwidth" : 32 + }, + { + "id" : 2, + "name" : "srcMac", + "type" : "macaddr", + "bitwidth" : 48 + }, + { + "id" : 3, + "name" : "dstMac", + "type" : "macaddr", + "bitwidth" : 48 + } + ], + "default_hit_action" : false, + "default_miss_action" : false + }, + { + "id" : 2, + "name" : "ingress/drop", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [], + "default_hit_action" : false, + "default_miss_action" : true + } + ] + } + ] +} \ No newline at end of file diff --git a/testdata/p4tc_samples_outputs/digest.p4-stderr b/testdata/p4tc_samples_outputs/digest.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4tc_samples_outputs/digest.template b/testdata/p4tc_samples_outputs/digest.template new file mode 100755 index 00000000000..02ca5838c4c --- /dev/null +++ b/testdata/p4tc_samples_outputs/digest.template @@ -0,0 +1,30 @@ +#!/bin/bash -x + +set -e + +TC="tc" +$TC p4template create pipeline/digest numtables 1 + +$TC p4template create action/digest/ingress/send_nh actid 1 \ + param port type dev \ + param srcMac type macaddr \ + param dstMac type macaddr +$TC p4template update action/digest/ingress/send_nh state active + +$TC p4template create action/digest/ingress/drop actid 2 +$TC p4template update action/digest/ingress/drop state active + +$TC p4template create extern/root/Digest extid 0x05000000 numinstances 1 tc_acl 0x19b6 has_exec_method + +$TC p4template create extern_inst/digest/Digest/Ingress_Deparser.digest_inst instid 1 \ +tc_numel 0 \ +control_path tc_key index ptype bit32 id 1 param srcAddr ptype macaddr id 2 param ingress_port ptype dev id 3 + +$TC p4template create table/digest/ingress/nh_table \ + tblid 1 \ + type exact \ + keysz 32 nummasks 8 permissions 0x3da4 tentries 2048 \ + table_acts act name digest/ingress/send_nh \ + act name digest/ingress/drop +$TC p4template update table/digest/ingress/nh_table default_miss_action permissions 0x1024 action digest/ingress/drop +$TC p4template update pipeline/digest state ready \ No newline at end of file diff --git a/testdata/p4tc_samples_outputs/digest_01.json b/testdata/p4tc_samples_outputs/digest_01.json new file mode 100644 index 00000000000..01f3ad9d4e2 --- /dev/null +++ b/testdata/p4tc_samples_outputs/digest_01.json @@ -0,0 +1,91 @@ +{ + "schema_version" : "1.0.0", + "pipeline_name" : "digest_01", + "externs" : [ + { + "name" : "Digest", + "id" : "0x05000000", + "permissions" : "0x19b6", + "instances" : [ + { + "inst_name" : "Ingress_Deparser.digest_inst", + "inst_id" : 1, + "params" : [ + { + "id" : 1, + "name" : "index", + "type" : "bit32", + "attr" : "tc_key", + "bitwidth" : 32 + }, + { + "id" : 2, + "name" : "data", + "type" : "bit32", + "attr" : "param", + "bitwidth" : 32 + } + ] + } + ] + } + ], + "tables" : [ + { + "name" : "ingress/nh_table", + "id" : 1, + "tentries" : 2048, + "permissions" : "0x3da4", + "nummask" : 8, + "keysize" : 32, + "keyfields" : [ + { + "id" : 1, + "name" : "dstAddr", + "type" : "ipv4", + "match_type" : "exact", + "bitwidth" : 32 + } + ], + "actions" : [ + { + "id" : 1, + "name" : "ingress/send_nh", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [ + { + "id" : 1, + "name" : "port", + "type" : "dev", + "bitwidth" : 32 + }, + { + "id" : 2, + "name" : "srcMac", + "type" : "macaddr", + "bitwidth" : 48 + }, + { + "id" : 3, + "name" : "dstMac", + "type" : "macaddr", + "bitwidth" : 48 + } + ], + "default_hit_action" : false, + "default_miss_action" : false + }, + { + "id" : 2, + "name" : "ingress/drop", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [], + "default_hit_action" : false, + "default_miss_action" : true + } + ] + } + ] +} \ No newline at end of file diff --git a/testdata/p4tc_samples_outputs/digest_01.p4-stderr b/testdata/p4tc_samples_outputs/digest_01.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4tc_samples_outputs/digest_01.template b/testdata/p4tc_samples_outputs/digest_01.template new file mode 100755 index 00000000000..37a7148a3f2 --- /dev/null +++ b/testdata/p4tc_samples_outputs/digest_01.template @@ -0,0 +1,30 @@ +#!/bin/bash -x + +set -e + +TC="tc" +$TC p4template create pipeline/digest_01 numtables 1 + +$TC p4template create action/digest_01/ingress/send_nh actid 1 \ + param port type dev \ + param srcMac type macaddr \ + param dstMac type macaddr +$TC p4template update action/digest_01/ingress/send_nh state active + +$TC p4template create action/digest_01/ingress/drop actid 2 +$TC p4template update action/digest_01/ingress/drop state active + +$TC p4template create extern/root/Digest extid 0x05000000 numinstances 1 tc_acl 0x19b6 has_exec_method + +$TC p4template create extern_inst/digest_01/Digest/Ingress_Deparser.digest_inst instid 1 \ +tc_numel 0 \ +control_path tc_key index ptype bit32 id 1 param data ptype bit32 id 2 + +$TC p4template create table/digest_01/ingress/nh_table \ + tblid 1 \ + type exact \ + keysz 32 nummasks 8 permissions 0x3da4 tentries 2048 \ + table_acts act name digest_01/ingress/send_nh \ + act name digest_01/ingress/drop +$TC p4template update table/digest_01/ingress/nh_table default_miss_action permissions 0x1024 action digest_01/ingress/drop +$TC p4template update pipeline/digest_01 state ready \ No newline at end of file diff --git a/testdata/p4tc_samples_outputs/digest_01_control_blocks.c b/testdata/p4tc_samples_outputs/digest_01_control_blocks.c new file mode 100644 index 00000000000..940cc86b8b2 --- /dev/null +++ b/testdata/p4tc_samples_outputs/digest_01_control_blocks.c @@ -0,0 +1,313 @@ +#include "digest_01_parser.h" +struct p4tc_filter_fields p4tc_filter_fields; + +struct internal_metadata { + __u16 pkt_ether_type; +} __attribute__((aligned(4))); + +struct __attribute__((__packed__)) ingress_nh_table_key { + u32 keysz; + u32 maskid; + u32 field0; /* hdr.ipv4.dstAddr */ +} __attribute__((aligned(8))); +#define INGRESS_NH_TABLE_ACT_INGRESS_SEND_NH 1 +#define INGRESS_NH_TABLE_ACT_INGRESS_DROP 2 +#define INGRESS_NH_TABLE_ACT_NOACTION 0 +struct __attribute__((__packed__)) ingress_nh_table_value { + unsigned int action; + u32 hit:1, + is_default_miss_act:1, + is_default_hit_act:1; + union { + struct { + } _NoAction; + struct __attribute__((__packed__)) { + u32 port; + u64 srcMac; + u64 dstMac; + } ingress_send_nh; + struct { + } ingress_drop; + } u; +}; + +static __always_inline int process(struct __sk_buff *skb, struct my_ingress_headers_t *hdr, struct pna_global_metadata *compiler_meta__) +{ + struct hdr_md *hdrMd; + + unsigned ebpf_packetOffsetInBits_save = 0; + ParserError_t ebpf_errorCode = NoError; + void* pkt = ((void*)(long)skb->data); + u8* hdr_start = pkt; + void* ebpf_packetEnd = ((void*)(long)skb->data_end); + u32 ebpf_zero = 0; + u32 ebpf_one = 1; + unsigned char ebpf_byte; + u32 pkt_len = skb->len; + + struct my_ingress_metadata_t *meta; + hdrMd = BPF_MAP_LOOKUP_ELEM(hdr_md_cpumap, &ebpf_zero); + if (!hdrMd) + return TC_ACT_SHOT; + unsigned ebpf_packetOffsetInBits = hdrMd->ebpf_packetOffsetInBits; + hdr_start = pkt + BYTES(ebpf_packetOffsetInBits); + hdr = &(hdrMd->cpumap_hdr); + meta = &(hdrMd->cpumap_usermeta); +{ + u8 hit; + { + meta->send_digest = false; + if (/* hdr->ipv4.isValid() */ + hdr->ipv4.ebpf_valid) { +/* nh_table_0.apply() */ + { + /* construct key */ + struct p4tc_table_entry_act_bpf_params__local params = { + .pipeid = p4tc_filter_fields.pipeid, + .tblid = 1 + }; + struct ingress_nh_table_key key; + __builtin_memset(&key, 0, sizeof(key)); + key.keysz = 32; + key.field0 = hdr->ipv4.dstAddr; + struct p4tc_table_entry_act_bpf *act_bpf; + /* value */ + struct ingress_nh_table_value *value = NULL; + /* perform lookup */ + act_bpf = bpf_p4tc_tbl_read(skb, ¶ms, sizeof(params), &key, sizeof(key)); + value = (struct ingress_nh_table_value *)act_bpf; + if (value == NULL) { + /* miss; find default action */ + hit = 0; + } else { + hit = value->hit; + } + if (value != NULL) { + /* run action */ + switch (value->action) { + case INGRESS_NH_TABLE_ACT_INGRESS_SEND_NH: + { + hdr->ethernet.srcAddr = value->u.ingress_send_nh.srcMac; + hdr->ethernet.dstAddr = value->u.ingress_send_nh.dstMac; + meta->ingress_port = skb->ifindex; + meta->send_digest = true; + /* send_to_port(value->u.ingress_send_nh.port) */ + compiler_meta__->drop = false; + send_to_port(value->u.ingress_send_nh.port); + } + break; + case INGRESS_NH_TABLE_ACT_INGRESS_DROP: + { +/* drop_packet() */ + drop_packet(); + } + break; + case INGRESS_NH_TABLE_ACT_NOACTION: + { + } + break; + } + } else { + } + } +; } + + } + } + { + struct p4tc_ext_bpf_params ext_params = {}; +{ +if (meta->send_digest) { +/* digest_inst_0.pack(16) */ + { + u32 digest_entry = 16; + + __builtin_memset(&ext_params, 0, sizeof(struct p4tc_ext_bpf_params)); + ext_params.pipe_id = p4tc_filter_fields.pipeid; + ext_params.ext_id = 0x05000000; + ext_params.inst_id = 1; + + __builtin_memcpy(ext_params.in_params, &digest_entry, sizeof(u32 )); + bpf_p4tc_extern_digest_pack(skb, &ext_params, sizeof(ext_params)); } +; } + + ; + ; + } + + if (compiler_meta__->drop) { + return TC_ACT_SHOT; + } + int outHeaderLength = 0; + if (hdr->ethernet.ebpf_valid) { + outHeaderLength += 112; + } +; if (hdr->ipv4.ebpf_valid) { + outHeaderLength += 160; + } +; + int outHeaderOffset = BYTES(outHeaderLength) - (hdr_start - (u8*)pkt); + if (outHeaderOffset != 0) { + int returnCode = 0; + returnCode = bpf_skb_adjust_room(skb, outHeaderOffset, 1, 0); + if (returnCode) { + return TC_ACT_SHOT; + } + } + pkt = ((void*)(long)skb->data); + ebpf_packetEnd = ((void*)(long)skb->data_end); + ebpf_packetOffsetInBits = 0; + if (hdr->ethernet.ebpf_valid) { + if (ebpf_packetEnd < pkt + BYTES(ebpf_packetOffsetInBits + 112)) { + return TC_ACT_SHOT; + } + + ebpf_byte = ((char*)(&hdr->ethernet.dstAddr))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.dstAddr))[1]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 1, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.dstAddr))[2]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 2, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.dstAddr))[3]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 3, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.dstAddr))[4]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 4, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.dstAddr))[5]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 5, (ebpf_byte)); + ebpf_packetOffsetInBits += 48; + + ebpf_byte = ((char*)(&hdr->ethernet.srcAddr))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.srcAddr))[1]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 1, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.srcAddr))[2]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 2, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.srcAddr))[3]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 3, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.srcAddr))[4]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 4, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.srcAddr))[5]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 5, (ebpf_byte)); + ebpf_packetOffsetInBits += 48; + + hdr->ethernet.etherType = bpf_htons(hdr->ethernet.etherType); + ebpf_byte = ((char*)(&hdr->ethernet.etherType))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.etherType))[1]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 1, (ebpf_byte)); + ebpf_packetOffsetInBits += 16; + + } +; if (hdr->ipv4.ebpf_valid) { + if (ebpf_packetEnd < pkt + BYTES(ebpf_packetOffsetInBits + 160)) { + return TC_ACT_SHOT; + } + + ebpf_byte = ((char*)(&hdr->ipv4.version))[0]; + write_partial(pkt + BYTES(ebpf_packetOffsetInBits) + 0, 4, 4, (ebpf_byte >> 0)); + ebpf_packetOffsetInBits += 4; + + ebpf_byte = ((char*)(&hdr->ipv4.ihl))[0]; + write_partial(pkt + BYTES(ebpf_packetOffsetInBits) + 0, 4, 0, (ebpf_byte >> 0)); + ebpf_packetOffsetInBits += 4; + + ebpf_byte = ((char*)(&hdr->ipv4.diffserv))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_packetOffsetInBits += 8; + + hdr->ipv4.totalLen = bpf_htons(hdr->ipv4.totalLen); + ebpf_byte = ((char*)(&hdr->ipv4.totalLen))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ipv4.totalLen))[1]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 1, (ebpf_byte)); + ebpf_packetOffsetInBits += 16; + + hdr->ipv4.identification = bpf_htons(hdr->ipv4.identification); + ebpf_byte = ((char*)(&hdr->ipv4.identification))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ipv4.identification))[1]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 1, (ebpf_byte)); + ebpf_packetOffsetInBits += 16; + + ebpf_byte = ((char*)(&hdr->ipv4.flags))[0]; + write_partial(pkt + BYTES(ebpf_packetOffsetInBits) + 0, 3, 5, (ebpf_byte >> 0)); + ebpf_packetOffsetInBits += 3; + + hdr->ipv4.fragOffset = bpf_htons(hdr->ipv4.fragOffset << 3); + ebpf_byte = ((char*)(&hdr->ipv4.fragOffset))[0]; + write_partial(pkt + BYTES(ebpf_packetOffsetInBits) + 0, 5, 0, (ebpf_byte >> 3)); + write_partial(pkt + BYTES(ebpf_packetOffsetInBits) + 0 + 1, 3, 5, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ipv4.fragOffset))[1]; + write_partial(pkt + BYTES(ebpf_packetOffsetInBits) + 1, 5, 0, (ebpf_byte >> 3)); + ebpf_packetOffsetInBits += 13; + + ebpf_byte = ((char*)(&hdr->ipv4.ttl))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_packetOffsetInBits += 8; + + ebpf_byte = ((char*)(&hdr->ipv4.protocol))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_packetOffsetInBits += 8; + + hdr->ipv4.hdrChecksum = bpf_htons(hdr->ipv4.hdrChecksum); + ebpf_byte = ((char*)(&hdr->ipv4.hdrChecksum))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ipv4.hdrChecksum))[1]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 1, (ebpf_byte)); + ebpf_packetOffsetInBits += 16; + + ebpf_byte = ((char*)(&hdr->ipv4.srcAddr))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ipv4.srcAddr))[1]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 1, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ipv4.srcAddr))[2]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 2, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ipv4.srcAddr))[3]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 3, (ebpf_byte)); + ebpf_packetOffsetInBits += 32; + + ebpf_byte = ((char*)(&hdr->ipv4.dstAddr))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ipv4.dstAddr))[1]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 1, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ipv4.dstAddr))[2]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 2, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ipv4.dstAddr))[3]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 3, (ebpf_byte)); + ebpf_packetOffsetInBits += 32; + + } +; + } + return -1; +} +SEC("p4tc/main") +int tc_ingress_func(struct __sk_buff *skb) { + struct pna_global_metadata *compiler_meta__ = (struct pna_global_metadata *) skb->cb; + if (compiler_meta__->pass_to_kernel == true) return TC_ACT_OK; + compiler_meta__->drop = false; + if (!compiler_meta__->recirculated) { + compiler_meta__->mark = 153; + struct internal_metadata *md = (struct internal_metadata *)(unsigned long)skb->data_meta; + if ((void *) ((struct internal_metadata *) md + 1) <= (void *)(long)skb->data) { + __u16 *ether_type = (__u16 *) ((void *) (long)skb->data + 12); + if ((void *) ((__u16 *) ether_type + 1) > (void *) (long) skb->data_end) { + return TC_ACT_SHOT; + } + *ether_type = md->pkt_ether_type; + } + } + struct hdr_md *hdrMd; + struct my_ingress_headers_t *hdr; + int ret = -1; + ret = process(skb, (struct my_ingress_headers_t *) hdr, compiler_meta__); + if (ret != -1) { + return ret; + } + if (!compiler_meta__->drop && compiler_meta__->egress_port == 0) { + compiler_meta__->pass_to_kernel = true; + return bpf_redirect(skb->ifindex, BPF_F_INGRESS); + } + return bpf_redirect(compiler_meta__->egress_port, 0); +} +char _license[] SEC("license") = "GPL"; diff --git a/testdata/p4tc_samples_outputs/digest_01_parser.c b/testdata/p4tc_samples_outputs/digest_01_parser.c new file mode 100644 index 00000000000..7deda9dc41a --- /dev/null +++ b/testdata/p4tc_samples_outputs/digest_01_parser.c @@ -0,0 +1,140 @@ +#include "digest_01_parser.h" + +struct p4tc_filter_fields p4tc_filter_fields; + +static __always_inline int run_parser(struct __sk_buff *skb, struct my_ingress_headers_t *hdr, struct pna_global_metadata *compiler_meta__) +{ + struct hdr_md *hdrMd; + + unsigned ebpf_packetOffsetInBits_save = 0; + ParserError_t ebpf_errorCode = NoError; + void* pkt = ((void*)(long)skb->data); + u8* hdr_start = pkt; + void* ebpf_packetEnd = ((void*)(long)skb->data_end); + u32 ebpf_zero = 0; + u32 ebpf_one = 1; + unsigned char ebpf_byte; + u32 pkt_len = skb->len; + + struct my_ingress_metadata_t *meta; + + hdrMd = BPF_MAP_LOOKUP_ELEM(hdr_md_cpumap, &ebpf_zero); + if (!hdrMd) + return TC_ACT_SHOT; + __builtin_memset(hdrMd, 0, sizeof(struct hdr_md)); + + unsigned ebpf_packetOffsetInBits = 0; + hdr = &(hdrMd->cpumap_hdr); + meta = &(hdrMd->cpumap_usermeta); + { + goto start; + parse_ipv4: { +/* extract(hdr->ipv4) */ + if ((u8*)ebpf_packetEnd < hdr_start + BYTES(160 + 0)) { + ebpf_errorCode = PacketTooShort; + goto reject; + } + + hdr->ipv4.version = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)) >> 4) & EBPF_MASK(u8, 4)); + ebpf_packetOffsetInBits += 4; + + hdr->ipv4.ihl = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits))) & EBPF_MASK(u8, 4)); + ebpf_packetOffsetInBits += 4; + + hdr->ipv4.diffserv = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + hdr->ipv4.totalLen = (u16)((load_half(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 16; + + hdr->ipv4.identification = (u16)((load_half(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 16; + + hdr->ipv4.flags = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)) >> 5) & EBPF_MASK(u8, 3)); + ebpf_packetOffsetInBits += 3; + + hdr->ipv4.fragOffset = (u16)((load_half(pkt, BYTES(ebpf_packetOffsetInBits))) & EBPF_MASK(u16, 13)); + ebpf_packetOffsetInBits += 13; + + hdr->ipv4.ttl = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + hdr->ipv4.protocol = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + hdr->ipv4.hdrChecksum = (u16)((load_half(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 16; + + __builtin_memcpy(&hdr->ipv4.srcAddr, pkt + BYTES(ebpf_packetOffsetInBits), 4); + ebpf_packetOffsetInBits += 32; + + __builtin_memcpy(&hdr->ipv4.dstAddr, pkt + BYTES(ebpf_packetOffsetInBits), 4); + ebpf_packetOffsetInBits += 32; + + + hdr->ipv4.ebpf_valid = 1; + hdr_start += BYTES(160); + +; + u8 select_0; + select_0 = hdr->ipv4.protocol; + if (select_0 == 0x6)goto accept; + if ((select_0 & 0x0) == (0x0 & 0x0))goto reject; + else goto reject; + } + start: { +/* extract(hdr->ethernet) */ + if ((u8*)ebpf_packetEnd < hdr_start + BYTES(112 + 0)) { + ebpf_errorCode = PacketTooShort; + goto reject; + } + + __builtin_memcpy(&hdr->ethernet.dstAddr, pkt + BYTES(ebpf_packetOffsetInBits), 6); + ebpf_packetOffsetInBits += 48; + + __builtin_memcpy(&hdr->ethernet.srcAddr, pkt + BYTES(ebpf_packetOffsetInBits), 6); + ebpf_packetOffsetInBits += 48; + + hdr->ethernet.etherType = (u16)((load_half(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 16; + + + hdr->ethernet.ebpf_valid = 1; + hdr_start += BYTES(112); + +; + u16 select_1; + select_1 = hdr->ethernet.etherType; + if (select_1 == 0x800)goto parse_ipv4; + if ((select_1 & 0x0) == (0x0 & 0x0))goto reject; + else goto reject; + } + + reject: { + if (ebpf_errorCode == 0) { + return TC_ACT_SHOT; + } + compiler_meta__->parser_error = ebpf_errorCode; + goto accept; + } + + } + + accept: + hdrMd->ebpf_packetOffsetInBits = ebpf_packetOffsetInBits; + return -1; +} + +SEC("p4tc/parse") +int tc_parse_func(struct __sk_buff *skb) { + struct pna_global_metadata *compiler_meta__ = (struct pna_global_metadata *) skb->cb; + struct hdr_md *hdrMd; + struct my_ingress_headers_t *hdr; + int ret = -1; + ret = run_parser(skb, (struct my_ingress_headers_t *) hdr, compiler_meta__); + if (ret != -1) { + return ret; + } + return TC_ACT_PIPE; + } +char _license[] SEC("license") = "GPL"; diff --git a/testdata/p4tc_samples_outputs/digest_01_parser.h b/testdata/p4tc_samples_outputs/digest_01_parser.h new file mode 100644 index 00000000000..cc42507e0b8 --- /dev/null +++ b/testdata/p4tc_samples_outputs/digest_01_parser.h @@ -0,0 +1,161 @@ +#include "ebpf_kernel.h" + +#include +#include +#include "pna.h" + +#define EBPF_MASK(t, w) ((((t)(1)) << (w)) - (t)1) +#define BYTES(w) ((w) / 8) +#define write_partial(a, w, s, v) do { *((u8*)a) = ((*((u8*)a)) & ~(EBPF_MASK(u8, w) << s)) | (v << s) ; } while (0) +#define write_byte(base, offset, v) do { *(u8*)((base) + (offset)) = (v); } while (0) +#define bpf_trace_message(fmt, ...) + + +struct ethernet_t { + u64 dstAddr; /* bit<48> */ + u64 srcAddr; /* bit<48> */ + u16 etherType; /* bit<16> */ + u8 ebpf_valid; +}; +struct ipv4_t { + u8 version; /* bit<4> */ + u8 ihl; /* bit<4> */ + u8 diffserv; /* bit<8> */ + u16 totalLen; /* bit<16> */ + u16 identification; /* bit<16> */ + u8 flags; /* bit<3> */ + u16 fragOffset; /* bit<13> */ + u8 ttl; /* bit<8> */ + u8 protocol; /* bit<8> */ + u16 hdrChecksum; /* bit<16> */ + u32 srcAddr; /* bit<32> */ + u32 dstAddr; /* bit<32> */ + u8 ebpf_valid; +}; +struct my_ingress_headers_t { + struct ethernet_t ethernet; /* ethernet_t */ + struct ipv4_t ipv4; /* ipv4_t */ +}; +struct my_ingress_metadata_t { + u32 ingress_port; /* PortId_t */ + u8 send_digest; /* bool */ +}; +struct mac_learn_digest_t { + u64 srcAddr; /* bit<48> */ + u32 ingress_port; /* PortId_t */ +}; + +struct hdr_md { + struct my_ingress_headers_t cpumap_hdr; + struct my_ingress_metadata_t cpumap_usermeta; + unsigned ebpf_packetOffsetInBits; + __u8 __hook; +}; + +struct p4tc_filter_fields { + __u32 pipeid; + __u32 handle; + __u32 classid; + __u32 chain; + __u32 blockid; + __be16 proto; + __u16 prio; +}; + +REGISTER_START() +REGISTER_TABLE(hdr_md_cpumap, BPF_MAP_TYPE_PERCPU_ARRAY, u32, struct hdr_md, 2) +BPF_ANNOTATE_KV_PAIR(hdr_md_cpumap, u32, struct hdr_md) +REGISTER_END() + +static __always_inline +void crc16_update(u16 * reg, const u8 * data, u16 data_size, const u16 poly) { + if (data_size <= 8) + data += data_size - 1; + #pragma clang loop unroll(full) + for (u16 i = 0; i < data_size; i++) { + bpf_trace_message("CRC16: data byte: %x\n", *data); + *reg ^= *data; + for (u8 bit = 0; bit < 8; bit++) { + *reg = (*reg) & 1 ? ((*reg) >> 1) ^ poly : (*reg) >> 1; + } + if (data_size <= 8) + data--; + else + data++; + } +} +static __always_inline u16 crc16_finalize(u16 reg) { + return reg; +} +static __always_inline +void crc32_update(u32 * reg, const u8 * data, u16 data_size, const u32 poly) { + u32* current = (u32*) data; + u32 index = 0; + u32 lookup_key = 0; + u32 lookup_value = 0; + u32 lookup_value1 = 0; + u32 lookup_value2 = 0; + u32 lookup_value3 = 0; + u32 lookup_value4 = 0; + u32 lookup_value5 = 0; + u32 lookup_value6 = 0; + u32 lookup_value7 = 0; + u32 lookup_value8 = 0; + u16 tmp = 0; + if (crc32_table != NULL) { + for (u16 i = data_size; i >= 8; i -= 8) { + /* Vars one and two will have swapped byte order if data_size == 8 */ + if (data_size == 8) current = (u32 *)(data + 4); + bpf_trace_message("CRC32: data dword: %x\n", *current); + u32 one = (data_size == 8 ? __builtin_bswap32(*current--) : *current++) ^ *reg; + bpf_trace_message("CRC32: data dword: %x\n", *current); + u32 two = (data_size == 8 ? __builtin_bswap32(*current--) : *current++); + lookup_key = (one & 0x000000FF); + lookup_value8 = crc32_table[(u16)(1792 + (u8)lookup_key)]; + lookup_key = (one >> 8) & 0x000000FF; + lookup_value7 = crc32_table[(u16)(1536 + (u8)lookup_key)]; + lookup_key = (one >> 16) & 0x000000FF; + lookup_value6 = crc32_table[(u16)(1280 + (u8)lookup_key)]; + lookup_key = one >> 24; + lookup_value5 = crc32_table[(u16)(1024 + (u8)(lookup_key))]; + lookup_key = (two & 0x000000FF); + lookup_value4 = crc32_table[(u16)(768 + (u8)lookup_key)]; + lookup_key = (two >> 8) & 0x000000FF; + lookup_value3 = crc32_table[(u16)(512 + (u8)lookup_key)]; + lookup_key = (two >> 16) & 0x000000FF; + lookup_value2 = crc32_table[(u16)(256 + (u8)lookup_key)]; + lookup_key = two >> 24; + lookup_value1 = crc32_table[(u8)(lookup_key)]; + *reg = lookup_value8 ^ lookup_value7 ^ lookup_value6 ^ lookup_value5 ^ + lookup_value4 ^ lookup_value3 ^ lookup_value2 ^ lookup_value1; + tmp += 8; + } + volatile int std_algo_lookup_key = 0; + if (data_size < 8) { + unsigned char *currentChar = (unsigned char *) current; + currentChar += data_size - 1; + for (u16 i = tmp; i < data_size; i++) { + bpf_trace_message("CRC32: data byte: %x\n", *currentChar); + std_algo_lookup_key = (u32)(((*reg) & 0xFF) ^ *currentChar--); + if (std_algo_lookup_key >= 0) { + lookup_value = crc32_table[(u8)(std_algo_lookup_key & 255)]; + } + *reg = ((*reg) >> 8) ^ lookup_value; + } + } else { + /* Consume data not processed by slice-by-8 algorithm above, these data are in network byte order */ + unsigned char *currentChar = (unsigned char *) current; + for (u16 i = tmp; i < data_size; i++) { + bpf_trace_message("CRC32: data byte: %x\n", *currentChar); + std_algo_lookup_key = (u32)(((*reg) & 0xFF) ^ *currentChar++); + if (std_algo_lookup_key >= 0) { + lookup_value = crc32_table[(u8)(std_algo_lookup_key & 255)]; + } + *reg = ((*reg) >> 8) ^ lookup_value; + } + } + } +} +static __always_inline u32 crc32_finalize(u32 reg) { + return reg ^ 0xFFFFFFFF; +} diff --git a/testdata/p4tc_samples_outputs/digest_control_blocks.c b/testdata/p4tc_samples_outputs/digest_control_blocks.c new file mode 100644 index 00000000000..21bd4337217 --- /dev/null +++ b/testdata/p4tc_samples_outputs/digest_control_blocks.c @@ -0,0 +1,314 @@ +#include "digest_parser.h" +struct p4tc_filter_fields p4tc_filter_fields; + +struct internal_metadata { + __u16 pkt_ether_type; +} __attribute__((aligned(4))); + +struct __attribute__((__packed__)) ingress_nh_table_key { + u32 keysz; + u32 maskid; + u32 field0; /* hdr.ipv4.dstAddr */ +} __attribute__((aligned(8))); +#define INGRESS_NH_TABLE_ACT_INGRESS_SEND_NH 1 +#define INGRESS_NH_TABLE_ACT_INGRESS_DROP 2 +#define INGRESS_NH_TABLE_ACT_NOACTION 0 +struct __attribute__((__packed__)) ingress_nh_table_value { + unsigned int action; + u32 hit:1, + is_default_miss_act:1, + is_default_hit_act:1; + union { + struct { + } _NoAction; + struct __attribute__((__packed__)) { + u32 port; + u64 srcMac; + u64 dstMac; + } ingress_send_nh; + struct { + } ingress_drop; + } u; +}; + +static __always_inline int process(struct __sk_buff *skb, struct my_ingress_headers_t *hdr, struct pna_global_metadata *compiler_meta__) +{ + struct hdr_md *hdrMd; + + unsigned ebpf_packetOffsetInBits_save = 0; + ParserError_t ebpf_errorCode = NoError; + void* pkt = ((void*)(long)skb->data); + u8* hdr_start = pkt; + void* ebpf_packetEnd = ((void*)(long)skb->data_end); + u32 ebpf_zero = 0; + u32 ebpf_one = 1; + unsigned char ebpf_byte; + u32 pkt_len = skb->len; + + struct my_ingress_metadata_t *meta; + hdrMd = BPF_MAP_LOOKUP_ELEM(hdr_md_cpumap, &ebpf_zero); + if (!hdrMd) + return TC_ACT_SHOT; + unsigned ebpf_packetOffsetInBits = hdrMd->ebpf_packetOffsetInBits; + hdr_start = pkt + BYTES(ebpf_packetOffsetInBits); + hdr = &(hdrMd->cpumap_hdr); + meta = &(hdrMd->cpumap_usermeta); +{ + u8 hit; + { + meta->send_digest = false; + if (/* hdr->ipv4.isValid() */ + hdr->ipv4.ebpf_valid) { +/* nh_table_0.apply() */ + { + /* construct key */ + struct p4tc_table_entry_act_bpf_params__local params = { + .pipeid = p4tc_filter_fields.pipeid, + .tblid = 1 + }; + struct ingress_nh_table_key key; + __builtin_memset(&key, 0, sizeof(key)); + key.keysz = 32; + key.field0 = hdr->ipv4.dstAddr; + struct p4tc_table_entry_act_bpf *act_bpf; + /* value */ + struct ingress_nh_table_value *value = NULL; + /* perform lookup */ + act_bpf = bpf_p4tc_tbl_read(skb, ¶ms, sizeof(params), &key, sizeof(key)); + value = (struct ingress_nh_table_value *)act_bpf; + if (value == NULL) { + /* miss; find default action */ + hit = 0; + } else { + hit = value->hit; + } + if (value != NULL) { + /* run action */ + switch (value->action) { + case INGRESS_NH_TABLE_ACT_INGRESS_SEND_NH: + { + hdr->ethernet.srcAddr = value->u.ingress_send_nh.srcMac; + hdr->ethernet.dstAddr = value->u.ingress_send_nh.dstMac; + meta->ingress_port = skb->ifindex; + meta->send_digest = true; + /* send_to_port(value->u.ingress_send_nh.port) */ + compiler_meta__->drop = false; + send_to_port(value->u.ingress_send_nh.port); + } + break; + case INGRESS_NH_TABLE_ACT_INGRESS_DROP: + { +/* drop_packet() */ + drop_packet(); + } + break; + case INGRESS_NH_TABLE_ACT_NOACTION: + { + } + break; + } + } else { + } + } +; } + + } + } + { + struct p4tc_ext_bpf_params ext_params = {}; + struct mac_learn_digest_t mac_learn_digest_0; + __builtin_memset((void *) &mac_learn_digest_0, 0, sizeof(struct mac_learn_digest_t )); +{ +if (meta->send_digest) { + mac_learn_digest_0.srcAddr = hdr->ethernet.srcAddr; + mac_learn_digest_0.ingress_port = meta->ingress_port; + /* digest_inst_0.pack(mac_learn_digest_0) */ + + __builtin_memset(&ext_params, 0, sizeof(struct p4tc_ext_bpf_params)); + ext_params.pipe_id = p4tc_filter_fields.pipeid; + ext_params.ext_id = 0x05000000; + ext_params.inst_id = 1; + + __builtin_memcpy(ext_params.in_params, &mac_learn_digest_0, sizeof(struct mac_learn_digest_t )); + bpf_p4tc_extern_digest_pack(skb, &ext_params, sizeof(ext_params)); + } + ; + ; + } + + if (compiler_meta__->drop) { + return TC_ACT_SHOT; + } + int outHeaderLength = 0; + if (hdr->ethernet.ebpf_valid) { + outHeaderLength += 112; + } +; if (hdr->ipv4.ebpf_valid) { + outHeaderLength += 160; + } +; + int outHeaderOffset = BYTES(outHeaderLength) - (hdr_start - (u8*)pkt); + if (outHeaderOffset != 0) { + int returnCode = 0; + returnCode = bpf_skb_adjust_room(skb, outHeaderOffset, 1, 0); + if (returnCode) { + return TC_ACT_SHOT; + } + } + pkt = ((void*)(long)skb->data); + ebpf_packetEnd = ((void*)(long)skb->data_end); + ebpf_packetOffsetInBits = 0; + if (hdr->ethernet.ebpf_valid) { + if (ebpf_packetEnd < pkt + BYTES(ebpf_packetOffsetInBits + 112)) { + return TC_ACT_SHOT; + } + + ebpf_byte = ((char*)(&hdr->ethernet.dstAddr))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.dstAddr))[1]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 1, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.dstAddr))[2]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 2, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.dstAddr))[3]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 3, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.dstAddr))[4]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 4, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.dstAddr))[5]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 5, (ebpf_byte)); + ebpf_packetOffsetInBits += 48; + + ebpf_byte = ((char*)(&hdr->ethernet.srcAddr))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.srcAddr))[1]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 1, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.srcAddr))[2]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 2, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.srcAddr))[3]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 3, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.srcAddr))[4]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 4, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.srcAddr))[5]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 5, (ebpf_byte)); + ebpf_packetOffsetInBits += 48; + + hdr->ethernet.etherType = bpf_htons(hdr->ethernet.etherType); + ebpf_byte = ((char*)(&hdr->ethernet.etherType))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ethernet.etherType))[1]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 1, (ebpf_byte)); + ebpf_packetOffsetInBits += 16; + + } +; if (hdr->ipv4.ebpf_valid) { + if (ebpf_packetEnd < pkt + BYTES(ebpf_packetOffsetInBits + 160)) { + return TC_ACT_SHOT; + } + + ebpf_byte = ((char*)(&hdr->ipv4.version))[0]; + write_partial(pkt + BYTES(ebpf_packetOffsetInBits) + 0, 4, 4, (ebpf_byte >> 0)); + ebpf_packetOffsetInBits += 4; + + ebpf_byte = ((char*)(&hdr->ipv4.ihl))[0]; + write_partial(pkt + BYTES(ebpf_packetOffsetInBits) + 0, 4, 0, (ebpf_byte >> 0)); + ebpf_packetOffsetInBits += 4; + + ebpf_byte = ((char*)(&hdr->ipv4.diffserv))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_packetOffsetInBits += 8; + + hdr->ipv4.totalLen = bpf_htons(hdr->ipv4.totalLen); + ebpf_byte = ((char*)(&hdr->ipv4.totalLen))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ipv4.totalLen))[1]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 1, (ebpf_byte)); + ebpf_packetOffsetInBits += 16; + + hdr->ipv4.identification = bpf_htons(hdr->ipv4.identification); + ebpf_byte = ((char*)(&hdr->ipv4.identification))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ipv4.identification))[1]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 1, (ebpf_byte)); + ebpf_packetOffsetInBits += 16; + + ebpf_byte = ((char*)(&hdr->ipv4.flags))[0]; + write_partial(pkt + BYTES(ebpf_packetOffsetInBits) + 0, 3, 5, (ebpf_byte >> 0)); + ebpf_packetOffsetInBits += 3; + + hdr->ipv4.fragOffset = bpf_htons(hdr->ipv4.fragOffset << 3); + ebpf_byte = ((char*)(&hdr->ipv4.fragOffset))[0]; + write_partial(pkt + BYTES(ebpf_packetOffsetInBits) + 0, 5, 0, (ebpf_byte >> 3)); + write_partial(pkt + BYTES(ebpf_packetOffsetInBits) + 0 + 1, 3, 5, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ipv4.fragOffset))[1]; + write_partial(pkt + BYTES(ebpf_packetOffsetInBits) + 1, 5, 0, (ebpf_byte >> 3)); + ebpf_packetOffsetInBits += 13; + + ebpf_byte = ((char*)(&hdr->ipv4.ttl))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_packetOffsetInBits += 8; + + ebpf_byte = ((char*)(&hdr->ipv4.protocol))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_packetOffsetInBits += 8; + + hdr->ipv4.hdrChecksum = bpf_htons(hdr->ipv4.hdrChecksum); + ebpf_byte = ((char*)(&hdr->ipv4.hdrChecksum))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ipv4.hdrChecksum))[1]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 1, (ebpf_byte)); + ebpf_packetOffsetInBits += 16; + + ebpf_byte = ((char*)(&hdr->ipv4.srcAddr))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ipv4.srcAddr))[1]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 1, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ipv4.srcAddr))[2]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 2, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ipv4.srcAddr))[3]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 3, (ebpf_byte)); + ebpf_packetOffsetInBits += 32; + + ebpf_byte = ((char*)(&hdr->ipv4.dstAddr))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ipv4.dstAddr))[1]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 1, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ipv4.dstAddr))[2]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 2, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->ipv4.dstAddr))[3]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 3, (ebpf_byte)); + ebpf_packetOffsetInBits += 32; + + } +; + } + return -1; +} +SEC("p4tc/main") +int tc_ingress_func(struct __sk_buff *skb) { + struct pna_global_metadata *compiler_meta__ = (struct pna_global_metadata *) skb->cb; + if (compiler_meta__->pass_to_kernel == true) return TC_ACT_OK; + compiler_meta__->drop = false; + if (!compiler_meta__->recirculated) { + compiler_meta__->mark = 153; + struct internal_metadata *md = (struct internal_metadata *)(unsigned long)skb->data_meta; + if ((void *) ((struct internal_metadata *) md + 1) <= (void *)(long)skb->data) { + __u16 *ether_type = (__u16 *) ((void *) (long)skb->data + 12); + if ((void *) ((__u16 *) ether_type + 1) > (void *) (long) skb->data_end) { + return TC_ACT_SHOT; + } + *ether_type = md->pkt_ether_type; + } + } + struct hdr_md *hdrMd; + struct my_ingress_headers_t *hdr; + int ret = -1; + ret = process(skb, (struct my_ingress_headers_t *) hdr, compiler_meta__); + if (ret != -1) { + return ret; + } + if (!compiler_meta__->drop && compiler_meta__->egress_port == 0) { + compiler_meta__->pass_to_kernel = true; + return bpf_redirect(skb->ifindex, BPF_F_INGRESS); + } + return bpf_redirect(compiler_meta__->egress_port, 0); +} +char _license[] SEC("license") = "GPL"; diff --git a/testdata/p4tc_samples_outputs/digest_parser.c b/testdata/p4tc_samples_outputs/digest_parser.c new file mode 100644 index 00000000000..a0c23e6fcec --- /dev/null +++ b/testdata/p4tc_samples_outputs/digest_parser.c @@ -0,0 +1,140 @@ +#include "digest_parser.h" + +struct p4tc_filter_fields p4tc_filter_fields; + +static __always_inline int run_parser(struct __sk_buff *skb, struct my_ingress_headers_t *hdr, struct pna_global_metadata *compiler_meta__) +{ + struct hdr_md *hdrMd; + + unsigned ebpf_packetOffsetInBits_save = 0; + ParserError_t ebpf_errorCode = NoError; + void* pkt = ((void*)(long)skb->data); + u8* hdr_start = pkt; + void* ebpf_packetEnd = ((void*)(long)skb->data_end); + u32 ebpf_zero = 0; + u32 ebpf_one = 1; + unsigned char ebpf_byte; + u32 pkt_len = skb->len; + + struct my_ingress_metadata_t *meta; + + hdrMd = BPF_MAP_LOOKUP_ELEM(hdr_md_cpumap, &ebpf_zero); + if (!hdrMd) + return TC_ACT_SHOT; + __builtin_memset(hdrMd, 0, sizeof(struct hdr_md)); + + unsigned ebpf_packetOffsetInBits = 0; + hdr = &(hdrMd->cpumap_hdr); + meta = &(hdrMd->cpumap_usermeta); + { + goto start; + parse_ipv4: { +/* extract(hdr->ipv4) */ + if ((u8*)ebpf_packetEnd < hdr_start + BYTES(160 + 0)) { + ebpf_errorCode = PacketTooShort; + goto reject; + } + + hdr->ipv4.version = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)) >> 4) & EBPF_MASK(u8, 4)); + ebpf_packetOffsetInBits += 4; + + hdr->ipv4.ihl = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits))) & EBPF_MASK(u8, 4)); + ebpf_packetOffsetInBits += 4; + + hdr->ipv4.diffserv = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + hdr->ipv4.totalLen = (u16)((load_half(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 16; + + hdr->ipv4.identification = (u16)((load_half(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 16; + + hdr->ipv4.flags = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)) >> 5) & EBPF_MASK(u8, 3)); + ebpf_packetOffsetInBits += 3; + + hdr->ipv4.fragOffset = (u16)((load_half(pkt, BYTES(ebpf_packetOffsetInBits))) & EBPF_MASK(u16, 13)); + ebpf_packetOffsetInBits += 13; + + hdr->ipv4.ttl = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + hdr->ipv4.protocol = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + hdr->ipv4.hdrChecksum = (u16)((load_half(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 16; + + __builtin_memcpy(&hdr->ipv4.srcAddr, pkt + BYTES(ebpf_packetOffsetInBits), 4); + ebpf_packetOffsetInBits += 32; + + __builtin_memcpy(&hdr->ipv4.dstAddr, pkt + BYTES(ebpf_packetOffsetInBits), 4); + ebpf_packetOffsetInBits += 32; + + + hdr->ipv4.ebpf_valid = 1; + hdr_start += BYTES(160); + +; + u8 select_0; + select_0 = hdr->ipv4.protocol; + if (select_0 == 0x6)goto accept; + if ((select_0 & 0x0) == (0x0 & 0x0))goto reject; + else goto reject; + } + start: { +/* extract(hdr->ethernet) */ + if ((u8*)ebpf_packetEnd < hdr_start + BYTES(112 + 0)) { + ebpf_errorCode = PacketTooShort; + goto reject; + } + + __builtin_memcpy(&hdr->ethernet.dstAddr, pkt + BYTES(ebpf_packetOffsetInBits), 6); + ebpf_packetOffsetInBits += 48; + + __builtin_memcpy(&hdr->ethernet.srcAddr, pkt + BYTES(ebpf_packetOffsetInBits), 6); + ebpf_packetOffsetInBits += 48; + + hdr->ethernet.etherType = (u16)((load_half(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 16; + + + hdr->ethernet.ebpf_valid = 1; + hdr_start += BYTES(112); + +; + u16 select_1; + select_1 = hdr->ethernet.etherType; + if (select_1 == 0x800)goto parse_ipv4; + if ((select_1 & 0x0) == (0x0 & 0x0))goto reject; + else goto reject; + } + + reject: { + if (ebpf_errorCode == 0) { + return TC_ACT_SHOT; + } + compiler_meta__->parser_error = ebpf_errorCode; + goto accept; + } + + } + + accept: + hdrMd->ebpf_packetOffsetInBits = ebpf_packetOffsetInBits; + return -1; +} + +SEC("p4tc/parse") +int tc_parse_func(struct __sk_buff *skb) { + struct pna_global_metadata *compiler_meta__ = (struct pna_global_metadata *) skb->cb; + struct hdr_md *hdrMd; + struct my_ingress_headers_t *hdr; + int ret = -1; + ret = run_parser(skb, (struct my_ingress_headers_t *) hdr, compiler_meta__); + if (ret != -1) { + return ret; + } + return TC_ACT_PIPE; + } +char _license[] SEC("license") = "GPL"; diff --git a/testdata/p4tc_samples_outputs/digest_parser.h b/testdata/p4tc_samples_outputs/digest_parser.h new file mode 100644 index 00000000000..cc42507e0b8 --- /dev/null +++ b/testdata/p4tc_samples_outputs/digest_parser.h @@ -0,0 +1,161 @@ +#include "ebpf_kernel.h" + +#include +#include +#include "pna.h" + +#define EBPF_MASK(t, w) ((((t)(1)) << (w)) - (t)1) +#define BYTES(w) ((w) / 8) +#define write_partial(a, w, s, v) do { *((u8*)a) = ((*((u8*)a)) & ~(EBPF_MASK(u8, w) << s)) | (v << s) ; } while (0) +#define write_byte(base, offset, v) do { *(u8*)((base) + (offset)) = (v); } while (0) +#define bpf_trace_message(fmt, ...) + + +struct ethernet_t { + u64 dstAddr; /* bit<48> */ + u64 srcAddr; /* bit<48> */ + u16 etherType; /* bit<16> */ + u8 ebpf_valid; +}; +struct ipv4_t { + u8 version; /* bit<4> */ + u8 ihl; /* bit<4> */ + u8 diffserv; /* bit<8> */ + u16 totalLen; /* bit<16> */ + u16 identification; /* bit<16> */ + u8 flags; /* bit<3> */ + u16 fragOffset; /* bit<13> */ + u8 ttl; /* bit<8> */ + u8 protocol; /* bit<8> */ + u16 hdrChecksum; /* bit<16> */ + u32 srcAddr; /* bit<32> */ + u32 dstAddr; /* bit<32> */ + u8 ebpf_valid; +}; +struct my_ingress_headers_t { + struct ethernet_t ethernet; /* ethernet_t */ + struct ipv4_t ipv4; /* ipv4_t */ +}; +struct my_ingress_metadata_t { + u32 ingress_port; /* PortId_t */ + u8 send_digest; /* bool */ +}; +struct mac_learn_digest_t { + u64 srcAddr; /* bit<48> */ + u32 ingress_port; /* PortId_t */ +}; + +struct hdr_md { + struct my_ingress_headers_t cpumap_hdr; + struct my_ingress_metadata_t cpumap_usermeta; + unsigned ebpf_packetOffsetInBits; + __u8 __hook; +}; + +struct p4tc_filter_fields { + __u32 pipeid; + __u32 handle; + __u32 classid; + __u32 chain; + __u32 blockid; + __be16 proto; + __u16 prio; +}; + +REGISTER_START() +REGISTER_TABLE(hdr_md_cpumap, BPF_MAP_TYPE_PERCPU_ARRAY, u32, struct hdr_md, 2) +BPF_ANNOTATE_KV_PAIR(hdr_md_cpumap, u32, struct hdr_md) +REGISTER_END() + +static __always_inline +void crc16_update(u16 * reg, const u8 * data, u16 data_size, const u16 poly) { + if (data_size <= 8) + data += data_size - 1; + #pragma clang loop unroll(full) + for (u16 i = 0; i < data_size; i++) { + bpf_trace_message("CRC16: data byte: %x\n", *data); + *reg ^= *data; + for (u8 bit = 0; bit < 8; bit++) { + *reg = (*reg) & 1 ? ((*reg) >> 1) ^ poly : (*reg) >> 1; + } + if (data_size <= 8) + data--; + else + data++; + } +} +static __always_inline u16 crc16_finalize(u16 reg) { + return reg; +} +static __always_inline +void crc32_update(u32 * reg, const u8 * data, u16 data_size, const u32 poly) { + u32* current = (u32*) data; + u32 index = 0; + u32 lookup_key = 0; + u32 lookup_value = 0; + u32 lookup_value1 = 0; + u32 lookup_value2 = 0; + u32 lookup_value3 = 0; + u32 lookup_value4 = 0; + u32 lookup_value5 = 0; + u32 lookup_value6 = 0; + u32 lookup_value7 = 0; + u32 lookup_value8 = 0; + u16 tmp = 0; + if (crc32_table != NULL) { + for (u16 i = data_size; i >= 8; i -= 8) { + /* Vars one and two will have swapped byte order if data_size == 8 */ + if (data_size == 8) current = (u32 *)(data + 4); + bpf_trace_message("CRC32: data dword: %x\n", *current); + u32 one = (data_size == 8 ? __builtin_bswap32(*current--) : *current++) ^ *reg; + bpf_trace_message("CRC32: data dword: %x\n", *current); + u32 two = (data_size == 8 ? __builtin_bswap32(*current--) : *current++); + lookup_key = (one & 0x000000FF); + lookup_value8 = crc32_table[(u16)(1792 + (u8)lookup_key)]; + lookup_key = (one >> 8) & 0x000000FF; + lookup_value7 = crc32_table[(u16)(1536 + (u8)lookup_key)]; + lookup_key = (one >> 16) & 0x000000FF; + lookup_value6 = crc32_table[(u16)(1280 + (u8)lookup_key)]; + lookup_key = one >> 24; + lookup_value5 = crc32_table[(u16)(1024 + (u8)(lookup_key))]; + lookup_key = (two & 0x000000FF); + lookup_value4 = crc32_table[(u16)(768 + (u8)lookup_key)]; + lookup_key = (two >> 8) & 0x000000FF; + lookup_value3 = crc32_table[(u16)(512 + (u8)lookup_key)]; + lookup_key = (two >> 16) & 0x000000FF; + lookup_value2 = crc32_table[(u16)(256 + (u8)lookup_key)]; + lookup_key = two >> 24; + lookup_value1 = crc32_table[(u8)(lookup_key)]; + *reg = lookup_value8 ^ lookup_value7 ^ lookup_value6 ^ lookup_value5 ^ + lookup_value4 ^ lookup_value3 ^ lookup_value2 ^ lookup_value1; + tmp += 8; + } + volatile int std_algo_lookup_key = 0; + if (data_size < 8) { + unsigned char *currentChar = (unsigned char *) current; + currentChar += data_size - 1; + for (u16 i = tmp; i < data_size; i++) { + bpf_trace_message("CRC32: data byte: %x\n", *currentChar); + std_algo_lookup_key = (u32)(((*reg) & 0xFF) ^ *currentChar--); + if (std_algo_lookup_key >= 0) { + lookup_value = crc32_table[(u8)(std_algo_lookup_key & 255)]; + } + *reg = ((*reg) >> 8) ^ lookup_value; + } + } else { + /* Consume data not processed by slice-by-8 algorithm above, these data are in network byte order */ + unsigned char *currentChar = (unsigned char *) current; + for (u16 i = tmp; i < data_size; i++) { + bpf_trace_message("CRC32: data byte: %x\n", *currentChar); + std_algo_lookup_key = (u32)(((*reg) & 0xFF) ^ *currentChar++); + if (std_algo_lookup_key >= 0) { + lookup_value = crc32_table[(u8)(std_algo_lookup_key & 255)]; + } + *reg = ((*reg) >> 8) ^ lookup_value; + } + } + } +} +static __always_inline u32 crc32_finalize(u32 reg) { + return reg ^ 0xFFFFFFFF; +}