diff --git a/backends/tc/backend.cpp b/backends/tc/backend.cpp index 4d36cb91d6..4e2cf942a9 100644 --- a/backends/tc/backend.cpp +++ b/backends/tc/backend.cpp @@ -354,6 +354,13 @@ void ConvertToBackendIR::updateDefaultMissAction(const IR::P4Table *t, IR::TCTab if (defaultActionProperty->isConstant) { tabledef->setDefaultMissConst(true); } + bool isTCMayOverride = false; + const IR::Annotation *overrideAnno = + defaultActionProperty->getAnnotations()->getSingle( + ParseTCAnnotations::tcMayOverride); + if (overrideAnno) { + isTCMayOverride = true; + } bool directionParamPresent = false; auto paramList = actionCall->action->getParameters(); for (auto param : paramList->parameters) { @@ -361,22 +368,36 @@ void ConvertToBackendIR::updateDefaultMissAction(const IR::P4Table *t, IR::TCTab } if (!directionParamPresent) { auto i = 0; + if (isTCMayOverride) { + if (paramList->parameters.empty()) + ::warning(ErrorType::WARN_INVALID, + "%1% annotation cannot be used with default_action without " + "parameters", + overrideAnno); + else + tabledef->setTcMayOverride(); + } for (auto param : paramList->parameters) { auto defaultParam = new IR::TCDefaultActionParam(); - defaultParam->setParamName(param->name.originalName); + for (auto actionParam : tcAction->actionParams) { + if (actionParam->paramName == param->name.originalName) { + defaultParam->setParamDetail(actionParam); + } + } auto defaultArg = methodexp->arguments->at(i++); if (auto constVal = defaultArg->expression->to()) { - bool sign; - if (const IR::Type_Bits *tb = constVal->type->to()) { - sign = tb->isSigned; - } else { - sign = false; - } - defaultParam->setDefaultValue( - Util::toString(constVal->value, 0, sign, constVal->base)); + if (!isTCMayOverride) + defaultParam->setDefaultValue( + Util::toString(constVal->value, 0, true, constVal->base)); + tabledef->defaultMissActionParams.push_back(defaultParam); } - tabledef->defaultMissActionParams.push_back(defaultParam); } + } else { + if (isTCMayOverride) + ::warning(ErrorType::WARN_INVALID, + "%1% annotation cannot be used with default_action with " + "directional parameters", + overrideAnno); } } } @@ -398,13 +419,13 @@ void ConvertToBackendIR::updateDefaultHitAction(const IR::P4Table *t, IR::TCTabl if (anno->name == IR::Annotation::tableOnlyAnnotation) { isTableOnly = true; } - if (anno->name == ParseTCAnnotations::default_hit) { + if (anno->name == ParseTCAnnotations::defaultHit) { isDefaultHit = true; defaultHit++; auto adecl = refMap->getDeclaration(action->getPath(), true); defaultActionName = externalName(adecl); } - if (anno->name == ParseTCAnnotations::default_hit_const) { + if (anno->name == ParseTCAnnotations::defaultHitConst) { isDefaultHitConst = true; defaultHitConst++; auto adecl = refMap->getDeclaration(action->getPath(), true); diff --git a/backends/tc/ebpfCodeGen.cpp b/backends/tc/ebpfCodeGen.cpp index 31b2c83184..95f1be5202 100644 --- a/backends/tc/ebpfCodeGen.cpp +++ b/backends/tc/ebpfCodeGen.cpp @@ -124,12 +124,41 @@ void PNAEbpfGenerator::emitP4TCFilterFields(EBPF::CodeBuilder *builder) const { builder->emitIndent(); builder->appendFormat("__u16 prio"); builder->endOfStatement(true); - + emitP4TCActionParam(builder); builder->blockEnd(false); builder->endOfStatement(true); builder->newline(); } +void PNAEbpfGenerator::emitP4TCActionParam(EBPF::CodeBuilder *builder) const { + std::vector actionParamList; + for (auto table : tcIR->tcPipeline->tableDefs) { + if (table->isTcMayOverride) { + cstring tblName = table->getTableName(); + cstring defaultActionName = table->defaultMissAction->getActionName(); + auto actionNameStr = defaultActionName.c_str(); + for (long unsigned int i = 0; i < defaultActionName.size(); i++) { + if (actionNameStr[i] == '/') { + defaultActionName = defaultActionName.substr(i + 1, defaultActionName.size()); + break; + } + } + for (auto param : table->defaultMissActionParams) { + cstring paramName = param->paramDetail->getParamName(); + cstring placeholder = tblName + "_" + defaultActionName + "_" + paramName; + auto itr = find(actionParamList.begin(), actionParamList.end(), placeholder); + if (itr == actionParamList.end()) { + actionParamList.push_back(placeholder); + cstring typeName = param->paramDetail->getParamType(); + builder->emitIndent(); + builder->appendFormat("%s %s", typeName, placeholder); + builder->endOfStatement(true); + } + } + } + } +} + void PNAEbpfGenerator::emitPipelineInstances(EBPF::CodeBuilder *builder) const { pipeline->parser->emitValueSetInstances(builder); pipeline->deparser->emitDigestInstances(builder); @@ -1162,7 +1191,7 @@ const PNAEbpfGenerator *ConvertToEbpfPNA::build(const IR::ToplevelBlock *tlb) { tlb->getProgram()->apply(*pipeline_converter); auto tcIngress = pipeline_converter->getEbpfPipeline(); - return new PNAArchTC(options, ebpfTypes, xdp, tcIngress); + return new PNAArchTC(options, ebpfTypes, xdp, tcIngress, tcIR); } const IR::Node *ConvertToEbpfPNA::preorder(IR::ToplevelBlock *tlb) { diff --git a/backends/tc/ebpfCodeGen.h b/backends/tc/ebpfCodeGen.h index 1d5786a746..1cfe126ec0 100644 --- a/backends/tc/ebpfCodeGen.h +++ b/backends/tc/ebpfCodeGen.h @@ -29,10 +29,11 @@ class EBPFPnaParser; class PNAEbpfGenerator : public EBPF::EbpfCodeGenerator { public: EBPF::EBPFPipeline *pipeline; + const ConvertToBackendIR *tcIR; PNAEbpfGenerator(const EbpfOptions &options, std::vector &ebpfTypes, - EBPF::EBPFPipeline *pipeline) - : EBPF::EbpfCodeGenerator(options, ebpfTypes), pipeline(pipeline) {} + EBPF::EBPFPipeline *pipeline, const ConvertToBackendIR *tcIR) + : EBPF::EbpfCodeGenerator(options, ebpfTypes), pipeline(pipeline), tcIR(tcIR) {} virtual void emit(EBPF::CodeBuilder *builder) const = 0; virtual void emitInstances(EBPF::CodeBuilder *builder) const = 0; @@ -46,6 +47,7 @@ class PNAEbpfGenerator : public EBPF::EbpfCodeGenerator { void emitGlobalHeadersMetadata(EBPF::CodeBuilder *builder) const override; void emitPipelineInstances(EBPF::CodeBuilder *builder) const override; void emitP4TCFilterFields(EBPF::CodeBuilder *builder) const; + void emitP4TCActionParam(EBPF::CodeBuilder *builder) const; cstring getProgramName() const; }; @@ -89,8 +91,9 @@ class PNAArchTC : public PNAEbpfGenerator { EBPF::XDPHelpProgram *xdp; PNAArchTC(const EbpfOptions &options, std::vector &ebpfTypes, - EBPF::XDPHelpProgram *xdp, EBPF::EBPFPipeline *pipeline) - : PNAEbpfGenerator(options, ebpfTypes, pipeline), xdp(xdp) {} + EBPF::XDPHelpProgram *xdp, EBPF::EBPFPipeline *pipeline, + const ConvertToBackendIR *tcIR) + : PNAEbpfGenerator(options, ebpfTypes, pipeline, tcIR), xdp(xdp) {} void emit(EBPF::CodeBuilder *builder) const override; void emitParser(EBPF::CodeBuilder *builder) const override; diff --git a/backends/tc/tc.def b/backends/tc/tc.def index b2453a68ef..bac2c3969d 100644 --- a/backends/tc/tc.def +++ b/backends/tc/tc.def @@ -45,29 +45,6 @@ class TCKernelMetadata { dbprint { out << toString(); } } -class TCDefaultActionParam { - cstring paramName; - cstring defaultValue; - void setParamName(cstring pN) { - paramName = pN; - } - void setDefaultValue(cstring dV) { - defaultValue = dV; - } - TCDefaultActionParam() { - paramName = nullptr; - defaultValue = nullptr; - } - toString { - std::string tcActionParam = ""; - tcActionParam += " param "; - tcActionParam += paramName; - tcActionParam += " " + defaultValue; - return tcActionParam; - } - dbprint { out << toString(); } -} - class TCActionParam { cstring paramName; unsigned dataType; @@ -91,6 +68,36 @@ class TCActionParam { cstring getName() const { return "param." + paramName; } + cstring getParamType() const { + std::string paramType = ""; + switch(dataType) { + case TC::BIT_TYPE : + paramType += "__u" + Util::toString(bitSize); + break; + case TC::DEV_TYPE : + paramType += "dev"; + break; + case TC::MACADDR_TYPE : + paramType += "macaddr"; + break; + case TC::IPV4_TYPE : + paramType += "ipv4"; + break; + case TC::IPV6_TYPE : + paramType += "ipv6"; + break; + case TC::BE16_TYPE : + paramType += "__be16"; + break; + case TC::BE32_TYPE : + paramType += "__be32"; + break; + case TC::BE64_TYPE : + paramType += "__be64"; + break; + } + return paramType; + } toString { std::string tcActionParam = ""; tcActionParam += "\n\tparam "; @@ -127,6 +134,29 @@ class TCActionParam { dbprint { out << toString(); } } +class TCDefaultActionParam { + TCActionParam paramDetail; + cstring defaultValue; + void setParamDetail(TCActionParam pN) { + paramDetail = pN; + } + void setDefaultValue(cstring dV) { + defaultValue = dV; + } + TCDefaultActionParam() { + paramDetail = nullptr; + defaultValue = nullptr; + } + toString { + std::string tcActionParam = ""; + tcActionParam += " " + paramDetail->paramName; + if (defaultValue != nullptr) + tcActionParam += " " + defaultValue; + return tcActionParam; + } + dbprint { out << toString(); } +} + class TCAction { cstring actionName; cstring pipelineName; @@ -137,6 +167,9 @@ class TCAction { tcAction += "/" + actionName; return tcAction; } + cstring getActionName() const { + return actionName; + } void setPipelineName(cstring pN) { pipelineName = pN; } @@ -204,6 +237,7 @@ class TCTable { TCAction defaultMissAction; optional safe_vector defaultMissActionParams; bool isDefaultMissConst; + bool isTcMayOverride; ordered_map actionList; safe_vector const_entries; @@ -231,12 +265,18 @@ class TCTable { void setDefaultMissConst(bool i) { isDefaultMissConst = i; } + void setTcMayOverride() { + isTcMayOverride = true; + } void addAction(TCAction action, unsigned flag) { actionList.emplace(action, flag); } void addConstEntries(TCEntry entry) { const_entries.push_back(entry); } + cstring getTableName() const { + return tableName; + } cstring printMatchType(unsigned matchType) const { cstring matchTypeString = ""; switch(matchType) { @@ -265,6 +305,7 @@ class TCTable { defaultMissAction = nullptr; isDefaultHitConst = false; isDefaultMissConst = false; + isTcMayOverride = false; } toString { std::string tcTable = ""; @@ -309,9 +350,12 @@ class TCTable { tcTable += " permissions 0x1024"; } tcTable += " action " + defaultMissAction->getName(); - for (auto param : defaultMissActionParams) { + if (!defaultMissActionParams.empty()) + tcTable += " param"; + for (auto param : defaultMissActionParams) tcTable += param->toString(); - } + if (isTcMayOverride) + tcTable += " flags runtime"; } if (const_entries.size() != 0) { for (auto entry : const_entries) { @@ -333,8 +377,6 @@ class TCPipeline { unsigned numTables; safe_vector actionDefs; safe_vector tableDefs; - TCAction preaction; - TCAction postaction; void setPipelineName(cstring pName) { pipelineName = pName; } @@ -347,19 +389,10 @@ class TCPipeline { void addTableDefinition(TCTable tableDef) { tableDefs.push_back(tableDef); } - void setPipelinePreAction(TCAction action) { - preaction = action; - } - void setPipelinePostAction(TCAction action) { - postaction = action; - } TCPipeline() { Util::SourceInfo* srcinfo = new Util::SourceInfo(); Node::srcInfo = *srcinfo; pipelineName = nullptr; - numTables = 0; - preaction = nullptr; - postaction = nullptr; } toString { std::string tcCode = "#!/bin/bash -x\n"; @@ -378,16 +411,6 @@ class TCPipeline { tcCode += "\n" + t->toString(); } } - if (preaction != nullptr) { - tcCode += "\n" + preaction->toString(); - tcCode += "\n$TC p4template update pipeline/" + pipelineName - + " preactions action " + pipelineName + "/preaction"; - } - if (postaction != nullptr) { - tcCode += "\n" + postaction->toString(); - tcCode += "\n$TC p4template update pipeline/" + pipelineName - + " postactions action " + pipelineName + "/postaction"; - } tcCode += "\n$TC p4template update pipeline/" + pipelineName + " state ready"; return tcCode; } diff --git a/backends/tc/tcAnnotations.cpp b/backends/tc/tcAnnotations.cpp index 99481ddbfb..8587e22c70 100644 --- a/backends/tc/tcAnnotations.cpp +++ b/backends/tc/tcAnnotations.cpp @@ -18,9 +18,10 @@ and limitations under the License. namespace TC { -const cstring ParseTCAnnotations::default_hit = "default_hit"; -const cstring ParseTCAnnotations::default_hit_const = "default_hit_const"; +const cstring ParseTCAnnotations::defaultHit = "default_hit"; +const cstring ParseTCAnnotations::defaultHitConst = "default_hit_const"; const cstring ParseTCAnnotations::tcType = "tc_type"; const cstring ParseTCAnnotations::numMask = "nummask"; +const cstring ParseTCAnnotations::tcMayOverride = "tc_may_override"; } // namespace TC diff --git a/backends/tc/tcAnnotations.h b/backends/tc/tcAnnotations.h index 574a7f7f04..8665ffbc50 100644 --- a/backends/tc/tcAnnotations.h +++ b/backends/tc/tcAnnotations.h @@ -25,15 +25,17 @@ namespace TC { class ParseTCAnnotations : public P4::ParseAnnotations { public: // TC specific annotations - static const cstring default_hit; - static const cstring default_hit_const; + static const cstring defaultHit; + static const cstring defaultHitConst; static const cstring tcType; static const cstring numMask; + static const cstring tcMayOverride; ParseTCAnnotations() - : P4::ParseAnnotations("TC", true, - {PARSE_EMPTY(default_hit), PARSE_EMPTY(default_hit_const), - PARSE_CONSTANT_OR_STRING_LITERAL(tcType), - PARSE_CONSTANT_OR_STRING_LITERAL(numMask)}) {} + : P4::ParseAnnotations( + "TC", true, + {PARSE_EMPTY(defaultHit), PARSE_EMPTY(defaultHitConst), + PARSE_CONSTANT_OR_STRING_LITERAL(tcType), PARSE_CONSTANT_OR_STRING_LITERAL(numMask), + PARSE_EMPTY(tcMayOverride)}) {} }; } // namespace TC diff --git a/testdata/p4tc_samples/tc_may_override_example_01.p4 b/testdata/p4tc_samples/tc_may_override_example_01.p4 new file mode 100644 index 0000000000..8a4a37a22c --- /dev/null +++ b/testdata/p4tc_samples/tc_may_override_example_01.p4 @@ -0,0 +1,134 @@ +#include +#include + +typedef bit<48> EthernetAddress; + +header ethernet_t { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + @tc_type ("ipv4") bit<32> srcAddr; + @tc_type ("ipv4") bit<32> dstAddr; +} + +////////////////////////////////////////////////////////////////////// +// Struct types for holding user-defined collections of headers and +// metadata in the P4 developer's program. +// +// Note: The names of these struct types are completely up to the P4 +// developer, as are their member fields, with the only restriction +// being that the structs intended to contain headers should only +// contain members whose types are header, header stack, or +// header_union. +////////////////////////////////////////////////////////////////////// + +struct main_metadata_t { + // empty for this skeleton +} + +// User-defined struct containing all of those headers parsed in the +// main parser. +struct headers_t { + ethernet_t ethernet; + ipv4_t ipv4; +} + +parser MainParserImpl( + packet_in pkt, + out headers_t hdr, + inout main_metadata_t main_meta, + in pna_main_parser_input_metadata_t istd) +{ + state start { + pkt.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + 0x0800 : parse_ipv4; + default : accept; + } + } + state parse_ipv4 { + pkt.extract(hdr.ipv4); + transition accept; + } +} + +control MainControlImpl( + inout headers_t hdr, // from main parser + inout main_metadata_t user_meta, // from main parser, to "next block" + in pna_main_input_metadata_t istd, + inout pna_main_output_metadata_t ostd) +{ + action next_hop(PortId_t vport) { + send_to_port(vport); + } + action default_route_drop() { + drop_packet(); + } + action drop() { + drop_packet(); + } + + table ipv4_tbl_1 { + key = { + hdr.ipv4.dstAddr : exact; + istd.input_port : exact; + } + actions = { + next_hop; + default_route_drop; + } + @tc_may_override default_action = next_hop((PortId_t)123); + } + table ipv4_tbl_2 { + key = { + hdr.ipv4.dstAddr : exact; + hdr.ipv4.srcAddr : exact; + hdr.ipv4.protocol : exact; + } + actions = { + next_hop; + drop; + } + default_action = drop; + } + + apply { + if (hdr.ipv4.isValid()) { + ipv4_tbl_1.apply(); + ipv4_tbl_2.apply(); + } + } +} + +control MainDeparserImpl( + packet_out pkt, + inout headers_t hdr, // from main control + in main_metadata_t user_meta, // from main control + in pna_main_output_metadata_t ostd) +{ + apply { + pkt.emit(hdr.ethernet); + pkt.emit(hdr.ipv4); + } +} + +// BEGIN:Package_Instantiation_Example +PNA_NIC( + MainParserImpl(), + MainControlImpl(), + MainDeparserImpl() + ) main; +// END:Package_Instantiation_Example diff --git a/testdata/p4tc_samples/tc_may_override_example_02.p4 b/testdata/p4tc_samples/tc_may_override_example_02.p4 new file mode 100644 index 0000000000..18a7a456b7 --- /dev/null +++ b/testdata/p4tc_samples/tc_may_override_example_02.p4 @@ -0,0 +1,134 @@ +#include +#include + +typedef bit<48> EthernetAddress; + +header ethernet_t { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + @tc_type ("ipv4") bit<32> srcAddr; + @tc_type ("ipv4") bit<32> dstAddr; +} + +////////////////////////////////////////////////////////////////////// +// Struct types for holding user-defined collections of headers and +// metadata in the P4 developer's program. +// +// Note: The names of these struct types are completely up to the P4 +// developer, as are their member fields, with the only restriction +// being that the structs intended to contain headers should only +// contain members whose types are header, header stack, or +// header_union. +////////////////////////////////////////////////////////////////////// + +struct main_metadata_t { + // empty for this skeleton +} + +// User-defined struct containing all of those headers parsed in the +// main parser. +struct headers_t { + ethernet_t ethernet; + ipv4_t ipv4; +} + +parser MainParserImpl( + packet_in pkt, + out headers_t hdr, + inout main_metadata_t main_meta, + in pna_main_parser_input_metadata_t istd) +{ + state start { + pkt.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + 0x0800 : parse_ipv4; + default : accept; + } + } + state parse_ipv4 { + pkt.extract(hdr.ipv4); + transition accept; + } +} + +control MainControlImpl( + inout headers_t hdr, // from main parser + inout main_metadata_t user_meta, // from main parser, to "next block" + in pna_main_input_metadata_t istd, + inout pna_main_output_metadata_t ostd) +{ + action next_hop(PortId_t vport) { + send_to_port(vport); + } + action dflt_route_drop() { + drop_packet(); + } + action drop() { + drop_packet(); + } + + table ipv4_tbl_1 { + key = { + hdr.ipv4.dstAddr : exact; + istd.input_port : exact; + } + actions = { + next_hop; + dflt_route_drop; + } + @tc_may_override default_action = dflt_route_drop(); + } + table ipv4_tbl_2 { + key = { + hdr.ipv4.dstAddr : exact; + hdr.ipv4.srcAddr : exact; + hdr.ipv4.protocol : exact; + } + actions = { + next_hop; + drop; + } + default_action = drop; + } + + apply { + if (hdr.ipv4.isValid()) { + ipv4_tbl_1.apply(); + ipv4_tbl_2.apply(); + } + } +} + +control MainDeparserImpl( + packet_out pkt, + inout headers_t hdr, // from main control + in main_metadata_t user_meta, // from main control + in pna_main_output_metadata_t ostd) +{ + apply { + pkt.emit(hdr.ethernet); + pkt.emit(hdr.ipv4); + } +} + +// BEGIN:Package_Instantiation_Example +PNA_NIC( + MainParserImpl(), + MainControlImpl(), + MainDeparserImpl() + ) main; +// END:Package_Instantiation_Example diff --git a/testdata/p4tc_samples/tc_may_override_example_03.p4 b/testdata/p4tc_samples/tc_may_override_example_03.p4 new file mode 100644 index 0000000000..9cb0468dc4 --- /dev/null +++ b/testdata/p4tc_samples/tc_may_override_example_03.p4 @@ -0,0 +1,135 @@ +#include +#include + +typedef bit<48> EthernetAddress; + +header ethernet_t { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + @tc_type ("ipv4") bit<32> srcAddr; + @tc_type ("ipv4") bit<32> dstAddr; +} + +////////////////////////////////////////////////////////////////////// +// Struct types for holding user-defined collections of headers and +// metadata in the P4 developer's program. +// +// Note: The names of these struct types are completely up to the P4 +// developer, as are their member fields, with the only restriction +// being that the structs intended to contain headers should only +// contain members whose types are header, header stack, or +// header_union. +////////////////////////////////////////////////////////////////////// + +struct main_metadata_t { + // empty for this skeleton +} + +// User-defined struct containing all of those headers parsed in the +// main parser. +struct headers_t { + ethernet_t ethernet; + ipv4_t ipv4; +} + +parser MainParserImpl( + packet_in pkt, + out headers_t hdr, + inout main_metadata_t main_meta, + in pna_main_parser_input_metadata_t istd) +{ + state start { + pkt.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + 0x0800 : parse_ipv4; + default : accept; + } + } + state parse_ipv4 { + pkt.extract(hdr.ipv4); + transition accept; + } +} + +control MainControlImpl( + inout headers_t hdr, // from main parser + inout main_metadata_t user_meta, // from main parser, to "next block" + in pna_main_input_metadata_t istd, + inout pna_main_output_metadata_t ostd) +{ + PortId_t z = (PortId_t)4; + action next_hop(inout PortId_t vport) { + send_to_port(vport); + } + action dflt_route_drop() { + drop_packet(); + } + action drop() { + drop_packet(); + } + + table ipv4_tbl_1 { + key = { + hdr.ipv4.dstAddr : exact; + istd.input_port : exact; + } + actions = { + @defaultonly next_hop(z); + dflt_route_drop; + } + @tc_may_override default_action = next_hop(z); + } + table ipv4_tbl_2 { + key = { + hdr.ipv4.dstAddr : exact; + hdr.ipv4.srcAddr : exact; + hdr.ipv4.protocol : exact; + } + actions = { + @defaultonly next_hop(z); + drop; + } + default_action = drop; + } + + apply { + if (hdr.ipv4.isValid()) { + ipv4_tbl_1.apply(); + ipv4_tbl_2.apply(); + } + } +} + +control MainDeparserImpl( + packet_out pkt, + inout headers_t hdr, // from main control + in main_metadata_t user_meta, // from main control + in pna_main_output_metadata_t ostd) +{ + apply { + pkt.emit(hdr.ethernet); + pkt.emit(hdr.ipv4); + } +} + +// BEGIN:Package_Instantiation_Example +PNA_NIC( + MainParserImpl(), + MainControlImpl(), + MainDeparserImpl() + ) main; +// END:Package_Instantiation_Example diff --git a/testdata/p4tc_samples/tc_may_override_example_04.p4 b/testdata/p4tc_samples/tc_may_override_example_04.p4 new file mode 100644 index 0000000000..2a284a6136 --- /dev/null +++ b/testdata/p4tc_samples/tc_may_override_example_04.p4 @@ -0,0 +1,135 @@ +#include +#include + +typedef bit<48> EthernetAddress; + +header ethernet_t { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + @tc_type ("ipv4") bit<32> srcAddr; + @tc_type ("ipv4") bit<32> dstAddr; +} + +////////////////////////////////////////////////////////////////////// +// Struct types for holding user-defined collections of headers and +// metadata in the P4 developer's program. +// +// Note: The names of these struct types are completely up to the P4 +// developer, as are their member fields, with the only restriction +// being that the structs intended to contain headers should only +// contain members whose types are header, header stack, or +// header_union. +////////////////////////////////////////////////////////////////////// + +struct main_metadata_t { + // empty for this skeleton +} + +// User-defined struct containing all of those headers parsed in the +// main parser. +struct headers_t { + ethernet_t ethernet; + ipv4_t ipv4; +} + +parser MainParserImpl( + packet_in pkt, + out headers_t hdr, + inout main_metadata_t main_meta, + in pna_main_parser_input_metadata_t istd) +{ + state start { + pkt.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + 0x0800 : parse_ipv4; + default : accept; + } + } + state parse_ipv4 { + pkt.extract(hdr.ipv4); + transition accept; + } +} + +control MainControlImpl( + inout headers_t hdr, // from main parser + inout main_metadata_t user_meta, // from main parser, to "next block" + in pna_main_input_metadata_t istd, + inout pna_main_output_metadata_t ostd) +{ + action next_hop(@tc_type("ipv4") bit<32> ipv4addr) { + hdr.ipv4.dstAddr = ipv4addr; + send_to_port((PortId_t)8); + } + action default_route_drop() { + drop_packet(); + } + action drop() { + drop_packet(); + } + + table ipv4_tbl_1 { + key = { + hdr.ipv4.dstAddr : exact; + istd.input_port : exact; + } + actions = { + next_hop; + default_route_drop; + } + @tc_may_override default_action = next_hop(0x3A4A5A6A); + } + table ipv4_tbl_2 { + key = { + hdr.ipv4.dstAddr : exact; + hdr.ipv4.srcAddr : exact; + hdr.ipv4.protocol : exact; + } + actions = { + next_hop; + drop; + } + default_action = drop; + } + + apply { + if (hdr.ipv4.isValid()) { + ipv4_tbl_1.apply(); + ipv4_tbl_2.apply(); + } + } +} + +control MainDeparserImpl( + packet_out pkt, + inout headers_t hdr, // from main control + in main_metadata_t user_meta, // from main control + in pna_main_output_metadata_t ostd) +{ + apply { + pkt.emit(hdr.ethernet); + pkt.emit(hdr.ipv4); + } +} + +// BEGIN:Package_Instantiation_Example +PNA_NIC( + MainParserImpl(), + MainControlImpl(), + MainDeparserImpl() + ) main; +// END:Package_Instantiation_Example diff --git a/testdata/p4tc_samples/tc_may_override_example_05.p4 b/testdata/p4tc_samples/tc_may_override_example_05.p4 new file mode 100644 index 0000000000..6acc776dbd --- /dev/null +++ b/testdata/p4tc_samples/tc_may_override_example_05.p4 @@ -0,0 +1,135 @@ +#include +#include + +typedef bit<48> EthernetAddress; + +header ethernet_t { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + @tc_type ("ipv4") bit<32> srcAddr; + @tc_type ("ipv4") bit<32> dstAddr; +} + +////////////////////////////////////////////////////////////////////// +// Struct types for holding user-defined collections of headers and +// metadata in the P4 developer's program. +// +// Note: The names of these struct types are completely up to the P4 +// developer, as are their member fields, with the only restriction +// being that the structs intended to contain headers should only +// contain members whose types are header, header stack, or +// header_union. +////////////////////////////////////////////////////////////////////// + +struct main_metadata_t { + // empty for this skeleton +} + +// User-defined struct containing all of those headers parsed in the +// main parser. +struct headers_t { + ethernet_t ethernet; + ipv4_t ipv4; +} + +parser MainParserImpl( + packet_in pkt, + out headers_t hdr, + inout main_metadata_t main_meta, + in pna_main_parser_input_metadata_t istd) +{ + state start { + pkt.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + 0x0800 : parse_ipv4; + default : accept; + } + } + state parse_ipv4 { + pkt.extract(hdr.ipv4); + transition accept; + } +} + +control MainControlImpl( + inout headers_t hdr, // from main parser + inout main_metadata_t user_meta, // from main parser, to "next block" + in pna_main_input_metadata_t istd, + inout pna_main_output_metadata_t ostd) +{ + PortId_t port = (PortId_t)8; + action next_hop(@tc_type ("dev") PortId_t vport) { + send_to_port(vport); + } + action default_route_drop() { + drop_packet(); + } + action drop() { + drop_packet(); + } + + table ipv4_tbl_1 { + key = { + hdr.ipv4.dstAddr : exact; + istd.input_port : exact; + } + actions = { + next_hop; + default_route_drop; + } + @tc_may_override default_action = next_hop((PortId_t) 8); + } + table ipv4_tbl_2 { + key = { + hdr.ipv4.dstAddr : exact; + hdr.ipv4.srcAddr : exact; + hdr.ipv4.protocol : exact; + } + actions = { + next_hop; + drop; + } + default_action = drop; + } + + apply { + if (hdr.ipv4.isValid()) { + ipv4_tbl_1.apply(); + ipv4_tbl_2.apply(); + } + } +} + +control MainDeparserImpl( + packet_out pkt, + inout headers_t hdr, // from main control + in main_metadata_t user_meta, // from main control + in pna_main_output_metadata_t ostd) +{ + apply { + pkt.emit(hdr.ethernet); + pkt.emit(hdr.ipv4); + } +} + +// BEGIN:Package_Instantiation_Example +PNA_NIC( + MainParserImpl(), + MainControlImpl(), + MainDeparserImpl() + ) main; +// END:Package_Instantiation_Example diff --git a/testdata/p4tc_samples/tc_may_override_example_06.p4 b/testdata/p4tc_samples/tc_may_override_example_06.p4 new file mode 100644 index 0000000000..9988827ba1 --- /dev/null +++ b/testdata/p4tc_samples/tc_may_override_example_06.p4 @@ -0,0 +1,136 @@ +#include +#include + +typedef bit<48> EthernetAddress; + +header ethernet_t { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + @tc_type ("ipv4") bit<32> srcAddr; + @tc_type ("ipv4") bit<32> dstAddr; +} + +////////////////////////////////////////////////////////////////////// +// Struct types for holding user-defined collections of headers and +// metadata in the P4 developer's program. +// +// Note: The names of these struct types are completely up to the P4 +// developer, as are their member fields, with the only restriction +// being that the structs intended to contain headers should only +// contain members whose types are header, header stack, or +// header_union. +////////////////////////////////////////////////////////////////////// + +struct main_metadata_t { + // empty for this skeleton +} + +// User-defined struct containing all of those headers parsed in the +// main parser. +struct headers_t { + ethernet_t ethernet; + ipv4_t ipv4; +} + +parser MainParserImpl( + packet_in pkt, + out headers_t hdr, + inout main_metadata_t main_meta, + in pna_main_parser_input_metadata_t istd) +{ + state start { + pkt.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + 0x0800 : parse_ipv4; + default : accept; + } + } + state parse_ipv4 { + pkt.extract(hdr.ipv4); + transition accept; + } +} + +control MainControlImpl( + inout headers_t hdr, // from main parser + inout main_metadata_t user_meta, // from main parser, to "next block" + in pna_main_input_metadata_t istd, + inout pna_main_output_metadata_t ostd) +{ + PortId_t port = (PortId_t)8; + action next_hop(@tc_type ("dev") PortId_t vport) { + send_to_port(vport); + } + action default_route_drop() { + drop_packet(); + } + action drop() { + drop_packet(); + } + + table ipv4_tbl_1 { + key = { + hdr.ipv4.dstAddr : exact; + istd.input_port : exact; + } + actions = { + next_hop; + default_route_drop; + } + @tc_may_override default_action = next_hop((PortId_t) 8); + } + table ipv4_tbl_2 { + key = { + hdr.ipv4.dstAddr : exact; + hdr.ipv4.srcAddr : exact; + hdr.ipv4.protocol : exact; + } + actions = { + next_hop; + drop; + } + @tc_may_override default_action = next_hop((PortId_t) 2); + + } + + apply { + if (hdr.ipv4.isValid()) { + ipv4_tbl_1.apply(); + ipv4_tbl_2.apply(); + } + } +} + +control MainDeparserImpl( + packet_out pkt, + inout headers_t hdr, // from main control + in main_metadata_t user_meta, // from main control + in pna_main_output_metadata_t ostd) +{ + apply { + pkt.emit(hdr.ethernet); + pkt.emit(hdr.ipv4); + } +} + +// BEGIN:Package_Instantiation_Example +PNA_NIC( + MainParserImpl(), + MainControlImpl(), + MainDeparserImpl() + ) main; +// END:Package_Instantiation_Example diff --git a/testdata/p4tc_samples_outputs/tc_may_override_example_01.json b/testdata/p4tc_samples_outputs/tc_may_override_example_01.json new file mode 100644 index 0000000000..8dbb2c3638 --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_01.json @@ -0,0 +1,113 @@ +{ + "schema_version" : "1.0.0", + "pipeline_name" : "tc_may_override_example_01", + "tables" : [ + { + "name" : "MainControlImpl/ipv4_tbl_1", + "id" : 1, + "tentries" : 2048, + "nummask" : 8, + "keysize" : 64, + "keyfields" : [ + { + "id" : 1, + "name" : "hdr.ipv4.dstAddr", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + }, + { + "id" : 2, + "name" : "istd.input_port", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + } + ], + "actions" : [ + { + "id" : 1, + "name" : "MainControlImpl/next_hop", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [ + { + "id" : 1, + "name" : "vport", + "type" : "bit32", + "bitwidth" : 32 + } + ], + "default_hit_action" : false, + "default_miss_action" : true + }, + { + "id" : 2, + "name" : "MainControlImpl/default_route_drop", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [], + "default_hit_action" : false, + "default_miss_action" : false + } + ] + }, + { + "name" : "MainControlImpl/ipv4_tbl_2", + "id" : 2, + "tentries" : 2048, + "nummask" : 8, + "keysize" : 72, + "keyfields" : [ + { + "id" : 1, + "name" : "hdr.ipv4.dstAddr", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + }, + { + "id" : 2, + "name" : "hdr.ipv4.srcAddr", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + }, + { + "id" : 3, + "name" : "hdr.ipv4.protocol", + "type" : "bit8", + "match_type" : "exact", + "bitwidth" : 8 + } + ], + "actions" : [ + { + "id" : 1, + "name" : "MainControlImpl/next_hop", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [ + { + "id" : 1, + "name" : "vport", + "type" : "bit32", + "bitwidth" : 32 + } + ], + "default_hit_action" : false, + "default_miss_action" : false + }, + { + "id" : 3, + "name" : "MainControlImpl/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/tc_may_override_example_01.p4-stderr b/testdata/p4tc_samples_outputs/tc_may_override_example_01.p4-stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/testdata/p4tc_samples_outputs/tc_may_override_example_01.template b/testdata/p4tc_samples_outputs/tc_may_override_example_01.template new file mode 100755 index 0000000000..ad0b526140 --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_01.template @@ -0,0 +1,33 @@ +#!/bin/bash -x + +set -e + +TC="tc" +$TC p4template create pipeline/tc_may_override_example_01 numtables 2 + +$TC p4template create action/tc_may_override_example_01/MainControlImpl/next_hop actid 1 \ + param vport type bit32 +$TC p4template update action/tc_may_override_example_01/MainControlImpl/next_hop state active + +$TC p4template create action/tc_may_override_example_01/MainControlImpl/default_route_drop actid 2 +$TC p4template update action/tc_may_override_example_01/MainControlImpl/default_route_drop state active + +$TC p4template create action/tc_may_override_example_01/MainControlImpl/drop actid 3 +$TC p4template update action/tc_may_override_example_01/MainControlImpl/drop state active + +$TC p4template create table/tc_may_override_example_01/MainControlImpl/ipv4_tbl_1 \ + tblid 1 \ + type exact \ + keysz 64 nummasks 8 tentries 2048 \ + table_acts act name tc_may_override_example_01/MainControlImpl/next_hop \ + act name tc_may_override_example_01/MainControlImpl/default_route_drop +$TC p4template update table/tc_may_override_example_01/MainControlImpl/ipv4_tbl_1 default_miss_action action tc_may_override_example_01/MainControlImpl/next_hop param vport flags runtime + +$TC p4template create table/tc_may_override_example_01/MainControlImpl/ipv4_tbl_2 \ + tblid 2 \ + type exact \ + keysz 72 nummasks 8 tentries 2048 \ + table_acts act name tc_may_override_example_01/MainControlImpl/next_hop \ + act name tc_may_override_example_01/MainControlImpl/drop +$TC p4template update table/tc_may_override_example_01/MainControlImpl/ipv4_tbl_2 default_miss_action action tc_may_override_example_01/MainControlImpl/drop +$TC p4template update pipeline/tc_may_override_example_01 state ready \ No newline at end of file diff --git a/testdata/p4tc_samples_outputs/tc_may_override_example_01_control_blocks.c b/testdata/p4tc_samples_outputs/tc_may_override_example_01_control_blocks.c new file mode 100644 index 0000000000..a1d1ae5bb5 --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_01_control_blocks.c @@ -0,0 +1,369 @@ +#include "tc_may_override_example_01_parser.h" +struct p4tc_filter_fields p4tc_filter_fields; + +struct internal_metadata { + __u16 pkt_ether_type; +} __attribute__((aligned(4))); + +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_1_key { + u32 keysz; + u32 maskid; + u32 field0; /* hdr.ipv4.dstAddr */ + u32 field1; /* istd.input_port */ +} __attribute__((aligned(8))); +#define MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_NEXT_HOP 1 +#define MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_DEFAULT_ROUTE_DROP 2 +#define MAINCONTROLIMPL_IPV4_TBL_1_ACT_NOACTION 0 +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_1_value { + unsigned int action; + u32 hit:1, + is_default_miss_act:1, + is_default_hit_act:1; + union { + struct { + } _NoAction; + struct __attribute__((__packed__)) { + u32 vport; + } MainControlImpl_next_hop; + struct { + } MainControlImpl_default_route_drop; + } u; +}; +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_2_key { + u32 keysz; + u32 maskid; + u32 field0; /* hdr.ipv4.dstAddr */ + u32 field1; /* hdr.ipv4.srcAddr */ + u8 field2; /* hdr.ipv4.protocol */ +} __attribute__((aligned(8))); +#define MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_NEXT_HOP 1 +#define MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_DROP 3 +#define MAINCONTROLIMPL_IPV4_TBL_2_ACT_NOACTION 0 +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_2_value { + unsigned int action; + u32 hit:1, + is_default_miss_act:1, + is_default_hit_act:1; + union { + struct { + } _NoAction; + struct __attribute__((__packed__)) { + u32 vport; + } MainControlImpl_next_hop; + struct { + } MainControlImpl_drop; + } u; +}; + +static __always_inline int process(struct __sk_buff *skb, struct 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 main_metadata_t *user_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); + user_meta = &(hdrMd->cpumap_usermeta); +{ + u8 hit; + { +if (/* hdr->ipv4.isValid() */ + hdr->ipv4.ebpf_valid) { +/* ipv4_tbl.apply() */ + { + /* construct key */ + struct p4tc_table_entry_act_bpf_params__local params = { + .pipeid = p4tc_filter_fields.pipeid, + .tblid = 1 + }; + struct MainControlImpl_ipv4_tbl_1_key key; + __builtin_memset(&key, 0, sizeof(key)); + key.keysz = 64; + key.field0 = hdr->ipv4.dstAddr; + key.field1 = skb->ifindex; + struct p4tc_table_entry_act_bpf *act_bpf; + /* value */ + struct MainControlImpl_ipv4_tbl_1_value *value = NULL; + /* perform lookup */ + act_bpf = bpf_p4tc_tbl_read(skb, ¶ms, &key, sizeof(key)); + value = (struct MainControlImpl_ipv4_tbl_1_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 MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_NEXT_HOP: + { +/* send_to_port(value->u.MainControlImpl_next_hop.vport) */ + compiler_meta__->drop = false; + send_to_port(value->u.MainControlImpl_next_hop.vport); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_DEFAULT_ROUTE_DROP: + { +/* drop_packet() */ + drop_packet(); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_1_ACT_NOACTION: + { + } + break; + } + } else { + } + } +; + /* ipv4_tbl_0.apply() */ + { + /* construct key */ + struct p4tc_table_entry_act_bpf_params__local params = { + .pipeid = p4tc_filter_fields.pipeid, + .tblid = 2 + }; + struct MainControlImpl_ipv4_tbl_2_key key; + __builtin_memset(&key, 0, sizeof(key)); + key.keysz = 72; + key.field0 = hdr->ipv4.dstAddr; + key.field1 = hdr->ipv4.srcAddr; + key.field2 = hdr->ipv4.protocol; + struct p4tc_table_entry_act_bpf *act_bpf; + /* value */ + struct MainControlImpl_ipv4_tbl_2_value *value = NULL; + /* perform lookup */ + act_bpf = bpf_p4tc_tbl_read(skb, ¶ms, &key, sizeof(key)); + value = (struct MainControlImpl_ipv4_tbl_2_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 MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_NEXT_HOP: + { +/* send_to_port(value->u.MainControlImpl_next_hop.vport) */ + compiler_meta__->drop = false; + send_to_port(value->u.MainControlImpl_next_hop.vport); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_DROP: + { +/* drop_packet() */ + drop_packet(); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_2_ACT_NOACTION: + { + } + break; + } + } else { + } + } +; + } + } + } + { +{ +; + ; + } + + 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; + } + + hdr->ethernet.dstAddr = htonll(hdr->ethernet.dstAddr << 16); + 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; + + hdr->ethernet.srcAddr = htonll(hdr->ethernet.srcAddr << 16); + 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; + 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 headers_t *hdr; + int ret = -1; + ret = process(skb, (struct 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/tc_may_override_example_01_parser.c b/testdata/p4tc_samples_outputs/tc_may_override_example_01_parser.c new file mode 100644 index 0000000000..16fbf526c8 --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_01_parser.c @@ -0,0 +1,136 @@ +#include "tc_may_override_example_01_parser.h" + +struct p4tc_filter_fields p4tc_filter_fields; + +static __always_inline int run_parser(struct __sk_buff *skb, struct 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 main_metadata_t *user_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); + user_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); + +; + goto accept; + } + start: { +/* extract(hdr->ethernet) */ + if ((u8*)ebpf_packetEnd < hdr_start + BYTES(112 + 0)) { + ebpf_errorCode = PacketTooShort; + goto reject; + } + + hdr->ethernet.dstAddr = (u64)((load_dword(pkt, BYTES(ebpf_packetOffsetInBits)) >> 16) & EBPF_MASK(u64, 48)); + ebpf_packetOffsetInBits += 48; + + hdr->ethernet.srcAddr = (u64)((load_dword(pkt, BYTES(ebpf_packetOffsetInBits)) >> 16) & EBPF_MASK(u64, 48)); + 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_0; + select_0 = hdr->ethernet.etherType; + if (select_0 == 0x800)goto parse_ipv4; + if ((select_0 & 0x0) == (0x0 & 0x0))goto accept; + 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 headers_t *hdr; + int ret = -1; + ret = run_parser(skb, (struct 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/tc_may_override_example_01_parser.h b/testdata/p4tc_samples_outputs/tc_may_override_example_01_parser.h new file mode 100644 index 0000000000..2d42144bb5 --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_01_parser.h @@ -0,0 +1,164 @@ +#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; /* EthernetAddress */ + u64 srcAddr; /* EthernetAddress */ + 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 main_metadata_t { +}; +struct headers_t { + struct ethernet_t ethernet; /* ethernet_t */ + struct ipv4_t ipv4; /* ipv4_t */ +}; + +struct hdr_md { + struct headers_t cpumap_hdr; + struct main_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; + __u32 ipv4_tbl_1_next_hop_vport; +}; + +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; +} +inline u16 csum16_add(u16 csum, u16 addend) { + u16 res = csum; + res += addend; + return (res + (res < addend)); +} +inline u16 csum16_sub(u16 csum, u16 addend) { + return csum16_add(csum, ~addend); +} diff --git a/testdata/p4tc_samples_outputs/tc_may_override_example_02.json b/testdata/p4tc_samples_outputs/tc_may_override_example_02.json new file mode 100644 index 0000000000..cf48a177c0 --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_02.json @@ -0,0 +1,113 @@ +{ + "schema_version" : "1.0.0", + "pipeline_name" : "tc_may_override_example_02", + "tables" : [ + { + "name" : "MainControlImpl/ipv4_tbl_1", + "id" : 1, + "tentries" : 2048, + "nummask" : 8, + "keysize" : 64, + "keyfields" : [ + { + "id" : 1, + "name" : "hdr.ipv4.dstAddr", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + }, + { + "id" : 2, + "name" : "istd.input_port", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + } + ], + "actions" : [ + { + "id" : 1, + "name" : "MainControlImpl/next_hop", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [ + { + "id" : 1, + "name" : "vport", + "type" : "bit32", + "bitwidth" : 32 + } + ], + "default_hit_action" : false, + "default_miss_action" : false + }, + { + "id" : 2, + "name" : "MainControlImpl/dflt_route_drop", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [], + "default_hit_action" : false, + "default_miss_action" : true + } + ] + }, + { + "name" : "MainControlImpl/ipv4_tbl_2", + "id" : 2, + "tentries" : 2048, + "nummask" : 8, + "keysize" : 72, + "keyfields" : [ + { + "id" : 1, + "name" : "hdr.ipv4.dstAddr", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + }, + { + "id" : 2, + "name" : "hdr.ipv4.srcAddr", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + }, + { + "id" : 3, + "name" : "hdr.ipv4.protocol", + "type" : "bit8", + "match_type" : "exact", + "bitwidth" : 8 + } + ], + "actions" : [ + { + "id" : 1, + "name" : "MainControlImpl/next_hop", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [ + { + "id" : 1, + "name" : "vport", + "type" : "bit32", + "bitwidth" : 32 + } + ], + "default_hit_action" : false, + "default_miss_action" : false + }, + { + "id" : 3, + "name" : "MainControlImpl/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/tc_may_override_example_02.p4-stderr b/testdata/p4tc_samples_outputs/tc_may_override_example_02.p4-stderr new file mode 100644 index 0000000000..e19e3390f0 --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_02.p4-stderr @@ -0,0 +1,3 @@ +p4tc_samples/tc_may_override_example_02.p4(93): [--Wwarn=invalid] warning: @tc_may_override annotation cannot be used with default_action without parameters + @tc_may_override default_action = dflt_route_drop(); + ^ diff --git a/testdata/p4tc_samples_outputs/tc_may_override_example_02.template b/testdata/p4tc_samples_outputs/tc_may_override_example_02.template new file mode 100755 index 0000000000..b10474c2a7 --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_02.template @@ -0,0 +1,33 @@ +#!/bin/bash -x + +set -e + +TC="tc" +$TC p4template create pipeline/tc_may_override_example_02 numtables 2 + +$TC p4template create action/tc_may_override_example_02/MainControlImpl/next_hop actid 1 \ + param vport type bit32 +$TC p4template update action/tc_may_override_example_02/MainControlImpl/next_hop state active + +$TC p4template create action/tc_may_override_example_02/MainControlImpl/dflt_route_drop actid 2 +$TC p4template update action/tc_may_override_example_02/MainControlImpl/dflt_route_drop state active + +$TC p4template create action/tc_may_override_example_02/MainControlImpl/drop actid 3 +$TC p4template update action/tc_may_override_example_02/MainControlImpl/drop state active + +$TC p4template create table/tc_may_override_example_02/MainControlImpl/ipv4_tbl_1 \ + tblid 1 \ + type exact \ + keysz 64 nummasks 8 tentries 2048 \ + table_acts act name tc_may_override_example_02/MainControlImpl/next_hop \ + act name tc_may_override_example_02/MainControlImpl/dflt_route_drop +$TC p4template update table/tc_may_override_example_02/MainControlImpl/ipv4_tbl_1 default_miss_action action tc_may_override_example_02/MainControlImpl/dflt_route_drop + +$TC p4template create table/tc_may_override_example_02/MainControlImpl/ipv4_tbl_2 \ + tblid 2 \ + type exact \ + keysz 72 nummasks 8 tentries 2048 \ + table_acts act name tc_may_override_example_02/MainControlImpl/next_hop \ + act name tc_may_override_example_02/MainControlImpl/drop +$TC p4template update table/tc_may_override_example_02/MainControlImpl/ipv4_tbl_2 default_miss_action action tc_may_override_example_02/MainControlImpl/drop +$TC p4template update pipeline/tc_may_override_example_02 state ready \ No newline at end of file diff --git a/testdata/p4tc_samples_outputs/tc_may_override_example_02_control_blocks.c b/testdata/p4tc_samples_outputs/tc_may_override_example_02_control_blocks.c new file mode 100644 index 0000000000..f7cf28034d --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_02_control_blocks.c @@ -0,0 +1,369 @@ +#include "tc_may_override_example_02_parser.h" +struct p4tc_filter_fields p4tc_filter_fields; + +struct internal_metadata { + __u16 pkt_ether_type; +} __attribute__((aligned(4))); + +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_1_key { + u32 keysz; + u32 maskid; + u32 field0; /* hdr.ipv4.dstAddr */ + u32 field1; /* istd.input_port */ +} __attribute__((aligned(8))); +#define MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_NEXT_HOP 1 +#define MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_DFLT_ROUTE_DROP 2 +#define MAINCONTROLIMPL_IPV4_TBL_1_ACT_NOACTION 0 +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_1_value { + unsigned int action; + u32 hit:1, + is_default_miss_act:1, + is_default_hit_act:1; + union { + struct { + } _NoAction; + struct __attribute__((__packed__)) { + u32 vport; + } MainControlImpl_next_hop; + struct { + } MainControlImpl_dflt_route_drop; + } u; +}; +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_2_key { + u32 keysz; + u32 maskid; + u32 field0; /* hdr.ipv4.dstAddr */ + u32 field1; /* hdr.ipv4.srcAddr */ + u8 field2; /* hdr.ipv4.protocol */ +} __attribute__((aligned(8))); +#define MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_NEXT_HOP 1 +#define MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_DROP 3 +#define MAINCONTROLIMPL_IPV4_TBL_2_ACT_NOACTION 0 +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_2_value { + unsigned int action; + u32 hit:1, + is_default_miss_act:1, + is_default_hit_act:1; + union { + struct { + } _NoAction; + struct __attribute__((__packed__)) { + u32 vport; + } MainControlImpl_next_hop; + struct { + } MainControlImpl_drop; + } u; +}; + +static __always_inline int process(struct __sk_buff *skb, struct 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 main_metadata_t *user_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); + user_meta = &(hdrMd->cpumap_usermeta); +{ + u8 hit; + { +if (/* hdr->ipv4.isValid() */ + hdr->ipv4.ebpf_valid) { +/* ipv4_tbl.apply() */ + { + /* construct key */ + struct p4tc_table_entry_act_bpf_params__local params = { + .pipeid = p4tc_filter_fields.pipeid, + .tblid = 1 + }; + struct MainControlImpl_ipv4_tbl_1_key key; + __builtin_memset(&key, 0, sizeof(key)); + key.keysz = 64; + key.field0 = hdr->ipv4.dstAddr; + key.field1 = skb->ifindex; + struct p4tc_table_entry_act_bpf *act_bpf; + /* value */ + struct MainControlImpl_ipv4_tbl_1_value *value = NULL; + /* perform lookup */ + act_bpf = bpf_p4tc_tbl_read(skb, ¶ms, &key, sizeof(key)); + value = (struct MainControlImpl_ipv4_tbl_1_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 MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_NEXT_HOP: + { +/* send_to_port(value->u.MainControlImpl_next_hop.vport) */ + compiler_meta__->drop = false; + send_to_port(value->u.MainControlImpl_next_hop.vport); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_DFLT_ROUTE_DROP: + { +/* drop_packet() */ + drop_packet(); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_1_ACT_NOACTION: + { + } + break; + } + } else { + } + } +; + /* ipv4_tbl_0.apply() */ + { + /* construct key */ + struct p4tc_table_entry_act_bpf_params__local params = { + .pipeid = p4tc_filter_fields.pipeid, + .tblid = 2 + }; + struct MainControlImpl_ipv4_tbl_2_key key; + __builtin_memset(&key, 0, sizeof(key)); + key.keysz = 72; + key.field0 = hdr->ipv4.dstAddr; + key.field1 = hdr->ipv4.srcAddr; + key.field2 = hdr->ipv4.protocol; + struct p4tc_table_entry_act_bpf *act_bpf; + /* value */ + struct MainControlImpl_ipv4_tbl_2_value *value = NULL; + /* perform lookup */ + act_bpf = bpf_p4tc_tbl_read(skb, ¶ms, &key, sizeof(key)); + value = (struct MainControlImpl_ipv4_tbl_2_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 MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_NEXT_HOP: + { +/* send_to_port(value->u.MainControlImpl_next_hop.vport) */ + compiler_meta__->drop = false; + send_to_port(value->u.MainControlImpl_next_hop.vport); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_DROP: + { +/* drop_packet() */ + drop_packet(); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_2_ACT_NOACTION: + { + } + break; + } + } else { + } + } +; + } + } + } + { +{ +; + ; + } + + 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; + } + + hdr->ethernet.dstAddr = htonll(hdr->ethernet.dstAddr << 16); + 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; + + hdr->ethernet.srcAddr = htonll(hdr->ethernet.srcAddr << 16); + 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; + 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 headers_t *hdr; + int ret = -1; + ret = process(skb, (struct 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/tc_may_override_example_02_parser.c b/testdata/p4tc_samples_outputs/tc_may_override_example_02_parser.c new file mode 100644 index 0000000000..704339bc65 --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_02_parser.c @@ -0,0 +1,136 @@ +#include "tc_may_override_example_02_parser.h" + +struct p4tc_filter_fields p4tc_filter_fields; + +static __always_inline int run_parser(struct __sk_buff *skb, struct 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 main_metadata_t *user_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); + user_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); + +; + goto accept; + } + start: { +/* extract(hdr->ethernet) */ + if ((u8*)ebpf_packetEnd < hdr_start + BYTES(112 + 0)) { + ebpf_errorCode = PacketTooShort; + goto reject; + } + + hdr->ethernet.dstAddr = (u64)((load_dword(pkt, BYTES(ebpf_packetOffsetInBits)) >> 16) & EBPF_MASK(u64, 48)); + ebpf_packetOffsetInBits += 48; + + hdr->ethernet.srcAddr = (u64)((load_dword(pkt, BYTES(ebpf_packetOffsetInBits)) >> 16) & EBPF_MASK(u64, 48)); + 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_0; + select_0 = hdr->ethernet.etherType; + if (select_0 == 0x800)goto parse_ipv4; + if ((select_0 & 0x0) == (0x0 & 0x0))goto accept; + 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 headers_t *hdr; + int ret = -1; + ret = run_parser(skb, (struct 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/tc_may_override_example_02_parser.h b/testdata/p4tc_samples_outputs/tc_may_override_example_02_parser.h new file mode 100644 index 0000000000..11d6b2e6fe --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_02_parser.h @@ -0,0 +1,163 @@ +#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; /* EthernetAddress */ + u64 srcAddr; /* EthernetAddress */ + 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 main_metadata_t { +}; +struct headers_t { + struct ethernet_t ethernet; /* ethernet_t */ + struct ipv4_t ipv4; /* ipv4_t */ +}; + +struct hdr_md { + struct headers_t cpumap_hdr; + struct main_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; +} +inline u16 csum16_add(u16 csum, u16 addend) { + u16 res = csum; + res += addend; + return (res + (res < addend)); +} +inline u16 csum16_sub(u16 csum, u16 addend) { + return csum16_add(csum, ~addend); +} diff --git a/testdata/p4tc_samples_outputs/tc_may_override_example_03.json b/testdata/p4tc_samples_outputs/tc_may_override_example_03.json new file mode 100644 index 0000000000..b4d0a5cfda --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_03.json @@ -0,0 +1,99 @@ +{ + "schema_version" : "1.0.0", + "pipeline_name" : "tc_may_override_example_03", + "tables" : [ + { + "name" : "MainControlImpl/ipv4_tbl_1", + "id" : 1, + "tentries" : 2048, + "nummask" : 8, + "keysize" : 64, + "keyfields" : [ + { + "id" : 1, + "name" : "hdr.ipv4.dstAddr", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + }, + { + "id" : 2, + "name" : "istd.input_port", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + } + ], + "actions" : [ + { + "id" : 1, + "name" : "MainControlImpl/next_hop", + "action_scope" : "DefaultOnly", + "annotations" : ["defaultonly"], + "params" : [], + "default_hit_action" : false, + "default_miss_action" : true + }, + { + "id" : 2, + "name" : "MainControlImpl/dflt_route_drop", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [], + "default_hit_action" : false, + "default_miss_action" : false + } + ] + }, + { + "name" : "MainControlImpl/ipv4_tbl_2", + "id" : 2, + "tentries" : 2048, + "nummask" : 8, + "keysize" : 72, + "keyfields" : [ + { + "id" : 1, + "name" : "hdr.ipv4.dstAddr", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + }, + { + "id" : 2, + "name" : "hdr.ipv4.srcAddr", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + }, + { + "id" : 3, + "name" : "hdr.ipv4.protocol", + "type" : "bit8", + "match_type" : "exact", + "bitwidth" : 8 + } + ], + "actions" : [ + { + "id" : 1, + "name" : "MainControlImpl/next_hop", + "action_scope" : "DefaultOnly", + "annotations" : ["defaultonly"], + "params" : [], + "default_hit_action" : false, + "default_miss_action" : false + }, + { + "id" : 3, + "name" : "MainControlImpl/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/tc_may_override_example_03.p4-stderr b/testdata/p4tc_samples_outputs/tc_may_override_example_03.p4-stderr new file mode 100644 index 0000000000..ab368b4392 --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_03.p4-stderr @@ -0,0 +1,3 @@ +p4tc_samples/tc_may_override_example_03.p4(94): [--Wwarn=invalid] warning: @tc_may_override annotation cannot be used with default_action without parameters + @tc_may_override default_action = next_hop(z); + ^ diff --git a/testdata/p4tc_samples_outputs/tc_may_override_example_03.template b/testdata/p4tc_samples_outputs/tc_may_override_example_03.template new file mode 100755 index 0000000000..12237d5f65 --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_03.template @@ -0,0 +1,32 @@ +#!/bin/bash -x + +set -e + +TC="tc" +$TC p4template create pipeline/tc_may_override_example_03 numtables 2 + +$TC p4template create action/tc_may_override_example_03/MainControlImpl/next_hop actid 1 +$TC p4template update action/tc_may_override_example_03/MainControlImpl/next_hop state active + +$TC p4template create action/tc_may_override_example_03/MainControlImpl/dflt_route_drop actid 2 +$TC p4template update action/tc_may_override_example_03/MainControlImpl/dflt_route_drop state active + +$TC p4template create action/tc_may_override_example_03/MainControlImpl/drop actid 3 +$TC p4template update action/tc_may_override_example_03/MainControlImpl/drop state active + +$TC p4template create table/tc_may_override_example_03/MainControlImpl/ipv4_tbl_1 \ + tblid 1 \ + type exact \ + keysz 64 nummasks 8 tentries 2048 \ + table_acts act name tc_may_override_example_03/MainControlImpl/next_hop flags defaultonly \ + act name tc_may_override_example_03/MainControlImpl/dflt_route_drop +$TC p4template update table/tc_may_override_example_03/MainControlImpl/ipv4_tbl_1 default_miss_action action tc_may_override_example_03/MainControlImpl/next_hop + +$TC p4template create table/tc_may_override_example_03/MainControlImpl/ipv4_tbl_2 \ + tblid 2 \ + type exact \ + keysz 72 nummasks 8 tentries 2048 \ + table_acts act name tc_may_override_example_03/MainControlImpl/next_hop flags defaultonly \ + act name tc_may_override_example_03/MainControlImpl/drop +$TC p4template update table/tc_may_override_example_03/MainControlImpl/ipv4_tbl_2 default_miss_action action tc_may_override_example_03/MainControlImpl/drop +$TC p4template update pipeline/tc_may_override_example_03 state ready \ No newline at end of file diff --git a/testdata/p4tc_samples_outputs/tc_may_override_example_03_control_blocks.c b/testdata/p4tc_samples_outputs/tc_may_override_example_03_control_blocks.c new file mode 100644 index 0000000000..7983409245 --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_03_control_blocks.c @@ -0,0 +1,369 @@ +#include "tc_may_override_example_03_parser.h" +struct p4tc_filter_fields p4tc_filter_fields; + +struct internal_metadata { + __u16 pkt_ether_type; +} __attribute__((aligned(4))); + +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_1_key { + u32 keysz; + u32 maskid; + u32 field0; /* hdr.ipv4.dstAddr */ + u32 field1; /* istd.input_port */ +} __attribute__((aligned(8))); +#define MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_NEXT_HOP 1 +#define MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_DFLT_ROUTE_DROP 2 +#define MAINCONTROLIMPL_IPV4_TBL_1_ACT_NOACTION 0 +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_1_value { + unsigned int action; + u32 hit:1, + is_default_miss_act:1, + is_default_hit_act:1; + union { + struct { + } _NoAction; + struct { + } MainControlImpl_next_hop; + struct { + } MainControlImpl_dflt_route_drop; + } u; +}; +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_2_key { + u32 keysz; + u32 maskid; + u32 field0; /* hdr.ipv4.dstAddr */ + u32 field1; /* hdr.ipv4.srcAddr */ + u8 field2; /* hdr.ipv4.protocol */ +} __attribute__((aligned(8))); +#define MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_NEXT_HOP 1 +#define MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_DROP 3 +#define MAINCONTROLIMPL_IPV4_TBL_2_ACT_NOACTION 0 +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_2_value { + unsigned int action; + u32 hit:1, + is_default_miss_act:1, + is_default_hit_act:1; + union { + struct { + } _NoAction; + struct { + } MainControlImpl_next_hop; + struct { + } MainControlImpl_drop; + } u; +}; + +static __always_inline int process(struct __sk_buff *skb, struct 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 main_metadata_t *user_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); + user_meta = &(hdrMd->cpumap_usermeta); +{ + u8 hit; + u32 z_0; + { + z_0 = 4; + if (/* hdr->ipv4.isValid() */ + hdr->ipv4.ebpf_valid) { +/* ipv4_tbl.apply() */ + { + /* construct key */ + struct p4tc_table_entry_act_bpf_params__local params = { + .pipeid = p4tc_filter_fields.pipeid, + .tblid = 1 + }; + struct MainControlImpl_ipv4_tbl_1_key key; + __builtin_memset(&key, 0, sizeof(key)); + key.keysz = 64; + key.field0 = hdr->ipv4.dstAddr; + key.field1 = skb->ifindex; + struct p4tc_table_entry_act_bpf *act_bpf; + /* value */ + struct MainControlImpl_ipv4_tbl_1_value *value = NULL; + /* perform lookup */ + act_bpf = bpf_p4tc_tbl_read(skb, ¶ms, &key, sizeof(key)); + value = (struct MainControlImpl_ipv4_tbl_1_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 MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_NEXT_HOP: + { +/* send_to_port(z_0) */ + compiler_meta__->drop = false; + send_to_port(z_0); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_DFLT_ROUTE_DROP: + { +/* drop_packet() */ + drop_packet(); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_1_ACT_NOACTION: + { + } + break; + } + } else { + } + } +; + /* ipv4_tbl_0.apply() */ + { + /* construct key */ + struct p4tc_table_entry_act_bpf_params__local params = { + .pipeid = p4tc_filter_fields.pipeid, + .tblid = 2 + }; + struct MainControlImpl_ipv4_tbl_2_key key; + __builtin_memset(&key, 0, sizeof(key)); + key.keysz = 72; + key.field0 = hdr->ipv4.dstAddr; + key.field1 = hdr->ipv4.srcAddr; + key.field2 = hdr->ipv4.protocol; + struct p4tc_table_entry_act_bpf *act_bpf; + /* value */ + struct MainControlImpl_ipv4_tbl_2_value *value = NULL; + /* perform lookup */ + act_bpf = bpf_p4tc_tbl_read(skb, ¶ms, &key, sizeof(key)); + value = (struct MainControlImpl_ipv4_tbl_2_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 MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_NEXT_HOP: + { +/* send_to_port(z_0) */ + compiler_meta__->drop = false; + send_to_port(z_0); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_DROP: + { +/* drop_packet() */ + drop_packet(); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_2_ACT_NOACTION: + { + } + break; + } + } else { + } + } +; + } + } + } + { +{ +; + ; + } + + 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; + } + + hdr->ethernet.dstAddr = htonll(hdr->ethernet.dstAddr << 16); + 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; + + hdr->ethernet.srcAddr = htonll(hdr->ethernet.srcAddr << 16); + 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; + 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 headers_t *hdr; + int ret = -1; + ret = process(skb, (struct 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/tc_may_override_example_03_parser.c b/testdata/p4tc_samples_outputs/tc_may_override_example_03_parser.c new file mode 100644 index 0000000000..dfa2d245d8 --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_03_parser.c @@ -0,0 +1,136 @@ +#include "tc_may_override_example_03_parser.h" + +struct p4tc_filter_fields p4tc_filter_fields; + +static __always_inline int run_parser(struct __sk_buff *skb, struct 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 main_metadata_t *user_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); + user_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); + +; + goto accept; + } + start: { +/* extract(hdr->ethernet) */ + if ((u8*)ebpf_packetEnd < hdr_start + BYTES(112 + 0)) { + ebpf_errorCode = PacketTooShort; + goto reject; + } + + hdr->ethernet.dstAddr = (u64)((load_dword(pkt, BYTES(ebpf_packetOffsetInBits)) >> 16) & EBPF_MASK(u64, 48)); + ebpf_packetOffsetInBits += 48; + + hdr->ethernet.srcAddr = (u64)((load_dword(pkt, BYTES(ebpf_packetOffsetInBits)) >> 16) & EBPF_MASK(u64, 48)); + 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_0; + select_0 = hdr->ethernet.etherType; + if (select_0 == 0x800)goto parse_ipv4; + if ((select_0 & 0x0) == (0x0 & 0x0))goto accept; + 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 headers_t *hdr; + int ret = -1; + ret = run_parser(skb, (struct 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/tc_may_override_example_03_parser.h b/testdata/p4tc_samples_outputs/tc_may_override_example_03_parser.h new file mode 100644 index 0000000000..11d6b2e6fe --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_03_parser.h @@ -0,0 +1,163 @@ +#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; /* EthernetAddress */ + u64 srcAddr; /* EthernetAddress */ + 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 main_metadata_t { +}; +struct headers_t { + struct ethernet_t ethernet; /* ethernet_t */ + struct ipv4_t ipv4; /* ipv4_t */ +}; + +struct hdr_md { + struct headers_t cpumap_hdr; + struct main_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; +} +inline u16 csum16_add(u16 csum, u16 addend) { + u16 res = csum; + res += addend; + return (res + (res < addend)); +} +inline u16 csum16_sub(u16 csum, u16 addend) { + return csum16_add(csum, ~addend); +} diff --git a/testdata/p4tc_samples_outputs/tc_may_override_example_04.json b/testdata/p4tc_samples_outputs/tc_may_override_example_04.json new file mode 100644 index 0000000000..09c28f647b --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_04.json @@ -0,0 +1,113 @@ +{ + "schema_version" : "1.0.0", + "pipeline_name" : "tc_may_override_example_04", + "tables" : [ + { + "name" : "MainControlImpl/ipv4_tbl_1", + "id" : 1, + "tentries" : 2048, + "nummask" : 8, + "keysize" : 64, + "keyfields" : [ + { + "id" : 1, + "name" : "hdr.ipv4.dstAddr", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + }, + { + "id" : 2, + "name" : "istd.input_port", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + } + ], + "actions" : [ + { + "id" : 1, + "name" : "MainControlImpl/next_hop", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [ + { + "id" : 1, + "name" : "ipv4addr", + "type" : "ipv4", + "bitwidth" : 32 + } + ], + "default_hit_action" : false, + "default_miss_action" : true + }, + { + "id" : 2, + "name" : "MainControlImpl/default_route_drop", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [], + "default_hit_action" : false, + "default_miss_action" : false + } + ] + }, + { + "name" : "MainControlImpl/ipv4_tbl_2", + "id" : 2, + "tentries" : 2048, + "nummask" : 8, + "keysize" : 72, + "keyfields" : [ + { + "id" : 1, + "name" : "hdr.ipv4.dstAddr", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + }, + { + "id" : 2, + "name" : "hdr.ipv4.srcAddr", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + }, + { + "id" : 3, + "name" : "hdr.ipv4.protocol", + "type" : "bit8", + "match_type" : "exact", + "bitwidth" : 8 + } + ], + "actions" : [ + { + "id" : 1, + "name" : "MainControlImpl/next_hop", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [ + { + "id" : 1, + "name" : "ipv4addr", + "type" : "ipv4", + "bitwidth" : 32 + } + ], + "default_hit_action" : false, + "default_miss_action" : false + }, + { + "id" : 3, + "name" : "MainControlImpl/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/tc_may_override_example_04.p4-stderr b/testdata/p4tc_samples_outputs/tc_may_override_example_04.p4-stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/testdata/p4tc_samples_outputs/tc_may_override_example_04.template b/testdata/p4tc_samples_outputs/tc_may_override_example_04.template new file mode 100755 index 0000000000..13d0dc0f83 --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_04.template @@ -0,0 +1,33 @@ +#!/bin/bash -x + +set -e + +TC="tc" +$TC p4template create pipeline/tc_may_override_example_04 numtables 2 + +$TC p4template create action/tc_may_override_example_04/MainControlImpl/next_hop actid 1 \ + param ipv4addr type ipv4 +$TC p4template update action/tc_may_override_example_04/MainControlImpl/next_hop state active + +$TC p4template create action/tc_may_override_example_04/MainControlImpl/default_route_drop actid 2 +$TC p4template update action/tc_may_override_example_04/MainControlImpl/default_route_drop state active + +$TC p4template create action/tc_may_override_example_04/MainControlImpl/drop actid 3 +$TC p4template update action/tc_may_override_example_04/MainControlImpl/drop state active + +$TC p4template create table/tc_may_override_example_04/MainControlImpl/ipv4_tbl_1 \ + tblid 1 \ + type exact \ + keysz 64 nummasks 8 tentries 2048 \ + table_acts act name tc_may_override_example_04/MainControlImpl/next_hop \ + act name tc_may_override_example_04/MainControlImpl/default_route_drop +$TC p4template update table/tc_may_override_example_04/MainControlImpl/ipv4_tbl_1 default_miss_action action tc_may_override_example_04/MainControlImpl/next_hop param ipv4addr flags runtime + +$TC p4template create table/tc_may_override_example_04/MainControlImpl/ipv4_tbl_2 \ + tblid 2 \ + type exact \ + keysz 72 nummasks 8 tentries 2048 \ + table_acts act name tc_may_override_example_04/MainControlImpl/next_hop \ + act name tc_may_override_example_04/MainControlImpl/drop +$TC p4template update table/tc_may_override_example_04/MainControlImpl/ipv4_tbl_2 default_miss_action action tc_may_override_example_04/MainControlImpl/drop +$TC p4template update pipeline/tc_may_override_example_04 state ready \ No newline at end of file diff --git a/testdata/p4tc_samples_outputs/tc_may_override_example_04_control_blocks.c b/testdata/p4tc_samples_outputs/tc_may_override_example_04_control_blocks.c new file mode 100644 index 0000000000..57a6ba43b8 --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_04_control_blocks.c @@ -0,0 +1,371 @@ +#include "tc_may_override_example_04_parser.h" +struct p4tc_filter_fields p4tc_filter_fields; + +struct internal_metadata { + __u16 pkt_ether_type; +} __attribute__((aligned(4))); + +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_1_key { + u32 keysz; + u32 maskid; + u32 field0; /* hdr.ipv4.dstAddr */ + u32 field1; /* istd.input_port */ +} __attribute__((aligned(8))); +#define MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_NEXT_HOP 1 +#define MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_DEFAULT_ROUTE_DROP 2 +#define MAINCONTROLIMPL_IPV4_TBL_1_ACT_NOACTION 0 +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_1_value { + unsigned int action; + u32 hit:1, + is_default_miss_act:1, + is_default_hit_act:1; + union { + struct { + } _NoAction; + struct __attribute__((__packed__)) { + u32 ipv4addr; + } MainControlImpl_next_hop; + struct { + } MainControlImpl_default_route_drop; + } u; +}; +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_2_key { + u32 keysz; + u32 maskid; + u32 field0; /* hdr.ipv4.dstAddr */ + u32 field1; /* hdr.ipv4.srcAddr */ + u8 field2; /* hdr.ipv4.protocol */ +} __attribute__((aligned(8))); +#define MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_NEXT_HOP 1 +#define MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_DROP 3 +#define MAINCONTROLIMPL_IPV4_TBL_2_ACT_NOACTION 0 +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_2_value { + unsigned int action; + u32 hit:1, + is_default_miss_act:1, + is_default_hit_act:1; + union { + struct { + } _NoAction; + struct __attribute__((__packed__)) { + u32 ipv4addr; + } MainControlImpl_next_hop; + struct { + } MainControlImpl_drop; + } u; +}; + +static __always_inline int process(struct __sk_buff *skb, struct 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 main_metadata_t *user_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); + user_meta = &(hdrMd->cpumap_usermeta); +{ + u8 hit; + { +if (/* hdr->ipv4.isValid() */ + hdr->ipv4.ebpf_valid) { +/* ipv4_tbl.apply() */ + { + /* construct key */ + struct p4tc_table_entry_act_bpf_params__local params = { + .pipeid = p4tc_filter_fields.pipeid, + .tblid = 1 + }; + struct MainControlImpl_ipv4_tbl_1_key key; + __builtin_memset(&key, 0, sizeof(key)); + key.keysz = 64; + key.field0 = hdr->ipv4.dstAddr; + key.field1 = skb->ifindex; + struct p4tc_table_entry_act_bpf *act_bpf; + /* value */ + struct MainControlImpl_ipv4_tbl_1_value *value = NULL; + /* perform lookup */ + act_bpf = bpf_p4tc_tbl_read(skb, ¶ms, &key, sizeof(key)); + value = (struct MainControlImpl_ipv4_tbl_1_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 MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_NEXT_HOP: + { + hdr->ipv4.dstAddr = value->u.MainControlImpl_next_hop.ipv4addr; + /* send_to_port(8) */ + compiler_meta__->drop = false; + send_to_port(8); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_DEFAULT_ROUTE_DROP: + { +/* drop_packet() */ + drop_packet(); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_1_ACT_NOACTION: + { + } + break; + } + } else { + } + } +; + /* ipv4_tbl_0.apply() */ + { + /* construct key */ + struct p4tc_table_entry_act_bpf_params__local params = { + .pipeid = p4tc_filter_fields.pipeid, + .tblid = 2 + }; + struct MainControlImpl_ipv4_tbl_2_key key; + __builtin_memset(&key, 0, sizeof(key)); + key.keysz = 72; + key.field0 = hdr->ipv4.dstAddr; + key.field1 = hdr->ipv4.srcAddr; + key.field2 = hdr->ipv4.protocol; + struct p4tc_table_entry_act_bpf *act_bpf; + /* value */ + struct MainControlImpl_ipv4_tbl_2_value *value = NULL; + /* perform lookup */ + act_bpf = bpf_p4tc_tbl_read(skb, ¶ms, &key, sizeof(key)); + value = (struct MainControlImpl_ipv4_tbl_2_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 MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_NEXT_HOP: + { + hdr->ipv4.dstAddr = value->u.MainControlImpl_next_hop.ipv4addr; + /* send_to_port(8) */ + compiler_meta__->drop = false; + send_to_port(8); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_DROP: + { +/* drop_packet() */ + drop_packet(); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_2_ACT_NOACTION: + { + } + break; + } + } else { + } + } +; + } + } + } + { +{ +; + ; + } + + 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; + } + + hdr->ethernet.dstAddr = htonll(hdr->ethernet.dstAddr << 16); + 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; + + hdr->ethernet.srcAddr = htonll(hdr->ethernet.srcAddr << 16); + 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; + 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 headers_t *hdr; + int ret = -1; + ret = process(skb, (struct 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/tc_may_override_example_04_parser.c b/testdata/p4tc_samples_outputs/tc_may_override_example_04_parser.c new file mode 100644 index 0000000000..10ba238ba2 --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_04_parser.c @@ -0,0 +1,136 @@ +#include "tc_may_override_example_04_parser.h" + +struct p4tc_filter_fields p4tc_filter_fields; + +static __always_inline int run_parser(struct __sk_buff *skb, struct 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 main_metadata_t *user_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); + user_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); + +; + goto accept; + } + start: { +/* extract(hdr->ethernet) */ + if ((u8*)ebpf_packetEnd < hdr_start + BYTES(112 + 0)) { + ebpf_errorCode = PacketTooShort; + goto reject; + } + + hdr->ethernet.dstAddr = (u64)((load_dword(pkt, BYTES(ebpf_packetOffsetInBits)) >> 16) & EBPF_MASK(u64, 48)); + ebpf_packetOffsetInBits += 48; + + hdr->ethernet.srcAddr = (u64)((load_dword(pkt, BYTES(ebpf_packetOffsetInBits)) >> 16) & EBPF_MASK(u64, 48)); + 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_0; + select_0 = hdr->ethernet.etherType; + if (select_0 == 0x800)goto parse_ipv4; + if ((select_0 & 0x0) == (0x0 & 0x0))goto accept; + 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 headers_t *hdr; + int ret = -1; + ret = run_parser(skb, (struct 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/tc_may_override_example_04_parser.h b/testdata/p4tc_samples_outputs/tc_may_override_example_04_parser.h new file mode 100644 index 0000000000..0c06ab8247 --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_04_parser.h @@ -0,0 +1,164 @@ +#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; /* EthernetAddress */ + u64 srcAddr; /* EthernetAddress */ + 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 main_metadata_t { +}; +struct headers_t { + struct ethernet_t ethernet; /* ethernet_t */ + struct ipv4_t ipv4; /* ipv4_t */ +}; + +struct hdr_md { + struct headers_t cpumap_hdr; + struct main_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; + ipv4 ipv4_tbl_1_next_hop_ipv4addr; +}; + +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; +} +inline u16 csum16_add(u16 csum, u16 addend) { + u16 res = csum; + res += addend; + return (res + (res < addend)); +} +inline u16 csum16_sub(u16 csum, u16 addend) { + return csum16_add(csum, ~addend); +} diff --git a/testdata/p4tc_samples_outputs/tc_may_override_example_05.json b/testdata/p4tc_samples_outputs/tc_may_override_example_05.json new file mode 100644 index 0000000000..135c370f6c --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_05.json @@ -0,0 +1,113 @@ +{ + "schema_version" : "1.0.0", + "pipeline_name" : "tc_may_override_example_05", + "tables" : [ + { + "name" : "MainControlImpl/ipv4_tbl_1", + "id" : 1, + "tentries" : 2048, + "nummask" : 8, + "keysize" : 64, + "keyfields" : [ + { + "id" : 1, + "name" : "hdr.ipv4.dstAddr", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + }, + { + "id" : 2, + "name" : "istd.input_port", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + } + ], + "actions" : [ + { + "id" : 1, + "name" : "MainControlImpl/next_hop", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [ + { + "id" : 1, + "name" : "vport", + "type" : "dev", + "bitwidth" : 32 + } + ], + "default_hit_action" : false, + "default_miss_action" : true + }, + { + "id" : 2, + "name" : "MainControlImpl/default_route_drop", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [], + "default_hit_action" : false, + "default_miss_action" : false + } + ] + }, + { + "name" : "MainControlImpl/ipv4_tbl_2", + "id" : 2, + "tentries" : 2048, + "nummask" : 8, + "keysize" : 72, + "keyfields" : [ + { + "id" : 1, + "name" : "hdr.ipv4.dstAddr", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + }, + { + "id" : 2, + "name" : "hdr.ipv4.srcAddr", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + }, + { + "id" : 3, + "name" : "hdr.ipv4.protocol", + "type" : "bit8", + "match_type" : "exact", + "bitwidth" : 8 + } + ], + "actions" : [ + { + "id" : 1, + "name" : "MainControlImpl/next_hop", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [ + { + "id" : 1, + "name" : "vport", + "type" : "dev", + "bitwidth" : 32 + } + ], + "default_hit_action" : false, + "default_miss_action" : false + }, + { + "id" : 3, + "name" : "MainControlImpl/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/tc_may_override_example_05.p4-stderr b/testdata/p4tc_samples_outputs/tc_may_override_example_05.p4-stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/testdata/p4tc_samples_outputs/tc_may_override_example_05.template b/testdata/p4tc_samples_outputs/tc_may_override_example_05.template new file mode 100755 index 0000000000..c641e7625c --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_05.template @@ -0,0 +1,33 @@ +#!/bin/bash -x + +set -e + +TC="tc" +$TC p4template create pipeline/tc_may_override_example_05 numtables 2 + +$TC p4template create action/tc_may_override_example_05/MainControlImpl/next_hop actid 1 \ + param vport type dev +$TC p4template update action/tc_may_override_example_05/MainControlImpl/next_hop state active + +$TC p4template create action/tc_may_override_example_05/MainControlImpl/default_route_drop actid 2 +$TC p4template update action/tc_may_override_example_05/MainControlImpl/default_route_drop state active + +$TC p4template create action/tc_may_override_example_05/MainControlImpl/drop actid 3 +$TC p4template update action/tc_may_override_example_05/MainControlImpl/drop state active + +$TC p4template create table/tc_may_override_example_05/MainControlImpl/ipv4_tbl_1 \ + tblid 1 \ + type exact \ + keysz 64 nummasks 8 tentries 2048 \ + table_acts act name tc_may_override_example_05/MainControlImpl/next_hop \ + act name tc_may_override_example_05/MainControlImpl/default_route_drop +$TC p4template update table/tc_may_override_example_05/MainControlImpl/ipv4_tbl_1 default_miss_action action tc_may_override_example_05/MainControlImpl/next_hop param vport flags runtime + +$TC p4template create table/tc_may_override_example_05/MainControlImpl/ipv4_tbl_2 \ + tblid 2 \ + type exact \ + keysz 72 nummasks 8 tentries 2048 \ + table_acts act name tc_may_override_example_05/MainControlImpl/next_hop \ + act name tc_may_override_example_05/MainControlImpl/drop +$TC p4template update table/tc_may_override_example_05/MainControlImpl/ipv4_tbl_2 default_miss_action action tc_may_override_example_05/MainControlImpl/drop +$TC p4template update pipeline/tc_may_override_example_05 state ready \ No newline at end of file diff --git a/testdata/p4tc_samples_outputs/tc_may_override_example_05_control_blocks.c b/testdata/p4tc_samples_outputs/tc_may_override_example_05_control_blocks.c new file mode 100644 index 0000000000..6d31d4a49f --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_05_control_blocks.c @@ -0,0 +1,369 @@ +#include "tc_may_override_example_05_parser.h" +struct p4tc_filter_fields p4tc_filter_fields; + +struct internal_metadata { + __u16 pkt_ether_type; +} __attribute__((aligned(4))); + +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_1_key { + u32 keysz; + u32 maskid; + u32 field0; /* hdr.ipv4.dstAddr */ + u32 field1; /* istd.input_port */ +} __attribute__((aligned(8))); +#define MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_NEXT_HOP 1 +#define MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_DEFAULT_ROUTE_DROP 2 +#define MAINCONTROLIMPL_IPV4_TBL_1_ACT_NOACTION 0 +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_1_value { + unsigned int action; + u32 hit:1, + is_default_miss_act:1, + is_default_hit_act:1; + union { + struct { + } _NoAction; + struct __attribute__((__packed__)) { + u32 vport; + } MainControlImpl_next_hop; + struct { + } MainControlImpl_default_route_drop; + } u; +}; +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_2_key { + u32 keysz; + u32 maskid; + u32 field0; /* hdr.ipv4.dstAddr */ + u32 field1; /* hdr.ipv4.srcAddr */ + u8 field2; /* hdr.ipv4.protocol */ +} __attribute__((aligned(8))); +#define MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_NEXT_HOP 1 +#define MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_DROP 3 +#define MAINCONTROLIMPL_IPV4_TBL_2_ACT_NOACTION 0 +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_2_value { + unsigned int action; + u32 hit:1, + is_default_miss_act:1, + is_default_hit_act:1; + union { + struct { + } _NoAction; + struct __attribute__((__packed__)) { + u32 vport; + } MainControlImpl_next_hop; + struct { + } MainControlImpl_drop; + } u; +}; + +static __always_inline int process(struct __sk_buff *skb, struct 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 main_metadata_t *user_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); + user_meta = &(hdrMd->cpumap_usermeta); +{ + u8 hit; + { +if (/* hdr->ipv4.isValid() */ + hdr->ipv4.ebpf_valid) { +/* ipv4_tbl.apply() */ + { + /* construct key */ + struct p4tc_table_entry_act_bpf_params__local params = { + .pipeid = p4tc_filter_fields.pipeid, + .tblid = 1 + }; + struct MainControlImpl_ipv4_tbl_1_key key; + __builtin_memset(&key, 0, sizeof(key)); + key.keysz = 64; + key.field0 = hdr->ipv4.dstAddr; + key.field1 = skb->ifindex; + struct p4tc_table_entry_act_bpf *act_bpf; + /* value */ + struct MainControlImpl_ipv4_tbl_1_value *value = NULL; + /* perform lookup */ + act_bpf = bpf_p4tc_tbl_read(skb, ¶ms, &key, sizeof(key)); + value = (struct MainControlImpl_ipv4_tbl_1_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 MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_NEXT_HOP: + { +/* send_to_port(value->u.MainControlImpl_next_hop.vport) */ + compiler_meta__->drop = false; + send_to_port(value->u.MainControlImpl_next_hop.vport); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_DEFAULT_ROUTE_DROP: + { +/* drop_packet() */ + drop_packet(); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_1_ACT_NOACTION: + { + } + break; + } + } else { + } + } +; + /* ipv4_tbl_0.apply() */ + { + /* construct key */ + struct p4tc_table_entry_act_bpf_params__local params = { + .pipeid = p4tc_filter_fields.pipeid, + .tblid = 2 + }; + struct MainControlImpl_ipv4_tbl_2_key key; + __builtin_memset(&key, 0, sizeof(key)); + key.keysz = 72; + key.field0 = hdr->ipv4.dstAddr; + key.field1 = hdr->ipv4.srcAddr; + key.field2 = hdr->ipv4.protocol; + struct p4tc_table_entry_act_bpf *act_bpf; + /* value */ + struct MainControlImpl_ipv4_tbl_2_value *value = NULL; + /* perform lookup */ + act_bpf = bpf_p4tc_tbl_read(skb, ¶ms, &key, sizeof(key)); + value = (struct MainControlImpl_ipv4_tbl_2_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 MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_NEXT_HOP: + { +/* send_to_port(value->u.MainControlImpl_next_hop.vport) */ + compiler_meta__->drop = false; + send_to_port(value->u.MainControlImpl_next_hop.vport); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_DROP: + { +/* drop_packet() */ + drop_packet(); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_2_ACT_NOACTION: + { + } + break; + } + } else { + } + } +; + } + } + } + { +{ +; + ; + } + + 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; + } + + hdr->ethernet.dstAddr = htonll(hdr->ethernet.dstAddr << 16); + 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; + + hdr->ethernet.srcAddr = htonll(hdr->ethernet.srcAddr << 16); + 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; + 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 headers_t *hdr; + int ret = -1; + ret = process(skb, (struct 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/tc_may_override_example_05_parser.c b/testdata/p4tc_samples_outputs/tc_may_override_example_05_parser.c new file mode 100644 index 0000000000..dcb5018eb1 --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_05_parser.c @@ -0,0 +1,136 @@ +#include "tc_may_override_example_05_parser.h" + +struct p4tc_filter_fields p4tc_filter_fields; + +static __always_inline int run_parser(struct __sk_buff *skb, struct 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 main_metadata_t *user_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); + user_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); + +; + goto accept; + } + start: { +/* extract(hdr->ethernet) */ + if ((u8*)ebpf_packetEnd < hdr_start + BYTES(112 + 0)) { + ebpf_errorCode = PacketTooShort; + goto reject; + } + + hdr->ethernet.dstAddr = (u64)((load_dword(pkt, BYTES(ebpf_packetOffsetInBits)) >> 16) & EBPF_MASK(u64, 48)); + ebpf_packetOffsetInBits += 48; + + hdr->ethernet.srcAddr = (u64)((load_dword(pkt, BYTES(ebpf_packetOffsetInBits)) >> 16) & EBPF_MASK(u64, 48)); + 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_0; + select_0 = hdr->ethernet.etherType; + if (select_0 == 0x800)goto parse_ipv4; + if ((select_0 & 0x0) == (0x0 & 0x0))goto accept; + 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 headers_t *hdr; + int ret = -1; + ret = run_parser(skb, (struct 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/tc_may_override_example_05_parser.h b/testdata/p4tc_samples_outputs/tc_may_override_example_05_parser.h new file mode 100644 index 0000000000..48e706ed20 --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_05_parser.h @@ -0,0 +1,164 @@ +#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; /* EthernetAddress */ + u64 srcAddr; /* EthernetAddress */ + 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 main_metadata_t { +}; +struct headers_t { + struct ethernet_t ethernet; /* ethernet_t */ + struct ipv4_t ipv4; /* ipv4_t */ +}; + +struct hdr_md { + struct headers_t cpumap_hdr; + struct main_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; + dev ipv4_tbl_1_next_hop_vport; +}; + +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; +} +inline u16 csum16_add(u16 csum, u16 addend) { + u16 res = csum; + res += addend; + return (res + (res < addend)); +} +inline u16 csum16_sub(u16 csum, u16 addend) { + return csum16_add(csum, ~addend); +} diff --git a/testdata/p4tc_samples_outputs/tc_may_override_example_06.json b/testdata/p4tc_samples_outputs/tc_may_override_example_06.json new file mode 100644 index 0000000000..bd88737a9f --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_06.json @@ -0,0 +1,113 @@ +{ + "schema_version" : "1.0.0", + "pipeline_name" : "tc_may_override_example_06", + "tables" : [ + { + "name" : "MainControlImpl/ipv4_tbl_1", + "id" : 1, + "tentries" : 2048, + "nummask" : 8, + "keysize" : 64, + "keyfields" : [ + { + "id" : 1, + "name" : "hdr.ipv4.dstAddr", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + }, + { + "id" : 2, + "name" : "istd.input_port", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + } + ], + "actions" : [ + { + "id" : 1, + "name" : "MainControlImpl/next_hop", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [ + { + "id" : 1, + "name" : "vport", + "type" : "dev", + "bitwidth" : 32 + } + ], + "default_hit_action" : false, + "default_miss_action" : true + }, + { + "id" : 2, + "name" : "MainControlImpl/default_route_drop", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [], + "default_hit_action" : false, + "default_miss_action" : false + } + ] + }, + { + "name" : "MainControlImpl/ipv4_tbl_2", + "id" : 2, + "tentries" : 2048, + "nummask" : 8, + "keysize" : 72, + "keyfields" : [ + { + "id" : 1, + "name" : "hdr.ipv4.dstAddr", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + }, + { + "id" : 2, + "name" : "hdr.ipv4.srcAddr", + "type" : "bit32", + "match_type" : "exact", + "bitwidth" : 32 + }, + { + "id" : 3, + "name" : "hdr.ipv4.protocol", + "type" : "bit8", + "match_type" : "exact", + "bitwidth" : 8 + } + ], + "actions" : [ + { + "id" : 1, + "name" : "MainControlImpl/next_hop", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [ + { + "id" : 1, + "name" : "vport", + "type" : "dev", + "bitwidth" : 32 + } + ], + "default_hit_action" : false, + "default_miss_action" : true + }, + { + "id" : 3, + "name" : "MainControlImpl/drop", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [], + "default_hit_action" : false, + "default_miss_action" : false + } + ] + } + ] +} \ No newline at end of file diff --git a/testdata/p4tc_samples_outputs/tc_may_override_example_06.p4-stderr b/testdata/p4tc_samples_outputs/tc_may_override_example_06.p4-stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/testdata/p4tc_samples_outputs/tc_may_override_example_06.template b/testdata/p4tc_samples_outputs/tc_may_override_example_06.template new file mode 100755 index 0000000000..67622f6f9f --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_06.template @@ -0,0 +1,33 @@ +#!/bin/bash -x + +set -e + +TC="tc" +$TC p4template create pipeline/tc_may_override_example_06 numtables 2 + +$TC p4template create action/tc_may_override_example_06/MainControlImpl/next_hop actid 1 \ + param vport type dev +$TC p4template update action/tc_may_override_example_06/MainControlImpl/next_hop state active + +$TC p4template create action/tc_may_override_example_06/MainControlImpl/default_route_drop actid 2 +$TC p4template update action/tc_may_override_example_06/MainControlImpl/default_route_drop state active + +$TC p4template create action/tc_may_override_example_06/MainControlImpl/drop actid 3 +$TC p4template update action/tc_may_override_example_06/MainControlImpl/drop state active + +$TC p4template create table/tc_may_override_example_06/MainControlImpl/ipv4_tbl_1 \ + tblid 1 \ + type exact \ + keysz 64 nummasks 8 tentries 2048 \ + table_acts act name tc_may_override_example_06/MainControlImpl/next_hop \ + act name tc_may_override_example_06/MainControlImpl/default_route_drop +$TC p4template update table/tc_may_override_example_06/MainControlImpl/ipv4_tbl_1 default_miss_action action tc_may_override_example_06/MainControlImpl/next_hop param vport flags runtime + +$TC p4template create table/tc_may_override_example_06/MainControlImpl/ipv4_tbl_2 \ + tblid 2 \ + type exact \ + keysz 72 nummasks 8 tentries 2048 \ + table_acts act name tc_may_override_example_06/MainControlImpl/next_hop \ + act name tc_may_override_example_06/MainControlImpl/drop +$TC p4template update table/tc_may_override_example_06/MainControlImpl/ipv4_tbl_2 default_miss_action action tc_may_override_example_06/MainControlImpl/next_hop param vport flags runtime +$TC p4template update pipeline/tc_may_override_example_06 state ready \ No newline at end of file diff --git a/testdata/p4tc_samples_outputs/tc_may_override_example_06_control_blocks.c b/testdata/p4tc_samples_outputs/tc_may_override_example_06_control_blocks.c new file mode 100644 index 0000000000..be449ad291 --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_06_control_blocks.c @@ -0,0 +1,369 @@ +#include "tc_may_override_example_06_parser.h" +struct p4tc_filter_fields p4tc_filter_fields; + +struct internal_metadata { + __u16 pkt_ether_type; +} __attribute__((aligned(4))); + +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_1_key { + u32 keysz; + u32 maskid; + u32 field0; /* hdr.ipv4.dstAddr */ + u32 field1; /* istd.input_port */ +} __attribute__((aligned(8))); +#define MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_NEXT_HOP 1 +#define MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_DEFAULT_ROUTE_DROP 2 +#define MAINCONTROLIMPL_IPV4_TBL_1_ACT_NOACTION 0 +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_1_value { + unsigned int action; + u32 hit:1, + is_default_miss_act:1, + is_default_hit_act:1; + union { + struct { + } _NoAction; + struct __attribute__((__packed__)) { + u32 vport; + } MainControlImpl_next_hop; + struct { + } MainControlImpl_default_route_drop; + } u; +}; +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_2_key { + u32 keysz; + u32 maskid; + u32 field0; /* hdr.ipv4.dstAddr */ + u32 field1; /* hdr.ipv4.srcAddr */ + u8 field2; /* hdr.ipv4.protocol */ +} __attribute__((aligned(8))); +#define MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_NEXT_HOP 1 +#define MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_DROP 3 +#define MAINCONTROLIMPL_IPV4_TBL_2_ACT_NOACTION 0 +struct __attribute__((__packed__)) MainControlImpl_ipv4_tbl_2_value { + unsigned int action; + u32 hit:1, + is_default_miss_act:1, + is_default_hit_act:1; + union { + struct { + } _NoAction; + struct __attribute__((__packed__)) { + u32 vport; + } MainControlImpl_next_hop; + struct { + } MainControlImpl_drop; + } u; +}; + +static __always_inline int process(struct __sk_buff *skb, struct 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 main_metadata_t *user_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); + user_meta = &(hdrMd->cpumap_usermeta); +{ + u8 hit; + { +if (/* hdr->ipv4.isValid() */ + hdr->ipv4.ebpf_valid) { +/* ipv4_tbl.apply() */ + { + /* construct key */ + struct p4tc_table_entry_act_bpf_params__local params = { + .pipeid = p4tc_filter_fields.pipeid, + .tblid = 1 + }; + struct MainControlImpl_ipv4_tbl_1_key key; + __builtin_memset(&key, 0, sizeof(key)); + key.keysz = 64; + key.field0 = hdr->ipv4.dstAddr; + key.field1 = skb->ifindex; + struct p4tc_table_entry_act_bpf *act_bpf; + /* value */ + struct MainControlImpl_ipv4_tbl_1_value *value = NULL; + /* perform lookup */ + act_bpf = bpf_p4tc_tbl_read(skb, ¶ms, &key, sizeof(key)); + value = (struct MainControlImpl_ipv4_tbl_1_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 MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_NEXT_HOP: + { +/* send_to_port(value->u.MainControlImpl_next_hop.vport) */ + compiler_meta__->drop = false; + send_to_port(value->u.MainControlImpl_next_hop.vport); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_1_ACT_MAINCONTROLIMPL_DEFAULT_ROUTE_DROP: + { +/* drop_packet() */ + drop_packet(); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_1_ACT_NOACTION: + { + } + break; + } + } else { + } + } +; + /* ipv4_tbl_0.apply() */ + { + /* construct key */ + struct p4tc_table_entry_act_bpf_params__local params = { + .pipeid = p4tc_filter_fields.pipeid, + .tblid = 2 + }; + struct MainControlImpl_ipv4_tbl_2_key key; + __builtin_memset(&key, 0, sizeof(key)); + key.keysz = 72; + key.field0 = hdr->ipv4.dstAddr; + key.field1 = hdr->ipv4.srcAddr; + key.field2 = hdr->ipv4.protocol; + struct p4tc_table_entry_act_bpf *act_bpf; + /* value */ + struct MainControlImpl_ipv4_tbl_2_value *value = NULL; + /* perform lookup */ + act_bpf = bpf_p4tc_tbl_read(skb, ¶ms, &key, sizeof(key)); + value = (struct MainControlImpl_ipv4_tbl_2_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 MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_NEXT_HOP: + { +/* send_to_port(value->u.MainControlImpl_next_hop.vport) */ + compiler_meta__->drop = false; + send_to_port(value->u.MainControlImpl_next_hop.vport); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_2_ACT_MAINCONTROLIMPL_DROP: + { +/* drop_packet() */ + drop_packet(); + } + break; + case MAINCONTROLIMPL_IPV4_TBL_2_ACT_NOACTION: + { + } + break; + } + } else { + } + } +; + } + } + } + { +{ +; + ; + } + + 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; + } + + hdr->ethernet.dstAddr = htonll(hdr->ethernet.dstAddr << 16); + 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; + + hdr->ethernet.srcAddr = htonll(hdr->ethernet.srcAddr << 16); + 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; + 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 headers_t *hdr; + int ret = -1; + ret = process(skb, (struct 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/tc_may_override_example_06_parser.c b/testdata/p4tc_samples_outputs/tc_may_override_example_06_parser.c new file mode 100644 index 0000000000..ea7398e3bf --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_06_parser.c @@ -0,0 +1,136 @@ +#include "tc_may_override_example_06_parser.h" + +struct p4tc_filter_fields p4tc_filter_fields; + +static __always_inline int run_parser(struct __sk_buff *skb, struct 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 main_metadata_t *user_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); + user_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); + +; + goto accept; + } + start: { +/* extract(hdr->ethernet) */ + if ((u8*)ebpf_packetEnd < hdr_start + BYTES(112 + 0)) { + ebpf_errorCode = PacketTooShort; + goto reject; + } + + hdr->ethernet.dstAddr = (u64)((load_dword(pkt, BYTES(ebpf_packetOffsetInBits)) >> 16) & EBPF_MASK(u64, 48)); + ebpf_packetOffsetInBits += 48; + + hdr->ethernet.srcAddr = (u64)((load_dword(pkt, BYTES(ebpf_packetOffsetInBits)) >> 16) & EBPF_MASK(u64, 48)); + 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_0; + select_0 = hdr->ethernet.etherType; + if (select_0 == 0x800)goto parse_ipv4; + if ((select_0 & 0x0) == (0x0 & 0x0))goto accept; + 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 headers_t *hdr; + int ret = -1; + ret = run_parser(skb, (struct 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/tc_may_override_example_06_parser.h b/testdata/p4tc_samples_outputs/tc_may_override_example_06_parser.h new file mode 100644 index 0000000000..61a32160ed --- /dev/null +++ b/testdata/p4tc_samples_outputs/tc_may_override_example_06_parser.h @@ -0,0 +1,165 @@ +#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; /* EthernetAddress */ + u64 srcAddr; /* EthernetAddress */ + 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 main_metadata_t { +}; +struct headers_t { + struct ethernet_t ethernet; /* ethernet_t */ + struct ipv4_t ipv4; /* ipv4_t */ +}; + +struct hdr_md { + struct headers_t cpumap_hdr; + struct main_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; + dev ipv4_tbl_1_next_hop_vport; + dev ipv4_tbl_2_next_hop_vport; +}; + +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; +} +inline u16 csum16_add(u16 csum, u16 addend) { + u16 res = csum; + res += addend; + return (res + (res < addend)); +} +inline u16 csum16_sub(u16 csum, u16 addend) { + return csum16_add(csum, ~addend); +}