Skip to content

Commit

Permalink
Fix for default_action
Browse files Browse the repository at this point in the history
 * tc template code change for default miss action
 * NoAction case generation in c code for tc backend
 * default case deletion in c code for tc backend
 * p4tc testcases output updated
  • Loading branch information
Sosutha committed Feb 29, 2024
1 parent eeee08e commit e7485f6
Show file tree
Hide file tree
Showing 44 changed files with 2,119 additions and 262 deletions.
24 changes: 24 additions & 0 deletions backends/tc/backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,30 @@ void ConvertToBackendIR::updateDefaultMissAction(const IR::P4Table *t, IR::TCTab
if (defaultActionProperty->isConstant) {
tabledef->setDefaultMissConst(true);
}
bool directionParamPresent = false;
auto paramList = actionCall->action->getParameters();
for (auto param : paramList->parameters) {
if (param->direction != IR::Direction::None) directionParamPresent = true;
}
if (!directionParamPresent) {
auto i = 0;
for (auto param : paramList->parameters) {
auto defaultParam = new IR::TCDefaultActionParam();
defaultParam->setParamName(param->name.originalName);
auto defaultArg = methodexp->arguments->at(i++);
if (auto constVal = defaultArg->expression->to<IR::Constant>()) {
bool sign;
if (const IR::Type_Bits *tb = constVal->type->to<IR::Type_Bits>()) {
sign = tb->isSigned;
} else {
sign = false;
}
defaultParam->setDefaultValue(
Util::toString(constVal->value, 0, sign, constVal->base));
}
tabledef->defaultMissActionParams.push_back(defaultParam);
}
}
}
}
}
Expand Down
80 changes: 34 additions & 46 deletions backends/tc/ebpfCodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -860,10 +860,13 @@ void EBPFTablePNA::emitAction(EBPF::CodeBuilder *builder, cstring valueName,
builder->emitIndent();
builder->appendFormat("switch (%s->action) ", valueName.c_str());
builder->blockStart();
bool noActionGenerated = false;

for (auto a : actionList->actionList) {
auto adecl = program->refMap->getDeclaration(a->getPath(), true);
auto action = adecl->getNode()->checkedTo<IR::P4Action>();
if (action->name.originalName == P4::P4CoreLibrary::instance().noAction.name)
noActionGenerated = true;
cstring name = EBPF::EBPFObject::externalName(action), msgStr, convStr;
builder->emitIndent();
cstring actionName = p4ActionToActionIDName(action);
Expand Down Expand Up @@ -903,16 +906,22 @@ void EBPFTablePNA::emitAction(EBPF::CodeBuilder *builder, cstring valueName,
builder->appendLine("break;");
builder->decreaseIndent();
}

builder->emitIndent();
builder->appendLine("default:");
builder->increaseIndent();
builder->target->emitTraceMessage(builder, "Control: Invalid action type, aborting");

builder->emitIndent();
builder->appendFormat("return %s", builder->target->abortReturnCode().c_str());
builder->endOfStatement(true);
builder->decreaseIndent();
if (!noActionGenerated) {
cstring noActionName = P4::P4CoreLibrary::instance().noAction.name;
cstring tableInstance = dataMapName;
cstring actionName =
Util::printf_format("%s_ACT_%s", tableInstance.toUpper(), noActionName.toUpper());
builder->emitIndent();
builder->appendFormat("case %s: ", actionName);
builder->newline();
builder->increaseIndent();
builder->emitIndent();
builder->blockStart();
builder->blockEnd(true);
builder->emitIndent();
builder->appendLine("break;");
builder->decreaseIndent();
}

builder->blockEnd(true);

Expand All @@ -924,13 +933,8 @@ void EBPFTablePNA::emitAction(EBPF::CodeBuilder *builder, cstring valueName,

builder->blockEnd(false);
builder->appendFormat(" else ");
if (dropOnNoMatchingEntryFound()) {
builder->target->emitTraceMessage(builder, "Control: Entry not found, aborting");
emitDefaultAction(builder, valueName);
} else {
builder->target->emitTraceMessage(builder,
"Control: Entry not found, executing implicit NoAction");
}
builder->blockStart();
builder->blockEnd(true);
}

void EBPFTablePNA::emitInitializer(EBPF::CodeBuilder *builder) {
Expand All @@ -953,46 +957,30 @@ void EBPFTablePNA::emitDefaultActionStruct(EBPF::CodeBuilder *builder) {
}
}

void EBPFTablePNA::emitDefaultAction(EBPF::CodeBuilder *builder, cstring valueName) {
const IR::P4Table *t = table->container;
const IR::Expression *default_action = t->getDefaultAction();
bool visitDefaultAction = false;
if (default_action) {
if (auto mc = default_action->to<IR::MethodCallExpression>()) {
default_action = mc->method;
}
auto path = default_action->to<IR::PathExpression>();
BUG_CHECK(path, "Default action path %1% cannot be found", default_action);
if (auto defaultActionDecl =
program->refMap->getDeclaration(path->path)->to<IR::P4Action>()) {
if (defaultActionDecl->name.originalName != "NoAction") {
visitDefaultAction = true;
auto visitor = createActionTranslationVisitor(valueName, program);
visitor->setBuilder(builder);
visitor->copySubstitutions(codeGen);
visitor->copyPointerVariables(codeGen);
defaultActionDecl->apply(*visitor);
builder->newline();
}
}
}
if (visitDefaultAction == false) {
builder->blockStart();
builder->blockEnd(true);
}
}

void EBPFTablePNA::emitValueActionIDNames(EBPF::CodeBuilder *builder) {
// create type definition for action
builder->emitIndent();
bool noActionGenerated = false;
for (auto a : actionList->actionList) {
auto adecl = program->refMap->getDeclaration(a->getPath(), true);
auto action = adecl->getNode()->checkedTo<IR::P4Action>();
if (action->name.originalName == P4::P4CoreLibrary::instance().noAction.name)
noActionGenerated = true;
unsigned int action_idx = tcIR->getActionId(tcIR->externalName(action));
builder->emitIndent();
builder->appendFormat("#define %s %d", p4ActionToActionIDName(action), action_idx);
builder->newline();
}
if (!noActionGenerated) {
cstring noActionName = P4::P4CoreLibrary::instance().noAction.name;
cstring tableInstance = dataMapName;
cstring actionName =
Util::printf_format("%s_ACT_%s", tableInstance.toUpper(), noActionName.toUpper());
unsigned int action_idx = tcIR->getActionId(noActionName);
builder->emitIndent();
builder->appendFormat("#define %s %d", actionName, action_idx);
builder->newline();
}
builder->emitIndent();
}

Expand Down
1 change: 0 additions & 1 deletion backends/tc/ebpfCodeGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ class EBPFTablePNA : public EBPF::EBPFTablePSA {
void emitAction(EBPF::CodeBuilder *builder, cstring valueName,
cstring actionRunVariable) override;
void emitValueActionIDNames(EBPF::CodeBuilder *builder) override;
void emitDefaultAction(EBPF::CodeBuilder *builder, cstring valueName);
cstring p4ActionToActionIDName(const IR::P4Action *action) const;

DECLARE_TYPEINFO(EBPFTablePNA, EBPF::EBPFTablePSA);
Expand Down
50 changes: 27 additions & 23 deletions backends/tc/tc.def
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,29 @@ 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;
Expand Down Expand Up @@ -176,11 +199,10 @@ class TCTable {
unsigned tableEntriesCount;
unsigned numMask;
unsigned matchType;
TCAction preaction;
TCAction postaction;
TCAction defaultHitAction;
bool isDefaultHitConst;
TCAction defaultMissAction;
optional safe_vector<TCDefaultActionParam> defaultMissActionParams;
bool isDefaultMissConst;
ordered_map<TCAction, unsigned> actionList;
safe_vector<TCEntry> const_entries;
Expand All @@ -197,12 +219,6 @@ class TCTable {
void setMatchType(unsigned m) {
matchType = m;
}
void setPreaction(TCAction p) {
preaction = p;
}
void setPostaction(TCAction p) {
postaction = p;
}
void setDefaultHitAction(TCAction d) {
defaultHitAction = d;
}
Expand Down Expand Up @@ -245,8 +261,6 @@ class TCTable {
tableEntriesCount = TC::DEFAULT_TABLE_ENTRIES;
numMask = TC::DEFAULT_KEY_MASK;
matchType = TC::EXACT_TYPE;
preaction = nullptr;
postaction = nullptr;
defaultHitAction = nullptr;
defaultMissAction = nullptr;
isDefaultHitConst = false;
Expand Down Expand Up @@ -278,19 +292,6 @@ class TCTable {
}
}
}

if (preaction != nullptr) {
tcTable += "\n" + preaction->toString();
tcTable += "\n$TC p4template update table/" + pipelineName
+ "/" + controlName + "/" + tableName
+ " preactions action " + preaction->getName();
}
if (postaction != nullptr) {
tcTable += "\n" + postaction->toString();
tcTable += "\n$TC p4template update table/" + pipelineName
+ "/" + controlName + "/" + tableName
+ " postactions action " + postaction->getName();
}
if (defaultHitAction != nullptr) {
tcTable += "\n$TC p4template update table/" + pipelineName
+ "/" + controlName + "/" + tableName
Expand All @@ -308,6 +309,9 @@ class TCTable {
tcTable += " permissions 0x1024";
}
tcTable += " action " + defaultMissAction->getName();
for (auto param : defaultMissActionParams) {
tcTable += param->toString();
}
}
if (const_entries.size() != 0) {
for (auto entry : const_entries) {
Expand Down
134 changes: 134 additions & 0 deletions testdata/p4tc_samples/default_action_with_param.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#include <core.p4>
#include <tc/pna.p4>

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;
}
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
Loading

0 comments on commit e7485f6

Please sign in to comment.