From c43b24a9b52ec846793cb1567b16a19d0ba82fa8 Mon Sep 17 00:00:00 2001 From: Komal Jain Date: Tue, 30 Jan 2024 13:02:47 +0530 Subject: [PATCH] P4TC - Support const entries (#4329) * Fix actionparams type field in introspection.json * Support const_entries * Update testcase * Address new changes * Address comments * Addressed comments * Fix issue when all entries are not emitted in case of multiple entry with same action --- backends/tc/backend.cpp | 60 +++ backends/tc/backend.h | 4 + backends/tc/tc.def | 31 ++ lib/stringify.h | 1 + testdata/p4tc_samples/calculator.p4 | 239 ++++++++++++ .../p4tc_samples/const_entries_range_mask.p4 | 75 ++++ testdata/p4tc_samples_outputs/calculator.json | 79 ++++ .../p4tc_samples_outputs/calculator.p4-stderr | 0 .../p4tc_samples_outputs/calculator.template | 42 ++ .../calculator_control_blocks.c | 360 ++++++++++++++++++ .../p4tc_samples_outputs/calculator_parser.c | 224 +++++++++++ .../p4tc_samples_outputs/calculator_parser.h | 43 +++ .../const_entries_range_mask.json | 50 +++ .../const_entries_range_mask.p4-stderr | 0 .../const_entries_range_mask.template | 27 ++ .../const_entries_range_mask_control_blocks.c | 180 +++++++++ .../const_entries_range_mask_parser.c | 87 +++++ .../const_entries_range_mask_parser.h | 34 ++ .../multiple_tables_example_01.template | 6 + .../multiple_tables_example_02.template | 6 + 20 files changed, 1548 insertions(+) create mode 100644 testdata/p4tc_samples/calculator.p4 create mode 100644 testdata/p4tc_samples/const_entries_range_mask.p4 create mode 100644 testdata/p4tc_samples_outputs/calculator.json create mode 100644 testdata/p4tc_samples_outputs/calculator.p4-stderr create mode 100755 testdata/p4tc_samples_outputs/calculator.template create mode 100644 testdata/p4tc_samples_outputs/calculator_control_blocks.c create mode 100644 testdata/p4tc_samples_outputs/calculator_parser.c create mode 100644 testdata/p4tc_samples_outputs/calculator_parser.h create mode 100644 testdata/p4tc_samples_outputs/const_entries_range_mask.json create mode 100644 testdata/p4tc_samples_outputs/const_entries_range_mask.p4-stderr create mode 100755 testdata/p4tc_samples_outputs/const_entries_range_mask.template create mode 100644 testdata/p4tc_samples_outputs/const_entries_range_mask_control_blocks.c create mode 100644 testdata/p4tc_samples_outputs/const_entries_range_mask_parser.c create mode 100644 testdata/p4tc_samples_outputs/const_entries_range_mask_parser.h diff --git a/backends/tc/backend.cpp b/backends/tc/backend.cpp index a1afef187e..17697e9e06 100644 --- a/backends/tc/backend.cpp +++ b/backends/tc/backend.cpp @@ -271,6 +271,65 @@ void ConvertToBackendIR::postorder(const IR::P4Action *action) { } } +void ConvertToBackendIR::updateConstEntries(const IR::P4Table *t, IR::TCTable *tabledef) { + // Check if there are const entries. + auto entriesList = t->getEntries(); + if (entriesList == nullptr) return; + auto keys = t->getKey(); + if (keys == nullptr) { + return; + } + for (auto e : entriesList->entries) { + auto keyset = e->getKeys(); + if (keyset->components.size() != keys->keyElements.size()) { + ::error(ErrorType::ERR_INVALID, + "No of keys in const_entries should be same as no of keys in the table."); + return; + } + ordered_map keyList; + for (size_t itr = 0; itr < keyset->components.size(); itr++) { + auto keyElement = keys->keyElements.at(itr); + auto keyString = keyElement->expression->toString(); + auto annotations = keyElement->getAnnotations(); + if (annotations) { + if (auto anno = annotations->getSingle("name")) { + keyString = anno->expr.at(0)->to()->value; + } + } + auto keySetElement = keyset->components.at(itr); + auto key = keySetElement->toString(); + if (keySetElement->is()) { + key = "default"; + } else if (keySetElement->is()) { + big_int kValue = keySetElement->to()->value; + int kBase = keySetElement->to()->base; + std::stringstream value; + std::deque buf; + do { + const int digit = static_cast(static_cast(kValue % kBase)); + kValue = kValue / kBase; + buf.push_front(Util::DigitToChar(digit)); + } while (kValue > 0); + for (auto ch : buf) value << ch; + key = value.str().c_str(); + } else if (keySetElement->is()) { + auto left = keySetElement->to()->left; + auto right = keySetElement->to()->right; + auto operand = keySetElement->to()->getStringOp(); + key = left->toString() + operand + right->toString(); + } else if (keySetElement->is()) { + auto left = keySetElement->to()->left; + auto right = keySetElement->to()->right; + auto operand = keySetElement->to()->getStringOp(); + key = left->toString() + operand + right->toString(); + } + keyList.emplace(keyString, key); + } + IR::TCEntry *constEntry = new IR::TCEntry(e->action->toString(), keyList); + tabledef->addConstEntries(constEntry); + } +} + void ConvertToBackendIR::updateDefaultMissAction(const IR::P4Table *t, IR::TCTable *tabledef) { auto defaultAction = t->getDefaultAction(); if (defaultAction == nullptr || !defaultAction->is()) return; @@ -450,6 +509,7 @@ void ConvertToBackendIR::postorder(const IR::P4Table *t) { updateDefaultHitAction(t, tableDefinition); updateDefaultMissAction(t, tableDefinition); updateMatchType(t, tableDefinition); + updateConstEntries(t, tableDefinition); tcPipeline->addTableDefinition(tableDefinition); } } diff --git a/backends/tc/backend.h b/backends/tc/backend.h index ae6ff95cac..a53935f0b5 100644 --- a/backends/tc/backend.h +++ b/backends/tc/backend.h @@ -17,6 +17,8 @@ and limitations under the License. #ifndef BACKENDS_TC_BACKEND_H_ #define BACKENDS_TC_BACKEND_H_ +#include + #include "backends/ebpf/psa/ebpfPsaGen.h" #include "ebpfCodeGen.h" #include "frontends/p4/evaluator/evaluator.h" @@ -26,6 +28,7 @@ and limitations under the License. #include "ir/ir.h" #include "lib/error.h" #include "lib/nullstream.h" +#include "lib/stringify.h" #include "options.h" #include "pnaProgramStructure.h" #include "tcAnnotations.h" @@ -73,6 +76,7 @@ class ConvertToBackendIR : public Inspector { bool isDuplicateOrNoAction(const IR::P4Action *action); void updateDefaultHitAction(const IR::P4Table *t, IR::TCTable *tdef); void updateDefaultMissAction(const IR::P4Table *t, IR::TCTable *tdef); + void updateConstEntries(const IR::P4Table *t, IR::TCTable *tdef); void updateMatchType(const IR::P4Table *t, IR::TCTable *tabledef); bool isPnaParserMeta(const IR::Member *mem); bool isPnaMainInputMeta(const IR::Member *mem); diff --git a/backends/tc/tc.def b/backends/tc/tc.def index ad89cb25ed..460f1368d9 100644 --- a/backends/tc/tc.def +++ b/backends/tc/tc.def @@ -151,6 +151,22 @@ class TCAction { dbprint { out << toString(); } } +class TCEntry { + cstring action; + ordered_map keys; + cstring getActionName() const { + return action; + } + toString { + std::string tcEntry = ""; + for(auto k : keys) { + tcEntry += " " + k.first + " " + k.second; + } + return tcEntry; + } + dbprint { out << toString(); } +} + class TCTable { unsigned tableID; cstring tableName; @@ -167,6 +183,8 @@ class TCTable { TCAction defaultMissAction; bool isDefaultMissConst; ordered_map actionList; + safe_vector const_entries; + void setKeySize(unsigned k) { keySize = k; } @@ -200,6 +218,9 @@ class TCTable { void addAction(TCAction action, unsigned flag) { actionList.emplace(action, flag); } + void addConstEntries(TCEntry entry) { + const_entries.push_back(entry); + } cstring printMatchType(unsigned matchType) const { cstring matchTypeString = ""; switch(matchType) { @@ -288,6 +309,16 @@ class TCTable { } tcTable += " action " + defaultMissAction->getName(); } + if (const_entries.size() != 0) { + for (auto entry : const_entries) { + tcTable += "\n$TC p4template create table/" + pipelineName + + "/" + controlName + "/" + tableName + + " entry" + entry->toString(); + tcTable += " action " + pipelineName + + "/" + controlName + "/" + entry->getActionName(); + tcTable += " permissions 0x1024"; + } + } return tcTable; } dbprint { out << toString(); } diff --git a/lib/stringify.h b/lib/stringify.h index 82c1e65c73..04bff19611 100644 --- a/lib/stringify.h +++ b/lib/stringify.h @@ -83,5 +83,6 @@ cstring toString(const void *value); cstring printf_format(const char *fmt_str, ...); // vprintf into a string cstring vprintf_format(const char *fmt_str, va_list ap); +char DigitToChar(int digit); } // namespace Util #endif /* LIB_STRINGIFY_H_ */ diff --git a/testdata/p4tc_samples/calculator.p4 b/testdata/p4tc_samples/calculator.p4 new file mode 100644 index 0000000000..343cb17108 --- /dev/null +++ b/testdata/p4tc_samples/calculator.p4 @@ -0,0 +1,239 @@ +/* -*- P4_16 -*- */ + +/* + * P4 Calculator + * + * This program implements a simple protocol. It can be carried over Ethernet + * (Ethertype 0x1234). + * + * The Protocol header looks like this: + * + * 0 1 2 3 + * +----------------+----------------+----------------+---------------+ + * | P | 4 | Version | Op | + * +----------------+----------------+----------------+---------------+ + * | Operand A | + * +----------------+----------------+----------------+---------------+ + * | Operand B | + * +----------------+----------------+----------------+---------------+ + * | Result | + * +----------------+----------------+----------------+---------------+ + * + * P is an ASCII Letter 'P' (0x50) + * 4 is an ASCII Letter '4' (0x34) + * Version is currently 0.1 (0x01) + * Op is an operation to Perform: + * '+' (0x2b) Result = OperandA + OperandB + * '-' (0x2d) Result = OperandA - OperandB + * '&' (0x26) Result = OperandA & OperandB + * '|' (0x7c) Result = OperandA | OperandB + * '^' (0x5e) Result = OperandA ^ OperandB + * + * The device receives a packet, performs the requested operation, fills in the + * result and sends the packet back out of the same port it came in on, while + * swapping the source and destination addresses. + * + * If an unknown operation is specified or the header is not valid, the packet + * is dropped + */ + +#include +#include + + +/* + * Define the headers the program will recognize + */ + +/* + * Standard ethernet header + */ +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +/* + * This is a custom protocol header for the calculator. We'll use + * ethertype 0x1234 for is (see parser) + */ +const bit<16> P4CALC_ETYPE = 0x1234; +const bit<8> P4CALC_P = 0x50; // 'P' +const bit<8> P4CALC_4 = 0x34; // '4' +const bit<8> P4CALC_VER = 0x01; // v0.1 +const bit<8> P4CALC_PLUS = 0x2b; // '+' +const bit<8> P4CALC_MINUS = 0x2d; // '-' +const bit<8> P4CALC_AND = 0x26; // '&' +const bit<8> P4CALC_OR = 0x7c; // '|' +const bit<8> P4CALC_CARET = 0x5e; // '^' + +header p4calc_t { + bit<8> p; + bit<8> four; + bit<8> ver; + bit<8> op; + bit<32> operand_a; + bit<32> operand_b; + bit<32> res; +} + +/* + * All headers, used in the program needs to be assembed into a single struct. + * We only need to declare the type, but there is no need to instantiate it, + * because it is done "by the architecture", i.e. outside of P4 functions + */ +struct headers_t { + ethernet_t ethernet; + p4calc_t p4calc; +} + +/* + * All metadata, globally used in the program, also needs to be assembed + * into a single struct. As in the case of the headers, we only need to + * declare the type, but there is no need to instantiate it, + * because it is done "by the architecture", i.e. outside of P4 functions + */ + +struct metadata_t { + /* In our case it is empty */ +} + +/************************************************************************* + *********************** P A R S E R *********************************** + *************************************************************************/ +parser MainParserImpl( + packet_in pkt, + out headers_t hdr, + inout metadata_t meta, + in pna_main_parser_input_metadata_t istd) +{ + + state start { + pkt.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + P4CALC_ETYPE : check_p4calc; + default : accept; + } + } + + state check_p4calc { + transition select(pkt.lookahead().p, + pkt.lookahead().four, + pkt.lookahead().ver) { + (P4CALC_P, P4CALC_4, P4CALC_VER) : parse_p4calc; + default : accept; + } + } + + state parse_p4calc { + pkt.extract(hdr.p4calc); + transition accept; + } +} + + +/************************************************************************* + ********************** M A I N C O N T R O L ************************ + *************************************************************************/ +control MainControlImpl( + inout headers_t hdr, + inout metadata_t meta, + in pna_main_input_metadata_t istd, + inout pna_main_output_metadata_t ostd) +{ + + action send_back(bit<32> result) { + bit<48> tmp; + + /* Put the result back in */ + hdr.p4calc.res = result; + + /* Swap the MAC addresses */ + tmp = hdr.ethernet.dstAddr; + hdr.ethernet.dstAddr = hdr.ethernet.srcAddr; + hdr.ethernet.srcAddr = tmp; + /* Send the packet back to the port it came from */ + send_to_port(istd.input_port); + } + + action operation_add() { + send_back(hdr.p4calc.operand_a + hdr.p4calc.operand_b); + } + + action operation_sub() { + send_back(hdr.p4calc.operand_a - hdr.p4calc.operand_b); + } + + action operation_and() { + send_back(hdr.p4calc.operand_a & hdr.p4calc.operand_b); + } + + action operation_or() { + send_back(hdr.p4calc.operand_a | hdr.p4calc.operand_b); + } + + action operation_xor() { + send_back(hdr.p4calc.operand_a ^ hdr.p4calc.operand_b); + } + + action operation_drop() { + drop_packet(); + } + + table calculate { + key = { + hdr.p4calc.op : exact @name("op"); + } + actions = { + operation_add; + operation_sub; + operation_and; + operation_or; + operation_xor; + operation_drop; + } + const default_action = operation_drop(); + const entries = { + P4CALC_PLUS : operation_add(); + P4CALC_MINUS: operation_sub(); + P4CALC_AND : operation_and(); + P4CALC_OR : operation_or(); + P4CALC_CARET: operation_xor(); + } + } + + + apply { + if (hdr.p4calc.isValid()) { + calculate.apply(); + } else { + operation_drop(); + } + } +} + + +/************************************************************************* + *********************** D E P A R S E R ******************************* + *************************************************************************/ +control MainDeparserImpl( + packet_out pkt, + inout headers_t hdr, + in metadata_t meta, + in pna_main_output_metadata_t ostd) +{ + apply { + pkt.emit(hdr.ethernet); + pkt.emit(hdr.p4calc); + } +} + +/************************************************************************* + ****************************** P N A ********************************** + *************************************************************************/ +PNA_NIC( + MainParserImpl(), + MainControlImpl(), + MainDeparserImpl() + ) main; \ No newline at end of file diff --git a/testdata/p4tc_samples/const_entries_range_mask.p4 b/testdata/p4tc_samples/const_entries_range_mask.p4 new file mode 100644 index 0000000000..2d9ba45eae --- /dev/null +++ b/testdata/p4tc_samples/const_entries_range_mask.p4 @@ -0,0 +1,75 @@ +#include +#include + +header hdr { + bit<8> e; + bit<16> t; + bit<8> l; + bit<8> r; + bit<8> v; +} + +struct Header_t { + hdr h; +} +struct Meta_t {} + +parser MainParserImpl(packet_in b, out Header_t h, inout Meta_t m, in pna_main_parser_input_metadata_t istd) { + state start { + b.extract(h.h); + transition accept; + } +} + +control MainControlImpl(inout Header_t h, inout Meta_t m, + in pna_main_input_metadata_t istd, + inout pna_main_output_metadata_t ostd) { + + action a() { h.h.e = 0; } + action a_with_control_params(bit<16> x) { h.h.t = x; } + + table t_range { + + key = { + h.h.r : range; + } + + actions = { + a; + a_with_control_params; + } + + default_action = a; + + const entries = { + 1 : a_with_control_params(21); + 6: a_with_control_params(22); + 15 : a_with_control_params(24); + 1..8 : a_with_control_params(23); + 1 &&& 2 : a_with_control_params(26); + } + } + + apply { + t_range.apply(); + } +} + +/********************* D E P A R S E R ************************/ + +control MainDeparserImpl( + packet_out b, inout Header_t h, in Meta_t m, in pna_main_output_metadata_t ostd) +{ + apply {} +} + +/************ F I N A L P A C K A G E ******************************/ + + +// BEGIN:Package_Instantiation_Example +PNA_NIC( + MainParserImpl(), + MainControlImpl(), + MainDeparserImpl() + ) main; +// END:Package_Instantiation_Example diff --git a/testdata/p4tc_samples_outputs/calculator.json b/testdata/p4tc_samples_outputs/calculator.json new file mode 100644 index 0000000000..b0a1e3ab11 --- /dev/null +++ b/testdata/p4tc_samples_outputs/calculator.json @@ -0,0 +1,79 @@ +{ + "schema_version" : "1.0.0", + "pipeline_name" : "calculator", + "id" : 1, + "tables" : [ + { + "name" : "MainControlImpl/calculate", + "id" : 1, + "tentries" : 2048, + "nummask" : 8, + "keysize" : 8, + "keyfields" : [ + { + "id" : 1, + "name" : "op", + "type" : "bit8", + "match_type" : "exact", + "bitwidth" : 8 + } + ], + "actions" : [ + { + "id" : 1, + "name" : "MainControlImpl/operation_add", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [], + "default_hit_action" : false, + "default_miss_action" : false + }, + { + "id" : 2, + "name" : "MainControlImpl/operation_sub", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [], + "default_hit_action" : false, + "default_miss_action" : false + }, + { + "id" : 3, + "name" : "MainControlImpl/operation_and", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [], + "default_hit_action" : false, + "default_miss_action" : false + }, + { + "id" : 4, + "name" : "MainControlImpl/operation_or", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [], + "default_hit_action" : false, + "default_miss_action" : false + }, + { + "id" : 5, + "name" : "MainControlImpl/operation_xor", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [], + "default_hit_action" : false, + "default_miss_action" : false + }, + { + "id" : 6, + "name" : "MainControlImpl/operation_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/calculator.p4-stderr b/testdata/p4tc_samples_outputs/calculator.p4-stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/testdata/p4tc_samples_outputs/calculator.template b/testdata/p4tc_samples_outputs/calculator.template new file mode 100755 index 0000000000..b9ec986fff --- /dev/null +++ b/testdata/p4tc_samples_outputs/calculator.template @@ -0,0 +1,42 @@ +#!/bin/bash -x + +set -e + +TC="tc" +$TC p4template create pipeline/calculator pipeid 1 numtables 1 + +$TC p4template create action/calculator/MainControlImpl/operation_add actid 1 +$TC p4template update action/calculator/MainControlImpl/operation_add state active + +$TC p4template create action/calculator/MainControlImpl/operation_sub actid 2 +$TC p4template update action/calculator/MainControlImpl/operation_sub state active + +$TC p4template create action/calculator/MainControlImpl/operation_and actid 3 +$TC p4template update action/calculator/MainControlImpl/operation_and state active + +$TC p4template create action/calculator/MainControlImpl/operation_or actid 4 +$TC p4template update action/calculator/MainControlImpl/operation_or state active + +$TC p4template create action/calculator/MainControlImpl/operation_xor actid 5 +$TC p4template update action/calculator/MainControlImpl/operation_xor state active + +$TC p4template create action/calculator/MainControlImpl/operation_drop actid 6 +$TC p4template update action/calculator/MainControlImpl/operation_drop state active + +$TC p4template create table/calculator/MainControlImpl/calculate \ + tblid 1 \ + type exact \ + keysz 8 nummasks 8 tentries 2048 \ + table_acts act name calculator/MainControlImpl/operation_add \ + act name calculator/MainControlImpl/operation_sub \ + act name calculator/MainControlImpl/operation_and \ + act name calculator/MainControlImpl/operation_or \ + act name calculator/MainControlImpl/operation_xor \ + act name calculator/MainControlImpl/operation_drop +$TC p4template update table/calculator/MainControlImpl/calculate default_miss_action permissions 0x1024 action calculator/MainControlImpl/operation_drop +$TC p4template create table/calculator/MainControlImpl/calculate entry op 2b action calculator/MainControlImpl/operation_add permissions 0x1024 +$TC p4template create table/calculator/MainControlImpl/calculate entry op 2d action calculator/MainControlImpl/operation_sub permissions 0x1024 +$TC p4template create table/calculator/MainControlImpl/calculate entry op 26 action calculator/MainControlImpl/operation_and permissions 0x1024 +$TC p4template create table/calculator/MainControlImpl/calculate entry op 7c action calculator/MainControlImpl/operation_or permissions 0x1024 +$TC p4template create table/calculator/MainControlImpl/calculate entry op 5e action calculator/MainControlImpl/operation_xor permissions 0x1024 +$TC p4template update pipeline/calculator state ready \ No newline at end of file diff --git a/testdata/p4tc_samples_outputs/calculator_control_blocks.c b/testdata/p4tc_samples_outputs/calculator_control_blocks.c new file mode 100644 index 0000000000..657f2ab4cf --- /dev/null +++ b/testdata/p4tc_samples_outputs/calculator_control_blocks.c @@ -0,0 +1,360 @@ +#include "calculator_parser.h" +struct internal_metadata { + __u16 pkt_ether_type; +} __attribute__((aligned(4))); + +struct __attribute__((__packed__)) MainControlImpl_calculate_key { + u32 keysz; + u32 maskid; + u8 field0; /* hdr.p4calc.op */ +} __attribute__((aligned(4))); +#define MAINCONTROLIMPL_CALCULATE_ACT_MAINCONTROLIMPL_OPERATION_ADD 1 +#define MAINCONTROLIMPL_CALCULATE_ACT_MAINCONTROLIMPL_OPERATION_SUB 2 +#define MAINCONTROLIMPL_CALCULATE_ACT_MAINCONTROLIMPL_OPERATION_AND 3 +#define MAINCONTROLIMPL_CALCULATE_ACT_MAINCONTROLIMPL_OPERATION_OR 4 +#define MAINCONTROLIMPL_CALCULATE_ACT_MAINCONTROLIMPL_OPERATION_XOR 5 +#define MAINCONTROLIMPL_CALCULATE_ACT_MAINCONTROLIMPL_OPERATION_DROP 6 +struct __attribute__((__packed__)) MainControlImpl_calculate_value { + unsigned int action; + union { + struct { + } _NoAction; + struct { + } MainControlImpl_operation_add; + struct { + } MainControlImpl_operation_sub; + struct { + } MainControlImpl_operation_and; + struct { + } MainControlImpl_operation_or; + struct { + } MainControlImpl_operation_xor; + struct { + } MainControlImpl_operation_drop; + } u; +}; + +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() + +SEC("xdp/xdp-ingress") +int xdp_func(struct xdp_md *skb) { + void *data_end = (void *)(long)skb->data_end; + struct ethhdr *eth = (struct ethhdr *)(long)skb->data; + if ((void *)((struct ethhdr *) eth + 1) > data_end) { + return XDP_ABORTED; + } + if (eth->h_proto == bpf_htons(0x0800) || eth->h_proto == bpf_htons(0x86DD)) { + return XDP_PASS; + } + + struct internal_metadata *meta; + int ret = bpf_xdp_adjust_meta(skb, -(int)sizeof(*meta)); + if (ret < 0) { + return XDP_ABORTED; + } + meta = (struct internal_metadata *)(unsigned long)skb->data_meta; + eth = (void *)(long)skb->data; + data_end = (void *)(long)skb->data_end; + if ((void *) ((struct internal_metadata *) meta + 1) > (void *)(long)skb->data) + return XDP_ABORTED; + if ((void *)((struct ethhdr *) eth + 1) > data_end) { + return XDP_ABORTED; + } + meta->pkt_ether_type = eth->h_proto; + eth->h_proto = bpf_htons(0x0800); + + return XDP_PASS; +} +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); + 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 metadata_t *meta; + hdrMd = BPF_MAP_LOOKUP_ELEM(hdr_md_cpumap, &ebpf_zero); + if (!hdrMd) + return TC_ACT_SHOT; + unsigned ebpf_packetOffsetInBits = hdrMd->ebpf_packetOffsetInBits; + hdr = &(hdrMd->cpumap_hdr); + meta = &(hdrMd->cpumap_usermeta); +{ + u8 hit; + u64 tmp_5 = 0; + { +if (/* hdr->p4calc.isValid() */ + hdr->p4calc.ebpf_valid) { +/* calculate_0.apply() */ + { + /* construct key */ + struct p4tc_table_entry_act_bpf_params__local params = { + .pipeid = 1, + .tblid = 1 + }; + struct MainControlImpl_calculate_key key = {}; + key.keysz = 8; + key.field0 = hdr->p4calc.op; + struct p4tc_table_entry_act_bpf *act_bpf; + /* value */ + struct MainControlImpl_calculate_value *value = NULL; + /* perform lookup */ + act_bpf = bpf_p4tc_tbl_read(skb, ¶ms, &key, sizeof(key)); + value = (struct MainControlImpl_calculate_value *)act_bpf; + if (value == NULL) { + /* miss; find default action */ + hit = 0; + } else { + hit = 1; + } + if (value != NULL) { + /* run action */ + switch (value->action) { + case MAINCONTROLIMPL_CALCULATE_ACT_MAINCONTROLIMPL_OPERATION_ADD: + { + hdr->p4calc.res = (hdr->p4calc.operand_a + hdr->p4calc.operand_b); + tmp_5 = hdr->ethernet.dstAddr; + hdr->ethernet.dstAddr = hdr->ethernet.srcAddr; + hdr->ethernet.srcAddr = tmp_5; + /* send_to_port(istd.input_port) */ + compiler_meta__->drop = false; + send_to_port(skb->ifindex); + } + break; + case MAINCONTROLIMPL_CALCULATE_ACT_MAINCONTROLIMPL_OPERATION_SUB: + { + hdr->p4calc.res = (hdr->p4calc.operand_a - hdr->p4calc.operand_b); + tmp_5 = hdr->ethernet.dstAddr; + hdr->ethernet.dstAddr = hdr->ethernet.srcAddr; + hdr->ethernet.srcAddr = tmp_5; + /* send_to_port(istd.input_port) */ + compiler_meta__->drop = false; + send_to_port(skb->ifindex); + } + break; + case MAINCONTROLIMPL_CALCULATE_ACT_MAINCONTROLIMPL_OPERATION_AND: + { + hdr->p4calc.res = (hdr->p4calc.operand_a & hdr->p4calc.operand_b); + tmp_5 = hdr->ethernet.dstAddr; + hdr->ethernet.dstAddr = hdr->ethernet.srcAddr; + hdr->ethernet.srcAddr = tmp_5; + /* send_to_port(istd.input_port) */ + compiler_meta__->drop = false; + send_to_port(skb->ifindex); + } + break; + case MAINCONTROLIMPL_CALCULATE_ACT_MAINCONTROLIMPL_OPERATION_OR: + { + hdr->p4calc.res = (hdr->p4calc.operand_a | hdr->p4calc.operand_b); + tmp_5 = hdr->ethernet.dstAddr; + hdr->ethernet.dstAddr = hdr->ethernet.srcAddr; + hdr->ethernet.srcAddr = tmp_5; + /* send_to_port(istd.input_port) */ + compiler_meta__->drop = false; + send_to_port(skb->ifindex); + } + break; + case MAINCONTROLIMPL_CALCULATE_ACT_MAINCONTROLIMPL_OPERATION_XOR: + { + hdr->p4calc.res = (hdr->p4calc.operand_a ^ hdr->p4calc.operand_b); + tmp_5 = hdr->ethernet.dstAddr; + hdr->ethernet.dstAddr = hdr->ethernet.srcAddr; + hdr->ethernet.srcAddr = tmp_5; + /* send_to_port(istd.input_port) */ + compiler_meta__->drop = false; + send_to_port(skb->ifindex); + } + break; + case MAINCONTROLIMPL_CALCULATE_ACT_MAINCONTROLIMPL_OPERATION_DROP: + { +/* drop_packet() */ + drop_packet(); + } + break; + default: + return TC_ACT_SHOT; + } + } else { +/* drop_packet() */ + drop_packet(); + } + } +; } + + else { +/* operation_drop_1() */ +{ +/* drop_packet() */ + drop_packet(); + }; } + + } + } + { +{ +; + ; + } + + if (compiler_meta__->drop) { + return TC_ACT_SHOT; + } + int outHeaderLength = 0; + if (hdr->ethernet.ebpf_valid) { + outHeaderLength += 112; + } +; if (hdr->p4calc.ebpf_valid) { + outHeaderLength += 128; + } +; + int outHeaderOffset = BYTES(outHeaderLength) - BYTES(ebpf_packetOffsetInBits); + 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->p4calc.ebpf_valid) { + if (ebpf_packetEnd < pkt + BYTES(ebpf_packetOffsetInBits + 128)) { + return TC_ACT_SHOT; + } + + ebpf_byte = ((char*)(&hdr->p4calc.p))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_packetOffsetInBits += 8; + + ebpf_byte = ((char*)(&hdr->p4calc.four))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_packetOffsetInBits += 8; + + ebpf_byte = ((char*)(&hdr->p4calc.ver))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_packetOffsetInBits += 8; + + ebpf_byte = ((char*)(&hdr->p4calc.op))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_packetOffsetInBits += 8; + + hdr->p4calc.operand_a = htonl(hdr->p4calc.operand_a); + ebpf_byte = ((char*)(&hdr->p4calc.operand_a))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->p4calc.operand_a))[1]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 1, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->p4calc.operand_a))[2]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 2, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->p4calc.operand_a))[3]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 3, (ebpf_byte)); + ebpf_packetOffsetInBits += 32; + + hdr->p4calc.operand_b = htonl(hdr->p4calc.operand_b); + ebpf_byte = ((char*)(&hdr->p4calc.operand_b))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->p4calc.operand_b))[1]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 1, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->p4calc.operand_b))[2]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 2, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->p4calc.operand_b))[3]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 3, (ebpf_byte)); + ebpf_packetOffsetInBits += 32; + + hdr->p4calc.res = htonl(hdr->p4calc.res); + ebpf_byte = ((char*)(&hdr->p4calc.res))[0]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->p4calc.res))[1]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 1, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->p4calc.res))[2]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 2, (ebpf_byte)); + ebpf_byte = ((char*)(&hdr->p4calc.res))[3]; + write_byte(pkt, BYTES(ebpf_packetOffsetInBits) + 3, (ebpf_byte)); + ebpf_packetOffsetInBits += 32; + + } +; + } + return -1; +} +SEC("classifier/tc-ingress") +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/calculator_parser.c b/testdata/p4tc_samples_outputs/calculator_parser.c new file mode 100644 index 0000000000..216e3157af --- /dev/null +++ b/testdata/p4tc_samples_outputs/calculator_parser.c @@ -0,0 +1,224 @@ +#include "calculator_parser.h" + +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 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); + 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 metadata_t *meta; + + hdrMd = BPF_MAP_LOOKUP_ELEM(hdr_md_cpumap, &ebpf_zero); + if (!hdrMd) + return TC_ACT_SHOT; + __builtin_memset(hdrMd, 0, sizeof(struct hdr_md)); + + unsigned ebpf_packetOffsetInBits = 0; + hdr = &(hdrMd->cpumap_hdr); + meta = &(hdrMd->cpumap_usermeta); + { + struct p4calc_t tmp_0; + struct p4calc_t tmp_2; + struct p4calc_t tmp_4; + goto start; + check_p4calc: { + { + ebpf_packetOffsetInBits_save = ebpf_packetOffsetInBits; + if (ebpf_packetEnd < pkt + BYTES(ebpf_packetOffsetInBits + 128 + 0)) { + ebpf_errorCode = PacketTooShort; + goto reject; + } + + tmp_0.p = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + tmp_0.four = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + tmp_0.ver = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + tmp_0.op = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + tmp_0.operand_a = (u32)((load_word(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 32; + + tmp_0.operand_b = (u32)((load_word(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 32; + + tmp_0.res = (u32)((load_word(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 32; + + tmp_0.ebpf_valid = 1; + + ebpf_packetOffsetInBits = ebpf_packetOffsetInBits_save; + } + { + ebpf_packetOffsetInBits_save = ebpf_packetOffsetInBits; + if (ebpf_packetEnd < pkt + BYTES(ebpf_packetOffsetInBits + 128 + 0)) { + ebpf_errorCode = PacketTooShort; + goto reject; + } + + tmp_2.p = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + tmp_2.four = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + tmp_2.ver = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + tmp_2.op = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + tmp_2.operand_a = (u32)((load_word(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 32; + + tmp_2.operand_b = (u32)((load_word(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 32; + + tmp_2.res = (u32)((load_word(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 32; + + tmp_2.ebpf_valid = 1; + + ebpf_packetOffsetInBits = ebpf_packetOffsetInBits_save; + } + { + ebpf_packetOffsetInBits_save = ebpf_packetOffsetInBits; + if (ebpf_packetEnd < pkt + BYTES(ebpf_packetOffsetInBits + 128 + 0)) { + ebpf_errorCode = PacketTooShort; + goto reject; + } + + tmp_4.p = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + tmp_4.four = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + tmp_4.ver = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + tmp_4.op = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + tmp_4.operand_a = (u32)((load_word(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 32; + + tmp_4.operand_b = (u32)((load_word(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 32; + + tmp_4.res = (u32)((load_word(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 32; + + tmp_4.ebpf_valid = 1; + + ebpf_packetOffsetInBits = ebpf_packetOffsetInBits_save; + } + u32 select_0; + select_0 = (((((u32)(((u16)tmp_0.p << 8) | ((u16)tmp_2.four & 0xff)) << 8) & ((1 << 24) - 1)) | (((u32)tmp_4.ver & 0xff) & ((1 << 24) - 1))) & ((1 << 24) - 1)); + if (select_0 == 0x503401)goto parse_p4calc; + if ((select_0 & 0x0) == (0x0 & 0x0))goto accept; + else goto reject; + } + parse_p4calc: { +/* extract(hdr->p4calc) */ + if (ebpf_packetEnd < pkt + BYTES(ebpf_packetOffsetInBits + 128 + 0)) { + ebpf_errorCode = PacketTooShort; + goto reject; + } + + hdr->p4calc.p = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + hdr->p4calc.four = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + hdr->p4calc.ver = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + hdr->p4calc.op = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + hdr->p4calc.operand_a = (u32)((load_word(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 32; + + hdr->p4calc.operand_b = (u32)((load_word(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 32; + + hdr->p4calc.res = (u32)((load_word(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 32; + + hdr->p4calc.ebpf_valid = 1; + +; + goto accept; + } + start: { +/* extract(hdr->ethernet) */ + if (ebpf_packetEnd < pkt + BYTES(ebpf_packetOffsetInBits + 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; + +; + u16 select_1; + select_1 = hdr->ethernet.etherType; + if (select_1 == 0x1234)goto check_p4calc; + if ((select_1 & 0x0) == (0x0 & 0x0))goto accept; + else goto reject; + } + + reject: { + if (ebpf_errorCode == 0) { + return TC_ACT_SHOT; + } + goto accept; + } + + } + + accept: + hdrMd->ebpf_packetOffsetInBits = ebpf_packetOffsetInBits; + return -1; +} + +SEC("classifier/tc-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/calculator_parser.h b/testdata/p4tc_samples_outputs/calculator_parser.h new file mode 100644 index 0000000000..9adb56182d --- /dev/null +++ b/testdata/p4tc_samples_outputs/calculator_parser.h @@ -0,0 +1,43 @@ +#include "ebpf_kernel.h" + +#include +#include +#include "pna.h" + +#define EBPF_MASK(t, w) ((((t)(1)) << (w)) - (t)1) +#define BYTES(w) ((w) / 8) +#define write_partial(a, w, s, v) do { *((u8*)a) = ((*((u8*)a)) & ~(EBPF_MASK(u8, w) << s)) | (v << s) ; } while (0) +#define write_byte(base, offset, v) do { *(u8*)((base) + (offset)) = (v); } while (0) +#define bpf_trace_message(fmt, ...) + + +struct ethernet_t { + u64 dstAddr; /* bit<48> */ + u64 srcAddr; /* bit<48> */ + u16 etherType; /* bit<16> */ + u8 ebpf_valid; +}; +struct p4calc_t { + u8 p; /* bit<8> */ + u8 four; /* bit<8> */ + u8 ver; /* bit<8> */ + u8 op; /* bit<8> */ + u32 operand_a; /* bit<32> */ + u32 operand_b; /* bit<32> */ + u32 res; /* bit<32> */ + u8 ebpf_valid; +}; +struct headers_t { + struct ethernet_t ethernet; /* ethernet_t */ + struct p4calc_t p4calc; /* p4calc_t */ +}; +struct metadata_t { +}; + +struct hdr_md { + struct headers_t cpumap_hdr; + struct metadata_t cpumap_usermeta; + unsigned ebpf_packetOffsetInBits; + __u8 __hook; +}; + diff --git a/testdata/p4tc_samples_outputs/const_entries_range_mask.json b/testdata/p4tc_samples_outputs/const_entries_range_mask.json new file mode 100644 index 0000000000..6ee18aa6c7 --- /dev/null +++ b/testdata/p4tc_samples_outputs/const_entries_range_mask.json @@ -0,0 +1,50 @@ +{ + "schema_version" : "1.0.0", + "pipeline_name" : "const_entries_range_mask", + "id" : 1, + "tables" : [ + { + "name" : "MainControlImpl/t_range", + "id" : 1, + "tentries" : 2048, + "nummask" : 8, + "keysize" : 8, + "keyfields" : [ + { + "id" : 1, + "name" : "h.h.r", + "type" : "bit8", + "match_type" : "range", + "bitwidth" : 8 + } + ], + "actions" : [ + { + "id" : 1, + "name" : "MainControlImpl/a", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [], + "default_hit_action" : false, + "default_miss_action" : true + }, + { + "id" : 2, + "name" : "MainControlImpl/a_with_control_params", + "action_scope" : "TableAndDefault", + "annotations" : [], + "params" : [ + { + "id" : 1, + "name" : "x", + "type" : "bit16", + "bitwidth" : 16 + } + ], + "default_hit_action" : false, + "default_miss_action" : false + } + ] + } + ] +} \ No newline at end of file diff --git a/testdata/p4tc_samples_outputs/const_entries_range_mask.p4-stderr b/testdata/p4tc_samples_outputs/const_entries_range_mask.p4-stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/testdata/p4tc_samples_outputs/const_entries_range_mask.template b/testdata/p4tc_samples_outputs/const_entries_range_mask.template new file mode 100755 index 0000000000..ed9e47ce53 --- /dev/null +++ b/testdata/p4tc_samples_outputs/const_entries_range_mask.template @@ -0,0 +1,27 @@ +#!/bin/bash -x + +set -e + +TC="tc" +$TC p4template create pipeline/const_entries_range_mask pipeid 1 numtables 1 + +$TC p4template create action/const_entries_range_mask/MainControlImpl/a actid 1 +$TC p4template update action/const_entries_range_mask/MainControlImpl/a state active + +$TC p4template create action/const_entries_range_mask/MainControlImpl/a_with_control_params actid 2 \ + param x type bit16 +$TC p4template update action/const_entries_range_mask/MainControlImpl/a_with_control_params state active + +$TC p4template create table/const_entries_range_mask/MainControlImpl/t_range \ + tblid 1 \ + type ternary \ + keysz 8 nummasks 8 tentries 2048 \ + table_acts act name const_entries_range_mask/MainControlImpl/a \ + act name const_entries_range_mask/MainControlImpl/a_with_control_params +$TC p4template update table/const_entries_range_mask/MainControlImpl/t_range default_miss_action action const_entries_range_mask/MainControlImpl/a +$TC p4template create table/const_entries_range_mask/MainControlImpl/t_range entry h.h.r 1 action const_entries_range_mask/MainControlImpl/a_with_control_params permissions 0x1024 +$TC p4template create table/const_entries_range_mask/MainControlImpl/t_range entry h.h.r 6 action const_entries_range_mask/MainControlImpl/a_with_control_params permissions 0x1024 +$TC p4template create table/const_entries_range_mask/MainControlImpl/t_range entry h.h.r 15 action const_entries_range_mask/MainControlImpl/a_with_control_params permissions 0x1024 +$TC p4template create table/const_entries_range_mask/MainControlImpl/t_range entry h.h.r 8w1..8w8 action const_entries_range_mask/MainControlImpl/a_with_control_params permissions 0x1024 +$TC p4template create table/const_entries_range_mask/MainControlImpl/t_range entry h.h.r 8w1&&&8w2 action const_entries_range_mask/MainControlImpl/a_with_control_params permissions 0x1024 +$TC p4template update pipeline/const_entries_range_mask state ready \ No newline at end of file diff --git a/testdata/p4tc_samples_outputs/const_entries_range_mask_control_blocks.c b/testdata/p4tc_samples_outputs/const_entries_range_mask_control_blocks.c new file mode 100644 index 0000000000..21e7fdd4c0 --- /dev/null +++ b/testdata/p4tc_samples_outputs/const_entries_range_mask_control_blocks.c @@ -0,0 +1,180 @@ +#include "const_entries_range_mask_parser.h" +struct internal_metadata { + __u16 pkt_ether_type; +} __attribute__((aligned(4))); + +struct __attribute__((__packed__)) MainControlImpl_t_range_key { + u32 keysz; + u32 maskid; + u8 field0; /* h.h.r */ +} __attribute__((aligned(4))); +#define MAINCONTROLIMPL_T_RANGE_ACT_MAINCONTROLIMPL_A 1 +#define MAINCONTROLIMPL_T_RANGE_ACT_MAINCONTROLIMPL_A_WITH_CONTROL_PARAMS 2 +struct __attribute__((__packed__)) MainControlImpl_t_range_value { + unsigned int action; + union { + struct { + } _NoAction; + struct { + } MainControlImpl_a; + struct __attribute__((__packed__)) { + u16 x; + } MainControlImpl_a_with_control_params; + } u; +}; + +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() + +SEC("xdp/xdp-ingress") +int xdp_func(struct xdp_md *skb) { + void *data_end = (void *)(long)skb->data_end; + struct ethhdr *eth = (struct ethhdr *)(long)skb->data; + if ((void *)((struct ethhdr *) eth + 1) > data_end) { + return XDP_ABORTED; + } + if (eth->h_proto == bpf_htons(0x0800) || eth->h_proto == bpf_htons(0x86DD)) { + return XDP_PASS; + } + + struct internal_metadata *meta; + int ret = bpf_xdp_adjust_meta(skb, -(int)sizeof(*meta)); + if (ret < 0) { + return XDP_ABORTED; + } + meta = (struct internal_metadata *)(unsigned long)skb->data_meta; + eth = (void *)(long)skb->data; + data_end = (void *)(long)skb->data_end; + if ((void *) ((struct internal_metadata *) meta + 1) > (void *)(long)skb->data) + return XDP_ABORTED; + if ((void *)((struct ethhdr *) eth + 1) > data_end) { + return XDP_ABORTED; + } + meta->pkt_ether_type = eth->h_proto; + eth->h_proto = bpf_htons(0x0800); + + return XDP_PASS; +} +static __always_inline int process(struct __sk_buff *skb, struct Header_t *h, 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); + 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 Meta_t *m; + hdrMd = BPF_MAP_LOOKUP_ELEM(hdr_md_cpumap, &ebpf_zero); + if (!hdrMd) + return TC_ACT_SHOT; + unsigned ebpf_packetOffsetInBits = hdrMd->ebpf_packetOffsetInBits; + h = &(hdrMd->cpumap_hdr); + m = &(hdrMd->cpumap_usermeta); +{ + u8 hit; + { +/* t_range_0.apply() */ + { + /* construct key */ + struct p4tc_table_entry_act_bpf_params__local params = { + .pipeid = 1, + .tblid = 1 + }; + struct MainControlImpl_t_range_key key = {}; + key.keysz = 8; + key.field0 = h->h.r; + struct p4tc_table_entry_act_bpf *act_bpf; + /* value */ + struct MainControlImpl_t_range_value *value = NULL; + /* perform lookup */ + act_bpf = bpf_p4tc_tbl_read(skb, ¶ms, &key, sizeof(key)); + value = (struct MainControlImpl_t_range_value *)act_bpf; + if (value == NULL) { + /* miss; find default action */ + hit = 0; + } else { + hit = 1; + } + if (value != NULL) { + /* run action */ + switch (value->action) { + case MAINCONTROLIMPL_T_RANGE_ACT_MAINCONTROLIMPL_A: + { + h->h.e = 0; + } + break; + case MAINCONTROLIMPL_T_RANGE_ACT_MAINCONTROLIMPL_A_WITH_CONTROL_PARAMS: + { + h->h.t = value->u.MainControlImpl_a_with_control_params.x; + } + break; + default: + return TC_ACT_SHOT; + } + } else { + h->h.e = 0; + } + } +; + } + } + { +{ + } + + if (compiler_meta__->drop) { + return TC_ACT_SHOT; + } + int outHeaderLength = 0; + + int outHeaderOffset = BYTES(outHeaderLength) - BYTES(ebpf_packetOffsetInBits); + 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; + + } + return -1; +} +SEC("classifier/tc-ingress") +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 Header_t *h; + int ret = -1; + ret = process(skb, (struct Header_t *) h, 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/const_entries_range_mask_parser.c b/testdata/p4tc_samples_outputs/const_entries_range_mask_parser.c new file mode 100644 index 0000000000..dcf14bb85a --- /dev/null +++ b/testdata/p4tc_samples_outputs/const_entries_range_mask_parser.c @@ -0,0 +1,87 @@ +#include "const_entries_range_mask_parser.h" + +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 int run_parser(struct __sk_buff *skb, struct Header_t *h, 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); + 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 Meta_t *m; + + 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; + h = &(hdrMd->cpumap_hdr); + m = &(hdrMd->cpumap_usermeta); + { + goto start; + start: { +/* extract(h->h) */ + if (ebpf_packetEnd < pkt + BYTES(ebpf_packetOffsetInBits + 48 + 0)) { + ebpf_errorCode = PacketTooShort; + goto reject; + } + + h->h.e = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + h->h.t = (u16)((load_half(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 16; + + h->h.l = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + h->h.r = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + h->h.v = (u8)((load_byte(pkt, BYTES(ebpf_packetOffsetInBits)))); + ebpf_packetOffsetInBits += 8; + + h->h.ebpf_valid = 1; + +; + goto accept; + } + + reject: { + if (ebpf_errorCode == 0) { + return TC_ACT_SHOT; + } + goto accept; + } + + } + + accept: + hdrMd->ebpf_packetOffsetInBits = ebpf_packetOffsetInBits; + return -1; +} + +SEC("classifier/tc-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 Header_t *h; + int ret = -1; + ret = run_parser(skb, (struct Header_t *) h, compiler_meta__); + if (ret != -1) { + return ret; + } + return TC_ACT_PIPE; + } +char _license[] SEC("license") = "GPL"; diff --git a/testdata/p4tc_samples_outputs/const_entries_range_mask_parser.h b/testdata/p4tc_samples_outputs/const_entries_range_mask_parser.h new file mode 100644 index 0000000000..a3e52c3362 --- /dev/null +++ b/testdata/p4tc_samples_outputs/const_entries_range_mask_parser.h @@ -0,0 +1,34 @@ +#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 hdr { + u8 e; /* bit<8> */ + u16 t; /* bit<16> */ + u8 l; /* bit<8> */ + u8 r; /* bit<8> */ + u8 v; /* bit<8> */ + u8 ebpf_valid; +}; +struct Header_t { + struct hdr h; /* hdr */ +}; +struct Meta_t { +}; + +struct hdr_md { + struct Header_t cpumap_hdr; + struct Meta_t cpumap_usermeta; + unsigned ebpf_packetOffsetInBits; + __u8 __hook; +}; + diff --git a/testdata/p4tc_samples_outputs/multiple_tables_example_01.template b/testdata/p4tc_samples_outputs/multiple_tables_example_01.template index ebb74f4ca5..1ad95743ff 100644 --- a/testdata/p4tc_samples_outputs/multiple_tables_example_01.template +++ b/testdata/p4tc_samples_outputs/multiple_tables_example_01.template @@ -84,4 +84,10 @@ $TC p4template create table/multiple_tables_example_01/MainControlImpl/set_all_o act name multiple_tables_example_01/MainControlImpl/sendtoport \ act name multiple_tables_example_01/MainControlImpl/drop $TC p4template update table/multiple_tables_example_01/MainControlImpl/set_all_options default_miss_action permissions 0x1024 action multiple_tables_example_01/MainControlImpl/drop +$TC p4template create table/multiple_tables_example_01/MainControlImpl/set_all_options entry hdr.ipv4.srcAddr 1000 hdr.tcp.srcPort 10 hdr.ipv4.fragOffset 10 hdr.ipv4.flags 1 action multiple_tables_example_01/MainControlImpl/tcp_syn_packet permissions 0x1024 +$TC p4template create table/multiple_tables_example_01/MainControlImpl/set_all_options entry hdr.ipv4.srcAddr 2000 hdr.tcp.srcPort 20 hdr.ipv4.fragOffset 20 hdr.ipv4.flags 2 action multiple_tables_example_01/MainControlImpl/tcp_fin_or_rst_packet permissions 0x1024 +$TC p4template create table/multiple_tables_example_01/MainControlImpl/set_all_options entry hdr.ipv4.srcAddr 3000 hdr.tcp.srcPort 30 hdr.ipv4.fragOffset 30 hdr.ipv4.flags 3 action multiple_tables_example_01/MainControlImpl/tcp_fin_or_rst_packet permissions 0x1024 +$TC p4template create table/multiple_tables_example_01/MainControlImpl/set_all_options entry hdr.ipv4.srcAddr 4000 hdr.tcp.srcPort 40 hdr.ipv4.fragOffset 40 hdr.ipv4.flags 4 action multiple_tables_example_01/MainControlImpl/default_route_drop permissions 0x1024 +$TC p4template create table/multiple_tables_example_01/MainControlImpl/set_all_options entry hdr.ipv4.srcAddr 5000 hdr.tcp.srcPort 50 hdr.ipv4.fragOffset 50 hdr.ipv4.flags 5 action multiple_tables_example_01/MainControlImpl/next_hop permissions 0x1024 +$TC p4template create table/multiple_tables_example_01/MainControlImpl/set_all_options entry hdr.ipv4.srcAddr 6000 hdr.tcp.srcPort 60 hdr.ipv4.fragOffset 60 hdr.ipv4.flags 6 action multiple_tables_example_01/MainControlImpl/sendtoport permissions 0x1024 $TC p4template update pipeline/multiple_tables_example_01 state ready \ No newline at end of file diff --git a/testdata/p4tc_samples_outputs/multiple_tables_example_02.template b/testdata/p4tc_samples_outputs/multiple_tables_example_02.template index b54e9f0680..33c7901ad6 100644 --- a/testdata/p4tc_samples_outputs/multiple_tables_example_02.template +++ b/testdata/p4tc_samples_outputs/multiple_tables_example_02.template @@ -83,4 +83,10 @@ $TC p4template create table/multiple_tables_example_02/MainControlImpl/set_all_o act name multiple_tables_example_02/MainControlImpl/sendtoport \ act name multiple_tables_example_02/MainControlImpl/drop $TC p4template update table/multiple_tables_example_02/MainControlImpl/set_all_options default_miss_action permissions 0x1024 action multiple_tables_example_02/MainControlImpl/drop +$TC p4template create table/multiple_tables_example_02/MainControlImpl/set_all_options entry hdr.ipv4.srcAddr 1000 hdr.tcp.srcPort 10 hdr.ipv4.fragOffset 10 hdr.ipv4.flags 1 action multiple_tables_example_02/MainControlImpl/tcp_syn_packet permissions 0x1024 +$TC p4template create table/multiple_tables_example_02/MainControlImpl/set_all_options entry hdr.ipv4.srcAddr 2000 hdr.tcp.srcPort 20 hdr.ipv4.fragOffset 20 hdr.ipv4.flags 2 action multiple_tables_example_02/MainControlImpl/tcp_fin_or_rst_packet permissions 0x1024 +$TC p4template create table/multiple_tables_example_02/MainControlImpl/set_all_options entry hdr.ipv4.srcAddr 3000 hdr.tcp.srcPort 30 hdr.ipv4.fragOffset 30 hdr.ipv4.flags 3 action multiple_tables_example_02/MainControlImpl/tcp_fin_or_rst_packet permissions 0x1024 +$TC p4template create table/multiple_tables_example_02/MainControlImpl/set_all_options entry hdr.ipv4.srcAddr 4000 hdr.tcp.srcPort 40 hdr.ipv4.fragOffset 40 hdr.ipv4.flags 4 action multiple_tables_example_02/MainControlImpl/default_route_drop permissions 0x1024 +$TC p4template create table/multiple_tables_example_02/MainControlImpl/set_all_options entry hdr.ipv4.srcAddr 5000 hdr.tcp.srcPort 50 hdr.ipv4.fragOffset 50 hdr.ipv4.flags 5 action multiple_tables_example_02/MainControlImpl/next_hop permissions 0x1024 +$TC p4template create table/multiple_tables_example_02/MainControlImpl/set_all_options entry hdr.ipv4.srcAddr 6000 hdr.tcp.srcPort 60 hdr.ipv4.fragOffset 60 hdr.ipv4.flags 6 action multiple_tables_example_02/MainControlImpl/sendtoport permissions 0x1024 $TC p4template update pipeline/multiple_tables_example_02 state ready \ No newline at end of file