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

P4TC - Support add_on_miss, add entry externs #4522

Merged
merged 15 commits into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
6 changes: 6 additions & 0 deletions backends/tc/backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,11 @@ void ConvertToBackendIR::postorder(const IR::P4Action *action) {
}
}

void ConvertToBackendIR::updateTimerProfiles(IR::TCTable *tabledef) {
if (options.timerProfiles > 4) {
komaljai marked this conversation as resolved.
Show resolved Hide resolved
tabledef->addTimerProfiles(options.timerProfiles);
}
}
void ConvertToBackendIR::updateConstEntries(const IR::P4Table *t, IR::TCTable *tabledef) {
// Check if there are const entries.
auto entriesList = t->getEntries();
Expand Down Expand Up @@ -544,6 +549,7 @@ void ConvertToBackendIR::postorder(const IR::P4Table *t) {
updateDefaultMissAction(t, tableDefinition);
updateMatchType(t, tableDefinition);
updateConstEntries(t, tableDefinition);
updateTimerProfiles(tableDefinition);
tcPipeline->addTableDefinition(tableDefinition);
}
}
Expand Down
8 changes: 8 additions & 0 deletions backends/tc/backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class ConvertToBackendIR : public Inspector {
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);
void updateTimerProfiles(IR::TCTable *tabledef);
bool isPnaParserMeta(const IR::Member *mem);
bool isPnaMainInputMeta(const IR::Member *mem);
bool isPnaMainOutputMeta(const IR::Member *mem);
Expand All @@ -88,6 +89,13 @@ class ConvertToBackendIR : public Inspector {
unsigned getActionId(cstring actionName) const;
unsigned getTableKeysize(unsigned tableId) const;
cstring externalName(const IR::IDeclaration *declaration) const;
void updateAddOnMissTable(cstring tblname) const {
for (auto table : tcPipeline->tableDefs) {
if (table->tableName == tblname) {
((IR::TCTable *)table)->setTableAddOnMiss();
}
}
}
};

class Extern {
Expand Down
231 changes: 117 additions & 114 deletions backends/tc/ebpfCodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1419,6 +1419,50 @@ bool ControlBodyTranslatorPNA::IsTableAddOnMiss(const IR::P4Table *table) {
return false;
}

const IR::P4Action *ControlBodyTranslatorPNA::GetAddOnMissHitAction(cstring actionName) {
for (auto a : table->actionList->actionList) {
auto adecl = control->program->refMap->getDeclaration(a->getPath(), true);
auto action = adecl->getNode()->to<IR::P4Action>();
if (action->name.originalName == actionName) {
auto annotations = a->getAnnotations();
if (annotations && annotations->getSingle("defaultonly")) {
::error(ErrorType::ERR_UNEXPECTED,
"add_entry hit action %1% cannot be annotated with defaultonly.",
actionName);
}
return action;
}
}
::error(ErrorType::ERR_UNEXPECTED,
"add_entry extern can only be applied for one of the hit action of table "
"%1%. %2% is not hit action of table.",
table->instanceName, actionName);
return nullptr;
}

void ControlBodyTranslatorPNA::ValidateAddOnMissMissAction(const IR::P4Action *act) {
if (!act) {
::error(ErrorType::ERR_UNEXPECTED, "%1% add_entry extern can only be used in an action",
act);
}
const IR::P4Table *t = table->table->container;
cstring tblname = t->name.originalName;
const IR::Expression *defaultAction = t->getDefaultAction();
CHECK_NULL(defaultAction);
auto defaultActionName = table->getActionNameExpression(defaultAction);
CHECK_NULL(defaultActionName);
if (defaultActionName->path->name.originalName != act->name.originalName) {
::error(ErrorType::ERR_UNEXPECTED,
"add_entry extern can only be applied in default action of the table.");
}
if (!IsTableAddOnMiss(t)) {
::warning(ErrorType::WARN_MISSING,
"add_entry extern can only be used in an action"
" of a table with property add_on_miss equals to true.");
}
tcIR->updateAddOnMissTable(tblname);
}

void ControlBodyTranslatorPNA::processFunction(const P4::ExternFunction *function) {
if (function->expr->method->toString() == "send_to_port" ||
function->expr->method->toString() == "drop_packet") {
Expand Down Expand Up @@ -1469,138 +1513,97 @@ void ControlBodyTranslatorPNA::processFunction(const P4::ExternFunction *functio
}
return;
} else if (function->expr->method->toString() == "add_entry") {
/*
add_entry() to be called with the following restrictions:
* Only from within an action
* Only if the action is a default action of a table with property add_on_miss equal to true.
* Only with an action name that is one of the hit actions of that same table. This action
has parameters that are all directionless.
* The type T is a struct containing one member for each directionless parameter of the hit
action to be added. The member names must match the hit action parameter names, and their
types must be the same as the corresponding hit action parameters.
*/
auto act = findContext<IR::P4Action>();
BUG_CHECK(act != nullptr, "%1% add_entry extern can only be used in an action", function);
const IR::P4Table *t = table->table->container;
const IR::Expression *defaultAction = t->getDefaultAction();
auto defaultActionName = table->getActionNameExpression(defaultAction);
CHECK_NULL(defaultActionName);
if (defaultActionName->path->name.originalName != act->name.originalName) {
::error(ErrorType::ERR_UNEXPECTED,
"add_entry extern can only be applied in default action of the table.");
}
ValidateAddOnMissMissAction(act);
BUG_CHECK(function->expr->arguments->size() == 3,
"%1%: expected 3 arguments in add_entry extern", function);
if (!IsTableAddOnMiss(t)) {
::warning(ErrorType::WARN_MISSING,
"add_entry extern can only be used in an action"
" of a table with property add_on_miss equals to true.");
}

auto action = function->expr->arguments->at(0);
auto actionName = action->expression->to<IR::StringLiteral>()->value;
auto param = function->expr->arguments->at(1)->expression;
auto expire_time_profile_id = function->expr->arguments->at(2);
auto controlName = control->controlBlock->getName().originalName;

if (table) {
auto actID = 0;
for (auto a : table->actionList->actionList) {
auto adecl = control->program->refMap->getDeclaration(a->getPath(), true);
auto action = adecl->getNode()->to<IR::P4Action>();
if (a->toString() == actionName) {
auto annotations = a->getAnnotations();
if (annotations && annotations->getSingle("defaultonly")) {
::error(ErrorType::ERR_UNEXPECTED,
"add_entry hit action %1% cannot be annotated with defaultonly.",
actionName);
}
cstring name = tcIR->externalName(action);
actID = tcIR->getActionId(name);
BUG_CHECK(actID != 0, "Action ID not found");

if (auto action = GetAddOnMissHitAction(actionName)) {
builder->emitIndent();
builder->appendLine("struct p4tc_table_entry_act_bpf update_act_bpf = {};");

if (param->is<IR::StructExpression>()) {
auto paramList = action->getParameters();
auto components = param->to<IR::StructExpression>()->components;
if (paramList->parameters.size() != components.size()) {
::error(ErrorType::ERR_UNEXPECTED,
"Action params in add_entry should be same as no of action "
"parameters. %1%",
action);
}
if (paramList->parameters.size() != 0) {
builder->emitIndent();
builder->appendLine("struct p4tc_table_entry_act_bpf update_act_bpf = {};");

if (param->is<IR::StructExpression>()) {
auto paramList = action->getParameters();
auto components = param->to<IR::StructExpression>()->components;
if (paramList->parameters.size() != components.size()) {
builder->appendFormat(
"struct %s *update_act_bpf_val = (struct %s*) &update_act_bpf;",
table->valueTypeName.c_str(), table->valueTypeName.c_str());
builder->newline();
cstring actionExtName = EBPF::EBPFObject::externalName(action);
// Assign Variables
for (size_t index = 0; index < components.size(); index++) {
auto param = paramList->getParameter(index);
if (param->direction != IR::Direction::None) {
::error(ErrorType::ERR_UNEXPECTED,
"Action params in add_entry should be same as no of action "
"parameters. %1%",
action);
"Parameters of action called from add_entry should be "
"directionless. %1%",
actionName);
}
if (components.size() == 0) {
break;
}

builder->emitIndent();
builder->appendLine("struct act_param {");
builder->emitIndent();
int index = 0;
for (auto param : paramList->parameters) {
if (param->direction != IR::Direction::None) {
::error(ErrorType::ERR_UNEXPECTED,
"Parameters of action called from add_entry should be "
"directionless. %1%",
actionName);
}
auto type = param->type;
auto etype = EBPF::EBPFTypeFactory::instance->create(type);
std::stringstream paramName;
paramName << "param" << index;
builder->append(" ");
etype->declare(builder, paramName.str().c_str(), false);
builder->endOfStatement();
builder->newline();
builder->emitIndent();
index = index + 1;
}
builder->appendLine("};");
builder->emitIndent();
builder->appendLine(
"struct act_param* params = (struct act_param *) "
"update_act_bpf.params;");
// Assign Variables
for (size_t index = 0; index < components.size(); index++) {
std::stringstream paramName;
paramName << "param" << index;
builder->emitIndent();
builder->appendFormat("params->%s = ", paramName.str().c_str());
visit(components.at(index)->expression);
builder->endOfStatement();
builder->newline();
}
builder->appendFormat("update_act_bpf_val->u.%s.%s = ", actionExtName,
param->toString());
visit(components.at(index)->expression);
builder->endOfStatement();
builder->newline();
}
komaljai marked this conversation as resolved.
Show resolved Hide resolved
break;
}
}
if (actID == 0) {
builder->emitIndent();
builder->appendFormat("update_act_bpf.action = %s;",
table->p4ActionToActionIDName(action));
builder->newline();
} else {
::error(ErrorType::ERR_UNEXPECTED,
"add_entry extern can only be applied for one of the hit action of table "
"%1%. %2% is not hit action of table.",
table->instanceName, actionName);
"action parameters of add_entry extern should be a structure only. %1%",
param);
}

builder->emitIndent();
builder->appendFormat("update_act_bpf.act_id = %d;", actID);
builder->newline();

builder->newline();
builder->emitIndent();
builder->appendLine("/* construct key */");
builder->emitIndent();
builder->appendLine(
"struct p4tc_table_entry_create_bpf_params__local update_params = {");
builder->emitIndent();
builder->appendLine(" .pipeid = 1,");
builder->emitIndent();
auto tableName = table->instanceName.substr(controlName.size() + 1);
auto tblId = tcIR->getTableId(tableName);
BUG_CHECK(tblId != 0, "Table ID not found");
builder->appendFormat(" .tblid = %d,", tblId);
builder->newline();
builder->emitIndent();
builder->append(" .profile_id = ");
visit(expire_time_profile_id);
builder->newline();
builder->emitIndent();
builder->appendLine("};");
builder->emitIndent();
builder->append(
"bpf_p4tc_entry_create_on_miss(skb, &update_params, &key, sizeof(key), "
"&update_act_bpf)");
}
builder->newline();
builder->emitIndent();
builder->appendLine("/* construct key */");
builder->emitIndent();
builder->appendLine("struct p4tc_table_entry_create_bpf_params__local update_params = {");
builder->emitIndent();
builder->appendLine(" .pipeid = p4tc_filter_fields.pipeid,");
builder->emitIndent();
auto tableName = table->instanceName.substr(controlName.size() + 1);
auto tblId = tcIR->getTableId(tableName);
BUG_CHECK(tblId != 0, "Table ID not found");
builder->appendFormat(" .tblid = %d,", tblId);
builder->newline();
builder->emitIndent();
builder->append(" .profile_id = ");
visit(expire_time_profile_id);
builder->newline();
builder->emitIndent();
builder->appendLine("};");
builder->emitIndent();
builder->append(
"bpf_p4tc_entry_create_on_miss(skb, &update_params, &key, sizeof(key), "
"&update_act_bpf)");
return;
}
processCustomExternFunction(function, EBPF::EBPFTypeFactory::instance);
Expand Down
2 changes: 2 additions & 0 deletions backends/tc/ebpfCodeGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,8 @@ class ControlBodyTranslatorPNA : public EBPF::ControlBodyTranslator {
void processMethod(const P4::ExternMethod *method) override;
bool preorder(const IR::Member *) override;
bool IsTableAddOnMiss(const IR::P4Table *table);
const IR::P4Action *GetAddOnMissHitAction(cstring actionName);
void ValidateAddOnMissMissAction(const IR::P4Action *act);
};

// Similar to class ActionTranslationVisitorPSA in backends/ebpf/psa/ebpfPsaControl.h
Expand Down
8 changes: 8 additions & 0 deletions backends/tc/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class TCOptions : public CompilerOptions {
bool emitTraceMessages = false;
// XDP2TC mode for PSA-eBPF
enum XDP2TC xdp2tcMode = XDP2TC_META;
unsigned timerProfiles = 4;

TCOptions() {
registerOption(
Expand Down Expand Up @@ -69,6 +70,13 @@ class TCOptions : public CompilerOptions {
},
"Select the mode used to pass metadata from XDP to TC "
"(possible values: meta, head, cpumap).");
registerOption(
"--num-timer-profiles", "No of Timer Profiles",
[this](const char *arg) {
timerProfiles = std::atoi(arg);
return true;
},
"Defines the no of timer profiles. Default is 4.");
komaljai marked this conversation as resolved.
Show resolved Hide resolved
}
};

Expand Down
16 changes: 16 additions & 0 deletions backends/tc/tc.def
Original file line number Diff line number Diff line change
Expand Up @@ -199,11 +199,13 @@ class TCTable {
unsigned tableEntriesCount;
unsigned numMask;
unsigned matchType;
unsigned timerProfiles;
TCAction defaultHitAction;
bool isDefaultHitConst;
TCAction defaultMissAction;
optional safe_vector<TCDefaultActionParam> defaultMissActionParams;
bool isDefaultMissConst;
bool isTableAddOnMiss;
ordered_map<TCAction, unsigned> actionList;
safe_vector<TCEntry> const_entries;

Expand Down Expand Up @@ -231,12 +233,18 @@ class TCTable {
void setDefaultMissConst(bool i) {
isDefaultMissConst = i;
}
void setTableAddOnMiss() {
isTableAddOnMiss = true;
}
void addAction(TCAction action, unsigned flag) {
actionList.emplace(action, flag);
}
void addConstEntries(TCEntry entry) {
const_entries.push_back(entry);
}
void addTimerProfiles(unsigned tp) {
timerProfiles = tp;
}
cstring printMatchType(unsigned matchType) const {
cstring matchTypeString = "";
switch(matchType) {
Expand All @@ -258,13 +266,15 @@ class TCTable {
controlName = cN;
pipelineName = pN;
keySize = 0;
timerProfiles = 4;
tableEntriesCount = TC::DEFAULT_TABLE_ENTRIES;
numMask = TC::DEFAULT_KEY_MASK;
matchType = TC::EXACT_TYPE;
defaultHitAction = nullptr;
defaultMissAction = nullptr;
isDefaultHitConst = false;
isDefaultMissConst = false;
isTableAddOnMiss = false;
}
toString {
std::string tcTable = "";
Expand All @@ -275,6 +285,12 @@ class TCTable {
tcTable += "\n\tkeysz " + Util::toString(keySize);
tcTable += " nummasks " + Util::toString(numMask);
tcTable += " tentries " + Util::toString(tableEntriesCount);
if (isTableAddOnMiss) {
tcTable += " permissions 0x3DE6";
if(timerProfiles > 4) {
komaljai marked this conversation as resolved.
Show resolved Hide resolved
tcTable += " num_timer_profiles " + timerProfiles;
}
}

if (!actionList.empty()) {
tcTable += " \\";
Expand Down
Loading