Skip to content

Commit

Permalink
Support for Register Extern in P4TC (#4671)
Browse files Browse the repository at this point in the history
* Implementation To annotate Register Extern
Generate Extern code in P4TC Template File

* Fix clang format issues

* Support for Register extern.

* Address merge conflict

* Update testcases

* Address comments

* Reverse noIncludes flag

* Addressed comments

* Addressed comments

* Change ext_params and ext_val to structure from structure pointer
  • Loading branch information
komaljai authored May 22, 2024
1 parent 5b9c0cc commit cca2a12
Show file tree
Hide file tree
Showing 103 changed files with 1,844 additions and 150 deletions.
2 changes: 2 additions & 0 deletions backends/tc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ set(P4TC_BACKEND_SOURCES
pnaProgramStructure.cpp
tc.cpp
tcAnnotations.cpp
tcExterns.cpp
version.cpp
../ebpf/ebpfBackend.cpp
../ebpf/ebpfProgram.cpp
Expand Down Expand Up @@ -63,6 +64,7 @@ set(P4TC_BACKEND_HEADERS
options.h
pnaProgramStructure.h
tcAnnotations.h
tcExterns.h
version.h
../ebpf/codeGen.h
../ebpf/ebpfBackend.h
Expand Down
193 changes: 191 additions & 2 deletions backends/tc/backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ bool Backend::process() {
parseTCAnno = new ParseTCAnnotations();
tcIR = new ConvertToBackendIR(toplevel, pipeline, refMap, typeMap, options);
genIJ = new IntrospectionGenerator(pipeline, refMap, typeMap);
addPasses({parseTCAnno, new P4::ResolveReferences(refMap),
new P4::TypeInference(refMap, typeMap), tcIR, genIJ});
addPasses({parseTCAnno, new P4::ClearTypeMap(typeMap),
new P4::TypeChecking(refMap, typeMap, true), tcIR, genIJ});
toplevel->getProgram()->apply(*this);
if (::errorCount() > 0) return false;
if (!ebpfCodeGen(refMapEBPF, typeMapEBPF)) return false;
Expand Down Expand Up @@ -713,6 +713,175 @@ void ConvertToBackendIR::postorder(const IR::P4Table *t) {
}
}

cstring ConvertToBackendIR::processExternPermission(const IR::Type_Extern *ext) {
cstring control_path, data_path;
// Check if access permissions is defined with annotation @tc_acl
auto annoList = ext->getAnnotations()->annotations;
for (auto anno : annoList) {
if (anno->name == ParseTCAnnotations::tc_acl) {
auto path = GetAnnotatedAccessPath(anno);
control_path = path->first;
data_path = path->second;
}
}
// Default access value of Control_path and Data_Path
if (control_path.isNullOrEmpty()) {
control_path = DEFAULT_EXTERN_CONTROL_PATH_ACCESS;
}
if (data_path.isNullOrEmpty()) {
data_path = DEFAULT_EXTERN_DATA_PATH_ACCESS;
}
auto access_cp = GetAccessNumericValue(control_path);
auto access_dp = GetAccessNumericValue(data_path);
auto access_permisson = (access_cp << 7) | access_dp;
std::stringstream value;
value << "0x" << std::hex << access_permisson;
return value.str().c_str();
}

void ConvertToBackendIR::processExternConstructorAnnotations(const IR::Type_Extern *extn,
const IR::Declaration_Instance *decl,
struct ExternInstance *instance) {
for (auto gd : *extn->getDeclarations()) {
if (!gd->getNode()->is<IR::Method>()) {
continue;
}
auto method = gd->getNode()->to<IR::Method>();
auto params = method->getParameters();
// Check if method is an constructor
if (method->name != extn->name) {
continue;
}
if (decl->arguments->size() != params->size()) {
continue;
}
for (unsigned itr = 0; itr < params->size(); itr++) {
auto annoList = params->getParameter(itr)->getAnnotations()->annotations;
for (auto anno : annoList) {
if (anno->name == ParseTCAnnotations::tc_numel) {
auto exp = decl->arguments->at(itr)->expression;
if (exp->is<IR::Constant>()) {
instance->is_num_elements = true;
instance->num_elements = exp->to<IR::Constant>()->asInt();
}
}
if (anno->name == ParseTCAnnotations::tc_init_val) {
// TODO: Process tc_init_val.
}
}
}
}
}

safe_vector<const IR::TCKey *> ConvertToBackendIR::processExternControlPath(
const IR::Type_SpecializedCanonical *ts, const IR::Type_Extern *extn, cstring eName) {
safe_vector<const IR::TCKey *> keys;
auto find = ControlStructPerExtern.find(eName);
if (find != ControlStructPerExtern.end()) {
auto extern_control_path = ControlStructPerExtern[eName];
int kId = 1;
for (auto field : extern_control_path->fields) {
if (field->getAnnotations()->annotations.size() != 1) {
continue;
}
cstring annoName;
auto annotation = field->getAnnotations()->annotations.at(0);
if (annotation->name == ParseTCAnnotations::tc_key ||
annotation->name == ParseTCAnnotations::tc_data_scalar) {
annoName = annotation->name;
} else if (annotation->name == ParseTCAnnotations::tc_data) {
annoName = "param";
}
/* If the field is of Type_Name example 'T' and 'T' is of Type_Struct,
extract all fields of structure*/
if (field->type->is<IR::Type_Name>()) {
auto type_extern_params = extn->getTypeParameters()->parameters;
for (unsigned itr = 0; itr < type_extern_params.size(); itr++) {
if (type_extern_params.at(itr)->toString() == field->type->toString()) {
auto param_val = ts->arguments->at(itr);
if (auto param_struct = param_val->to<IR::Type_Struct>()) {
for (auto f : param_struct->fields) {
IR::TCKey *key = new IR::TCKey(kId++, f->type->width_bits(),
f->toString(), annoName);
keys.push_back(key);
}
} else {
IR::TCKey *key = new IR::TCKey(kId++, param_val->width_bits(),
field->toString(), annoName);
keys.push_back(key);
}
}
}
} else {
IR::TCKey *key =
new IR::TCKey(kId++, field->type->width_bits(), field->toString(), annoName);
keys.push_back(key);
}
}
}
return keys;
}

/* Process each declaration instance of externs*/
void ConvertToBackendIR::postorder(const IR::Declaration_Instance *decl) {
auto decl_type = typeMap->getType(decl, true);
if (auto ts = decl_type->to<IR::Type_SpecializedCanonical>()) {
if (auto extn = ts->baseType->to<IR::Type_Extern>()) {
auto eName = ts->baseType->toString();
// TODO: Enable template generation for other externs as well.
if (eName != "Register") return;
IR::TCExtern *externDefinition;
auto instance = new struct ExternInstance();
instance->instance_name = decl->toString();

processExternConstructorAnnotations(extn, decl, instance);

// Get Control Path information if specified for extern.
auto controlKeys = processExternControlPath(ts, extn, eName);

/* If the extern info is already present, add new instance
Or else create new extern info.*/
auto iterator = externsInfo.find(eName);
if (iterator == externsInfo.end()) {
struct ExternBlock *eb = new struct ExternBlock();
eb->externId = ++externCount;
eb->permissions = processExternPermission(extn);
eb->no_of_instances += 1;
externsInfo.emplace(eName, eb);

instance->instance_id = eb->no_of_instances;
eb->eInstance.push_back(instance);

externDefinition = new IR::TCExtern(eb->externId, eName, pipelineName,
eb->no_of_instances, eb->permissions);
tcPipeline->addExternDefinition(externDefinition);
} else {
auto eb = externsInfo[eName];
externDefinition = ((IR::TCExtern *)tcPipeline->getExternDefinition(eName));
externDefinition->numinstances = ++eb->no_of_instances;
instance->instance_id = eb->no_of_instances;
eb->eInstance.push_back(instance);
}
IR::TCExternInstance *tcExternInstance =
new IR::TCExternInstance(instance->instance_id, instance->instance_name,
instance->is_num_elements, instance->num_elements);
if (controlKeys.size() != 0) {
tcExternInstance->addControlPathKeys(controlKeys);
}
externDefinition->addExternInstance(tcExternInstance);
}
}
}

void ConvertToBackendIR::postorder(const IR::Type_Struct *ts) {
auto struct_name = ts->externalName();
auto cp = "tc_ControlPath_";
if (struct_name.startsWith(cp)) {
auto type_extern_name = struct_name.substr(strlen(cp));
ControlStructPerExtern.emplace(type_extern_name, ts);
}
}

void ConvertToBackendIR::postorder(const IR::P4Program *p) {
if (p != nullptr) {
tcPipeline->setPipelineName(pipelineName);
Expand Down Expand Up @@ -831,6 +1000,26 @@ unsigned ConvertToBackendIR::getActionId(cstring actionName) const {
return 0;
}

unsigned ConvertToBackendIR::getExternId(cstring externName) const {
for (auto e : externsInfo) {
if (e.first == externName) return e.second->externId;
}
return 0;
}

unsigned ConvertToBackendIR::getExternInstanceId(cstring externName, cstring instanceName) const {
for (auto e : externsInfo) {
if (e.first == externName) {
for (auto eI : e.second->eInstance) {
if (eI->instance_name == instanceName) {
return eI->instance_id;
}
}
}
}
return 0;
}

unsigned ConvertToBackendIR::getTableKeysize(unsigned tableId) const {
auto itr = tableKeysizeList.find(tableId);
if (itr != tableKeysizeList.end()) return itr->second;
Expand Down
30 changes: 29 additions & 1 deletion backends/tc/backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,19 @@ class PNAEbpfGenerator;
*/
class ConvertToBackendIR : public Inspector {
public:
struct ExternInstance {
cstring instance_name;
unsigned instance_id;
bool is_num_elements;
int num_elements;
};
struct ExternBlock {
unsigned externId;
cstring control_name;
unsigned no_of_instances;
cstring permissions;
safe_vector<struct ExternInstance *> eInstance;
};
const IR::ToplevelBlock *tlb;
IR::TCPipeline *tcPipeline;
P4::ReferenceMap *refMap;
Expand All @@ -56,6 +69,7 @@ class ConvertToBackendIR : public Inspector {
unsigned int actionCount = 0;
unsigned int metadataCount = 0;
unsigned int labelCount = 0;
unsigned int externCount = 0;
cstring pipelineName = nullptr;
cstring mainParserName = nullptr;
ordered_map<cstring, const IR::P4Action *> actions;
Expand All @@ -64,6 +78,8 @@ class ConvertToBackendIR : public Inspector {
ordered_map<unsigned, unsigned> tableKeysizeList;
safe_vector<const IR::P4Table *> add_on_miss_tables;
ordered_map<cstring, std::pair<cstring, cstring> *> tablePermissions;
ordered_map<cstring, const IR::Type_Struct *> ControlStructPerExtern;
ordered_map<cstring, struct ExternBlock *> externsInfo;

public:
ConvertToBackendIR(const IR::ToplevelBlock *tlb, IR::TCPipeline *pipe, P4::ReferenceMap *refMap,
Expand All @@ -75,7 +91,17 @@ class ConvertToBackendIR : public Inspector {
void postorder(const IR::P4Action *a) override;
void postorder(const IR::P4Table *t) override;
void postorder(const IR::P4Program *p) override;
void postorder(const IR::Declaration_Instance *d) override;
void postorder(const IR::Type_Struct *ts) override;
void processExternConstructorAnnotations(const IR::Type_Extern *extn,
const IR::Declaration_Instance *decl,
struct ExternInstance *instance);
safe_vector<const IR::TCKey *> processExternControlPath(const IR::Type_SpecializedCanonical *ts,
const IR::Type_Extern *extn,
cstring eName);
unsigned GetAccessNumericValue(cstring access);
bool isDuplicateAction(const IR::P4Action *action);
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);
Expand All @@ -89,11 +115,13 @@ class ConvertToBackendIR : public Inspector {
unsigned getTcType(const IR::StringLiteral *sl);
unsigned getTableId(cstring tableName) const;
unsigned getActionId(cstring actionName) const;
unsigned getExternId(cstring externName) const;
unsigned getExternInstanceId(cstring externName, cstring instanceName) const;
cstring processExternPermission(const IR::Type_Extern *ext);
unsigned getTableKeysize(unsigned tableId) const;
cstring externalName(const IR::IDeclaration *declaration) const;
cstring HandleTableAccessPermission(const IR::P4Table *t);
std::pair<cstring, cstring> *GetAnnotatedAccessPath(const IR::Annotation *anno);
unsigned GetAccessNumericValue(cstring access);
void updateAddOnMissTable(const IR::P4Table *t);
};

Expand Down
Loading

0 comments on commit cca2a12

Please sign in to comment.