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

DPDK Backend: Connection tracking support #3290

Merged
merged 3 commits into from
May 16, 2022
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
7 changes: 7 additions & 0 deletions backends/dpdk/DpdkXfail.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,10 @@ p4c_add_xfail_reason("dpdk"
testdata/p4_16_samples/psa-dpdk-struct-field.p4
testdata/p4_16_samples/psa-example-register2-bmv2.p4
)

p4c_add_xfail_reason("dpdk"
"must only be called from within an action"
testdata/p4_16_samples/pna-add-on-miss-err.p4
testdata/p4_16_samples/pna-example-tcp-connection-tracking-err-1.p4
testdata/p4_16_samples/pna-example-tcp-connection-tracking-err.p4
)
1 change: 1 addition & 0 deletions backends/dpdk/backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ void DpdkBackend::convert(const IR::ToplevelBlock *tlb) {
new ConvertActionSelectorAndProfile(refMap, typeMap, &structure),
new CollectTableInfo(&structure),
new CollectAddOnMissTable(refMap, typeMap, &structure),
new ValidateAddOnMissExterns(refMap, typeMap, &structure),
new P4::MoveDeclarations(), // Move all local declarations to the beginning
new CollectProgramStructure(refMap, typeMap, &structure),
new CollectMetadataHeaderInfo(&structure),
Expand Down
9 changes: 8 additions & 1 deletion backends/dpdk/dpdk.def
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ class DpdkApplyStatement : DpdkAsmStatement, IDPDKNode {

class DpdkLearnStatement : DpdkAsmStatement, IDPDKNode {
cstring action;
optional Expression argument;
Expression timeout;
NullOK optional Expression argument;
std::ostream& toSpec(std::ostream& out) const override;
}

Expand Down Expand Up @@ -450,6 +451,12 @@ class DpdkReturnStatement : DpdkAsmStatement, IDPDKNode {
#nodbprint
}

class DpdkRearmStatement : DpdkAsmStatement, IDPDKNode {
NullOK optional Expression timeout;
std::ostream& toSpec(std::ostream& out) const override;
#nodbprint
}

class DpdkRecirculateStatement : DpdkAsmStatement, IDPDKNode {
std::ostream& toSpec(std::ostream& out) const override;
#nodbprint
Expand Down
78 changes: 77 additions & 1 deletion backends/dpdk/dpdkArch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2239,6 +2239,12 @@ void CollectAddOnMissTable::postorder(const IR::P4Table* t) {
default_action);
}
}
if (use_add_on_miss) {
for (auto action : t->getActionList()->actionList) {
auto action_decl = refMap->getDeclaration(action->getPath())->to<IR::P4Action>();
structure->learner_action_table.emplace(action_decl->externalName(), t);
}
}
}

void CollectAddOnMissTable::postorder(const IR::MethodCallStatement *mcs) {
Expand All @@ -2255,14 +2261,84 @@ void CollectAddOnMissTable::postorder(const IR::MethodCallStatement *mcs) {
BUG_CHECK(ctxt != nullptr, "%1%: add_entry extern can only be used in an action", mcs);

// assuming checking on number of arguments is already performed in frontend.
BUG_CHECK(mce->arguments->size() == 2, "%1%: expected two arguments in add_entry extern", mcs);
BUG_CHECK(mce->arguments->size() == 3,
"%1%: expected 3 arguments in add_entry extern", mcs);
auto action = mce->arguments->at(0);
// assuming syntax check is already performed earlier
auto action_name = action->expression->to<IR::StringLiteral>()->value;
structure->learner_actions.insert(action_name);
return;
}

void ValidateAddOnMissExterns::postorder(const IR::MethodCallStatement *mcs) {
bool isValidExternCall = false;
auto mce = mcs->methodCall;
auto mi = P4::MethodInstance::resolve(mce, refMap, typeMap);
if (!mi->is<P4::ExternFunction>()) {
return;
}
auto func = mi->to<P4::ExternFunction>();
auto externFuncName = func->method->name;
if (externFuncName != "restart_expire_timer" && externFuncName != "set_entry_expire_time" &&
externFuncName != "add_entry")
return;
auto act = findOrigCtxt<IR::P4Action>();
BUG_CHECK(act != nullptr, "%1%: %2% extern can only be used in an action", mcs, externFuncName);
auto tbl = ::get(structure->learner_action_table,act->externalName());
if (externFuncName == "restart_expire_timer" || externFuncName == "set_entry_expire_time") {
bool use_idle_timeout_with_auto_delete = false;
if (tbl) {
auto idle_timeout_with_auto_delete =
tbl->properties->getProperty("idle_timeout_with_auto_delete");
if (idle_timeout_with_auto_delete != nullptr) {
if (idle_timeout_with_auto_delete->value->is<IR::ExpressionValue>()) {
auto expr =
idle_timeout_with_auto_delete->value->to<IR::ExpressionValue>()->expression;
if (!expr->is<IR::BoolLiteral>()) {
::error(ErrorType::ERR_UNEXPECTED,
"%1%: expected boolean for 'idle_timeout_with_auto_delete' property",
idle_timeout_with_auto_delete);
return;
} else {
use_idle_timeout_with_auto_delete = expr->to<IR::BoolLiteral>()->value;
if (use_idle_timeout_with_auto_delete)
isValidExternCall = true;
}
}
}
}
if (!isValidExternCall) {
::error(ErrorType::ERR_UNEXPECTED,
"%1% must only be called from within an action with of a table with "
"'idle_timeout_with_auto_delete' property equal to true", externFuncName);
}
} else if (externFuncName == "add_entry") {
if (tbl) {
mihaibudiu marked this conversation as resolved.
Show resolved Hide resolved
auto add_on_miss = tbl->properties->getProperty("add_on_miss");
if (add_on_miss != nullptr) {
if (add_on_miss->value->is<IR::ExpressionValue>()) {
auto expr = add_on_miss->value->to<IR::ExpressionValue>()->expression;
if (!expr->is<IR::BoolLiteral>()) {
::error(ErrorType::ERR_UNEXPECTED,
"%1%: expected boolean for 'add_on_miss' property", add_on_miss);
return;
} else {
auto use_add_on_miss = expr->to<IR::BoolLiteral>()->value;
if (use_add_on_miss)
isValidExternCall = true;
}
}
}
}
if (!isValidExternCall) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be after the next brace?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

::error(ErrorType::ERR_UNEXPECTED,
"%1% must only be called from within an action with 'add_on_miss'"
" property equal to true", externFuncName);
}
}
return;
}

bool ElimHeaderCopy::isHeader(const IR::Expression* e) {
auto type = typeMap->getType(e);
if (type)
Expand Down
13 changes: 13 additions & 0 deletions backends/dpdk/dpdkArch.h
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,19 @@ class CollectAddOnMissTable : public Inspector {
void postorder(const IR::MethodCallStatement*) override;
};

class ValidateAddOnMissExterns : public Inspector {
P4::ReferenceMap* refMap;
P4::TypeMap* typeMap;
DpdkProgramStructure* structure;

public:
ValidateAddOnMissExterns(P4::ReferenceMap *refMap, P4::TypeMap *typeMap,
DpdkProgramStructure* structure) :
refMap(refMap), typeMap(typeMap), structure(structure) {}

void postorder(const IR::MethodCallStatement*) override;
};

class CollectErrors : public Inspector {
DpdkProgramStructure *structure;

Expand Down
62 changes: 49 additions & 13 deletions backends/dpdk/dpdkContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,37 @@ void DpdkContextGenerator::CollectTablesAndSetAttributes() {
tblAttr.size = size->asUnsigned();
auto hidden = tbl->annotations->getSingle(IR::Annotation::hiddenAnnotation);
auto selector = tbl->properties->getProperty("selector");
tblAttr.is_add_on_miss = false;
auto add_on_miss = tbl->properties->getProperty("add_on_miss");
if (add_on_miss != nullptr) {
if (add_on_miss->value->is<IR::ExpressionValue>()) {
auto expr = add_on_miss->value->to<IR::ExpressionValue>()->expression;
if (!expr->is<IR::BoolLiteral>()) {
::error(ErrorType::ERR_UNEXPECTED,
"%1%: expected boolean for 'add_on_miss' property", add_on_miss);
return;
} else {
tblAttr.is_add_on_miss = expr->to<IR::BoolLiteral>()->value;
}
}
}
auto idle_timeout_with_auto_delete =
tbl->properties->getProperty("idle_timeout_with_auto_delete");
if (idle_timeout_with_auto_delete != nullptr) {
if (idle_timeout_with_auto_delete->value->is<IR::ExpressionValue>()) {
auto expr =
idle_timeout_with_auto_delete->value->to<IR::ExpressionValue>()->expression;
if (!expr->is<IR::BoolLiteral>()) {
::error(ErrorType::ERR_UNEXPECTED,
"%1%: expected boolean for 'idle_timeout_with_auto_delete' property",
idle_timeout_with_auto_delete);
return;
} else {
tblAttr.idle_timeout_with_auto_delete =
expr->to<IR::BoolLiteral>()->value;
}
}
}
if (hidden) {
tblAttr.tableType = selector ? "selection" : "action";
tblAttr.isHidden = true;
Expand Down Expand Up @@ -113,6 +144,8 @@ Util::JsonObject* DpdkContextGenerator::initTableCommonJson(
tableJson->emplace("table_type", attr.tableType);
tableJson->emplace("size", attr.size);
tableJson->emplace("p4_hidden", attr.isHidden);
tableJson->emplace("add_on_miss", attr.is_add_on_miss);
tableJson->emplace("idle_timeout_with_auto_delete", attr.idle_timeout_with_auto_delete);
return tableJson;
}

Expand Down Expand Up @@ -213,7 +246,8 @@ Util::JsonArray* paramJson, const cstring name, int dest_start, int dest_width)

// This functions creates JSON object for match attributes of a table.
Util::JsonObject*
DpdkContextGenerator::addMatchAttributes(const IR::P4Table*table, const cstring ctrlName) {
DpdkContextGenerator::addMatchAttributes(const IR::P4Table* table, const cstring ctrlName) {
auto tableAttr = ::get(tableAttrmap, table->name.originalName);
auto* match_attributes = new Util::JsonObject();
auto* actFmtArray = new Util::JsonArray();
auto* stageTblArray = new Util::JsonArray();
Expand All @@ -236,16 +270,17 @@ DpdkContextGenerator::addMatchAttributes(const IR::P4Table*table, const cstring
if (attr.params) {
int index = 0;
int position = 0;
int param_width = 8; // Minimum width for dpdk action params
for (auto param : *(attr.params)) {
// TODO Handle other types of parameters
if (param->type->is<IR::Type_Bits>()) {
addImmediateField(immFldArray, param->name.originalName,
index/8, param->type->width_bits());
index += param->type->width_bits();
position++;
} else {
param_width = param->type->width_bits();
} else if (!param->type->is<IR::Type_Boolean>()) {
BUG("Unsupported parameter type %1%", param->type);
}
addImmediateField(immFldArray, param->name.originalName,
index/8, param_width);
index += param_width;
position++;
}
}
oneAction->emplace("immediate_fields",immFldArray);
Expand Down Expand Up @@ -295,16 +330,17 @@ const IR::P4Table * table, const cstring controlName, bool isMatch) {
if (attr.params) {
int index = 0;
int position = 0;
int param_width = 8;
for (auto param : *(attr.params)) {
// TODO Handle other types of parameters
if (param->type->is<IR::Type_Bits>()) {
addActionParam(paramJson, param->name.originalName,
param->type->width_bits(), position, index/8);
position++;
index += param->type->width_bits();
} else {
param_width = param->type->width_bits();
} else if (!param->type->is<IR::Type_Boolean>()) {
BUG("Unsupported parameter type %1%", param->type);
}
addActionParam(paramJson, param->name.originalName,
param_width, position, index/8);
index += param_width;
position++;
}
}
act->emplace("p4_parameters", paramJson);
Expand Down
2 changes: 2 additions & 0 deletions backends/dpdk/dpdkContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ struct TableAttributes {
Match table is a regular P4 table, selection table and action tables are compiler
generated tables when psa_implementation is action_selector or action_profile */
cstring tableType;
bool is_add_on_miss;
bool idle_timeout_with_auto_delete;
bool isHidden;
unsigned size;
cstring controlName;
Expand Down
49 changes: 45 additions & 4 deletions backends/dpdk/dpdkHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -768,26 +768,67 @@ bool ConvertStatementToDpdk::preorder(const IR::MethodCallStatement *s) {
append_parser_name(parser, IR::ParserState::reject)));
add_instr(new IR::DpdkLabelStatement(end_label));
} else if (a->method->name == "add_entry") {
auto args = a->expr->arguments;
auto argSize = args->size();
if (argSize != 3) {
::error(ErrorType::ERR_UNEXPECTED, "Unexpected number of arguments for %1%",
a->method->name);
return false;
}
auto action = a->expr->arguments->at(0)->expression;
auto action_name = action->to<IR::StringLiteral>()->value;
auto param = a->expr->arguments->at(1)->expression;
auto timeout_id = a->expr->arguments->at(2)->expression;
if (timeout_id->is<IR::Constant>()) {
BUG_CHECK(metadataStruct, "Metadata structure missing unexpectedly!");
IR::ID tmo(refmap->newName("timeout_id"));
auto timeout = new IR::Member(new IR::PathExpression("m"), tmo);
metadataStruct->fields.push_back(new IR::StructField(tmo, timeout_id->type));
add_instr(new IR::DpdkMovStatement(timeout, timeout_id));
timeout_id = timeout;
}
if (param->is<IR::Member>()) {
auto argument = param->to<IR::Member>();
add_instr(new IR::DpdkLearnStatement(action_name, argument));
add_instr(new IR::DpdkLearnStatement(action_name, timeout_id, argument));
mihaibudiu marked this conversation as resolved.
Show resolved Hide resolved
} else if (param->is<IR::StructExpression>()) {
auto argument = param->to<IR::StructExpression>()->components.at(0)->expression;
add_instr(new IR::DpdkLearnStatement(action_name, argument));
if (param->to<IR::StructExpression>()->components.size() == 0) {
add_instr(new IR::DpdkLearnStatement(action_name, timeout_id));
} else {
auto argument = param->to<IR::StructExpression>()->components.at(0)->expression;
add_instr(new IR::DpdkLearnStatement(action_name, timeout_id, argument));
}
} else if (param->is<IR::Constant>()) {
// Move constant param to metadata as DPDK expects it to be in metadata
BUG_CHECK(metadataStruct, "Metadata structure missing unexpectedly!");
IR::ID learnArg(refmap->newName("learnArg"));
metadataStruct->fields.push_back(new IR::StructField(learnArg, param->type));
auto learnMember = new IR::Member(new IR::PathExpression("m"), learnArg);
add_instr(new IR::DpdkMovStatement(learnMember, param));
add_instr(new IR::DpdkLearnStatement(action_name, learnMember));
add_instr(new IR::DpdkLearnStatement(action_name, timeout_id, learnMember));
} else {
::error(ErrorType::ERR_UNEXPECTED, "%1%: unhandled function", s);
}
} else if (a->method->name == "restart_expire_timer") {
add_instr(new IR::DpdkRearmStatement());
} else if (a->method->name == "set_entry_expire_time") {
auto args = a->expr->arguments;
if (args->size() != 1) {
::error(ErrorType::ERR_UNEXPECTED, "Expected 1 arguments for %1%",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 argument

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

a->method->name);
return false;
}
auto timeout = a->expr->arguments->at(0)->expression;
if (timeout->is<IR::Constant>()) {
// Move timeout_is to metadata fields as DPDK expects these parameters
// to be in metadata
BUG_CHECK(metadataStruct, "Metadata structure missing unexpectedly!");
IR::ID tmo(refmap->newName("new_timeout"));
metadataStruct->fields.push_back(new IR::StructField(tmo, timeout->type));
auto tmoMem = new IR::Member(new IR::PathExpression("m"), tmo);
add_instr(new IR::DpdkMovStatement(tmoMem, timeout));
timeout = tmoMem;
}
add_instr(new IR::DpdkRearmStatement(timeout));
} else if (a->method->name == "mirror_packet") {
auto args = a->expr->arguments;
if (args->size() != 2) {
Expand Down
1 change: 1 addition & 0 deletions backends/dpdk/dpdkProgramStructure.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ struct DpdkProgramStructure {
ordered_set<cstring> learner_tables;
ordered_set<cstring> learner_actions;
ordered_map<cstring, std::vector<cstring>> learner_action_params;
ordered_map<cstring, const IR::P4Table *> learner_action_table;

IR::IndexedVector<IR::DpdkDeclaration> variables;

Expand Down
3 changes: 2 additions & 1 deletion backends/dpdk/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ DpdkMidEnd::DpdkMidEnd(CompilerOptions &options,
if (arch == "pna") {
return new P4::ValidateTableProperties({"pna_implementation",
"pna_direct_counter", "pna_direct_meter", "pna_idle_timeout", "size",
"add_on_miss"});
"add_on_miss", "idle_timeout_with_auto_delete",
"default_idle_timeout_for_data_plane_added_entries"});
} else if (arch == "psa") {
return new P4::ValidateTableProperties({"psa_implementation",
"psa_direct_counter", "psa_direct_meter", "psa_idle_timeout", "size"});
Expand Down
Loading