Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support const entries in P4TC #15

Closed
wants to merge 13 commits into from
Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions backends/tc/backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,63 @@ 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();
for (auto e : entriesList->entries) {
if (keys == nullptr) {
return;
}
auto keyset = e->getKeys();
if (keyset->components.size() != keys->keyElements.size()) {
::error("No of keys in const_entries should be same as no of keys in the table.");
return;
}
ordered_map<cstring, cstring> 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<IR::StringLiteral>()->value;
}
}
auto keySetElement = keyset->components.at(itr);
auto key = keySetElement->toString();
if (keySetElement->is<IR::DefaultExpression>()) {
key = "default";
} else if (keySetElement->is<IR::Constant>()) {
big_int kValue = keySetElement->to<IR::Constant>()->value;
int kBase = keySetElement->to<IR::Constant>()->base;
std::stringstream value;
std::deque<char> buf;
do {
const int digit = static_cast<int>(static_cast<big_int>(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<IR::Range>()) {
auto left = keySetElement->to<IR::Range>()->left;
auto right = keySetElement->to<IR::Range>()->right;
auto operand = keySetElement->to<IR::Range>()->getStringOp();
key = left->toString() + operand + right->toString();
} else if (keySetElement->is<IR::Mask>()) {
auto left = keySetElement->to<IR::Mask>()->left;
auto right = keySetElement->to<IR::Mask>()->right;
auto operand = keySetElement->to<IR::Mask>()->getStringOp();
key = left->toString() + operand + right->toString();
}
keyList.emplace(keyString, key);
}
komaljai marked this conversation as resolved.
Show resolved Hide resolved
tabledef->addConstEntries(e->action->toString(), keyList);
}
}

void ConvertToBackendIR::updateDefaultMissAction(const IR::P4Table *t, IR::TCTable *tabledef) {
auto defaultAction = t->getDefaultAction();
if (defaultAction == nullptr || !defaultAction->is<IR::MethodCallExpression>()) return;
Expand Down Expand Up @@ -450,6 +507,7 @@ void ConvertToBackendIR::postorder(const IR::P4Table *t) {
updateDefaultHitAction(t, tableDefinition);
updateDefaultMissAction(t, tableDefinition);
updateMatchType(t, tableDefinition);
updateConstEntries(t, tableDefinition);
tcPipeline->addTableDefinition(tableDefinition);
}
}
Expand Down
4 changes: 4 additions & 0 deletions backends/tc/backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ and limitations under the License.
#ifndef BACKENDS_TC_BACKEND_H_
#define BACKENDS_TC_BACKEND_H_

#include <deque>

#include "backends/ebpf/psa/ebpfPsaGen.h"
#include "ebpfCodeGen.h"
#include "frontends/p4/evaluator/evaluator.h"
Expand All @@ -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"
Expand Down Expand Up @@ -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);
Expand Down
17 changes: 17 additions & 0 deletions backends/tc/tc.def
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ class TCTable {
TCAction defaultMissAction;
bool isDefaultMissConst;
ordered_map<TCAction, unsigned> actionList;
ordered_map<cstring, ordered_map<cstring, cstring>> const_entries;
void setKeySize(unsigned k) {
keySize = k;
}
Expand Down Expand Up @@ -200,6 +201,9 @@ class TCTable {
void addAction(TCAction action, unsigned flag) {
actionList.emplace(action, flag);
}
void addConstEntries(cstring action, ordered_map<cstring, cstring> keys) {
const_entries.emplace(action, keys);
}
cstring printMatchType(unsigned matchType) const {
cstring matchTypeString = "";
switch(matchType) {
Expand Down Expand Up @@ -288,6 +292,19 @@ 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";
for(auto k : entry.second) {
tcTable += " " + k.first + " " + k.second;
komaljai marked this conversation as resolved.
Show resolved Hide resolved
}
tcTable += " action " + pipelineName
+ "/" + controlName + "/" + entry.first;
tcTable += " permissions 0x1024";
}
}
return tcTable;
}
dbprint { out << toString(); }
Expand Down
1 change: 1 addition & 0 deletions lib/stringify.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_ */
239 changes: 239 additions & 0 deletions testdata/p4tc_samples/calculator.p4
Original file line number Diff line number Diff line change
@@ -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 <core.p4>
#include <tc/pna.p4>


/*
* 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<p4calc_t>().p,
pkt.lookahead<p4calc_t>().four,
pkt.lookahead<p4calc_t>().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,
in 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;
Loading
Loading