Skip to content

Commit

Permalink
mplementation of Meter and DirectMeter in P4TC (#4884)
Browse files Browse the repository at this point in the history
Signed-off-by: Komal, Jain <komal.jain@intel.com>
  • Loading branch information
komaljai committed Sep 3, 2024
1 parent 3306162 commit c069b4c
Show file tree
Hide file tree
Showing 40 changed files with 3,944 additions and 88 deletions.
176 changes: 113 additions & 63 deletions backends/tc/backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,47 @@ void ConvertToBackendIR::updatePnaDirectCounter(const IR::P4Table *t, IR::TCTabl
}
}

void ConvertToBackendIR::updatePnaDirectMeter(const IR::P4Table *t, IR::TCTable *tabledef,
unsigned tentries) {
cstring propertyName = "pna_direct_meter"_cs;
auto property = t->properties->getProperty(propertyName);
if (property == nullptr) return;
auto expr = property->value->to<IR::ExpressionValue>()->expression;
auto ctrl = findContext<IR::P4Control>();
auto cName = ctrl->name.originalName;
auto externInstanceName = cName + "." + expr->toString();
tabledef->setDirectMeter(externInstanceName);

auto externInstance = P4::ExternInstance::resolve(expr, refMap, typeMap);
if (!externInstance) {
::P4::error(ErrorType::ERR_INVALID,
"Expected %1% property value for table %2% to resolve to an "
"extern instance: %3%",
propertyName, t->name.originalName, property);
return;
}
bool foundExtern = false;
for (auto ext : externsInfo) {
if (ext.first == externInstance->type->toString()) {
auto externDefinition = tcPipeline->getExternDefinition(ext.first);
if (externDefinition) {
auto extInstDef = ((IR::TCExternInstance *)externDefinition->getExternInstance(
externInstanceName));
extInstDef->setExternTableBindable(true);
extInstDef->setNumElements(tentries);
foundExtern = true;
break;
}
}
}
if (foundExtern == false) {
::P4::error(ErrorType::ERR_INVALID,
"Expected %1% property value for table %2% to resolve to an "
"extern instance: %3%",
propertyName, t->name.originalName, property);
}
}

void ConvertToBackendIR::updateAddOnMissTable(const IR::P4Table *t) {
auto tblname = t->name.originalName;
for (auto table : tcPipeline->tableDefs) {
Expand Down Expand Up @@ -778,6 +819,7 @@ void ConvertToBackendIR::postorder(const IR::P4Table *t) {
}
}
updatePnaDirectCounter(t, tableDefinition, tEntriesCount);
updatePnaDirectMeter(t, tableDefinition, tEntriesCount);
updateDefaultHitAction(t, tableDefinition);
updateDefaultMissAction(t, tableDefinition);
updateMatchType(t, tableDefinition);
Expand Down Expand Up @@ -1018,72 +1060,80 @@ bool ConvertToBackendIR::hasExecuteMethod(const IR::Type_Extern *extn) {
/* 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();
auto find = ControlStructPerExtern.find(eName);
if (find == ControlStructPerExtern.end()) {
return;
}
IR::TCExtern *externDefinition;
auto instance = new struct ExternInstance();
instance->instance_name = decl->toString();

auto constructorKeys = processExternConstructor(extn, decl, instance);

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

bool has_exec_method = hasExecuteMethod(extn);

/* 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();
if (eName == "DirectCounter") {
eb->externId = "0x1A000000"_cs;
} else if (eName == "Counter") {
eb->externId = "0x19000000"_cs;
} else if (eName == "Digest") {
eb->externId = "0x05000000"_cs;
instance->is_num_elements = true;
instance->num_elements = 0;
} else {
externCount += 1;
std::stringstream value;
value << "0x" << std::hex << externCount;
eb->externId = value.str();
}
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, has_exec_method);
tcPipeline->addExternDefinition(externDefinition);
auto ts = decl_type->to<IR::Type_SpecializedCanonical>();
if (decl_type->is<IR::Type_Extern>() || (ts && ts->baseType->is<IR::Type_Extern>())) {
const IR::Type_Extern *extn;
if (decl_type->is<IR::Type_Extern>()) {
extn = decl_type->to<IR::Type_Extern>();
} else {
extn = ts->baseType->to<IR::Type_Extern>();
}
auto eName = extn->name;
auto find = ControlStructPerExtern.find(eName);
if (find == ControlStructPerExtern.end()) {
return;
}
IR::TCExtern *externDefinition;
auto instance = new struct ExternInstance();
instance->instance_name = decl->toString();

auto constructorKeys = processExternConstructor(extn, decl, instance);

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

bool has_exec_method = hasExecuteMethod(extn);

/* 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();
if (eName == "DirectCounter") {
eb->externId = "0x1A000000"_cs;
} else if (eName == "Counter") {
eb->externId = "0x19000000"_cs;
} else if (eName == "Digest") {
eb->externId = "0x05000000"_cs;
instance->is_num_elements = true;
instance->num_elements = 0;
} else if (eName == "Meter") {
eb->externId = "0x1B000000"_cs;
} else if (eName == "DirectMeter") {
eb->externId = "0x1C000000"_cs;
} 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);
}
if (constructorKeys.size() != 0) {
tcExternInstance->addConstructorKeys(constructorKeys);
externCount += 1;
std::stringstream value;
value << "0x" << std::hex << externCount;
eb->externId = value.str();
}
externDefinition->addExternInstance(tcExternInstance);
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, has_exec_method);
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);
}
if (constructorKeys.size() != 0) {
tcExternInstance->addConstructorKeys(constructorKeys);
}
externDefinition->addExternInstance(tcExternInstance);
}
}

Expand Down
1 change: 1 addition & 0 deletions backends/tc/backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ class ConvertToBackendIR : public Inspector {
void updateMatchType(const IR::P4Table *t, IR::TCTable *tabledef);
void updateTimerProfiles(IR::TCTable *tabledef);
void updatePnaDirectCounter(const IR::P4Table *t, IR::TCTable *tabledef, unsigned tentries);
void updatePnaDirectMeter(const IR::P4Table *t, IR::TCTable *tabledef, unsigned tentries);
bool isPnaParserMeta(const IR::Member *mem);
bool isPnaMainInputMeta(const IR::Member *mem);
bool isPnaMainOutputMeta(const IR::Member *mem);
Expand Down
43 changes: 42 additions & 1 deletion backends/tc/ebpfCodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -873,7 +873,6 @@ void EBPFTablePNA::emitValueType(EBPF::CodeBuilder *builder) {
builder->blockStart();

emitValueStructStructure(builder);
emitDirectValueTypes(builder);

builder->blockEnd(false);
builder->endOfStatement(true);
Expand Down Expand Up @@ -1143,6 +1142,11 @@ void EBPFTablePNA::initDirectCounters() {
visitor.visitTableProperty();
}

void EBPFTablePNA::initDirectMeters() {
EBPFTablePNADirectMeterPropertyVisitor visitor(this);
visitor.visitTableProperty();
}

// =====================IngressDeparserPNA=============================
bool IngressDeparserPNA::build() {
auto pl = controlBlock->container->type->applyParams;
Expand Down Expand Up @@ -1482,6 +1486,12 @@ bool ConvertToEBPFControlPNA::preorder(const IR::ExternBlock *instance) {
control->addExternDeclaration = true;
auto ctr = new EBPFCounterPNA(program, di, name, control->codeGen);
control->counters.emplace(name, ctr);
} else if (typeName == "DirectMeter") {
control->addExternDeclaration = true;
} else if (typeName == "Meter") {
control->addExternDeclaration = true;
auto met = new EBPFMeterPNA(program, name, di, control->codeGen);
control->meters.emplace(name, met);
} else {
::P4::error(ErrorType::ERR_UNEXPECTED, "Unexpected block %s nested within control",
instance);
Expand Down Expand Up @@ -1974,6 +1984,12 @@ void ControlBodyTranslatorPNA::processMethod(const P4::ExternMethod *method) {
auto pna_ctr = dynamic_cast<EBPFCounterPNA *>(counterMap);
pna_ctr->emitMethodInvocation(builder, method, this);
return;
} else if (declType->name.name == "Meter") {
auto meter = control->to<EBPF::EBPFControlPSA>()->getMeter(name);
auto pna_meter = dynamic_cast<EBPFMeterPNA *>(meter);
::P4::warning(ErrorType::WARN_UNUSED, "This Meter (%1%) return value is not used!", name);
pna_meter->emitExecute(builder, method, this, nullptr);
return;
} else if (declType->name.name == "Hash") {
auto hash = control->to<EBPF::EBPFControlPSA>()->getHash(name);
hash->processMethod(builder, method->method->name.name, method->expr, this);
Expand Down Expand Up @@ -2019,6 +2035,18 @@ bool ControlBodyTranslatorPNA::preorder(const IR::AssignmentStatement *a) {
// Then the hash value is stored in a registerVar variable.
hash->calculateHash(builder, ext->expr, this);
builder->emitIndent();
} else if (ext->originalExternType->name.name == "Meter") {
cstring name = EBPF::EBPFObject::externalName(ext->object);
auto meter = control->to<EBPF::EBPFControlPSA>()->getMeter(name);
auto pna_meter = dynamic_cast<EBPFMeterPNA *>(meter);
pna_meter->emitExecute(builder, ext, this, a->left);
return false;
} else if (ext->originalExternType->name.name == "DirectMeter") {
cstring name = EBPF::EBPFObject::externalName(ext->object);
auto meter = table->getMeter(name);
auto pna_meter = dynamic_cast<EBPFMeterPNA *>(meter);
pna_meter->emitDirectMeterExecute(builder, ext, this, a->left);
return false;
}
}

Expand Down Expand Up @@ -2081,6 +2109,7 @@ void ActionTranslationVisitorPNA::processMethod(const P4::ExternMethod *method)
BUG_CHECK(decl->is<IR::Declaration_Instance>(), "Extern has not been declared: %1%", decl);
auto di = decl->to<IR::Declaration_Instance>();
auto instanceName = EBPF::EBPFObject::externalName(di);
cstring name = EBPF::EBPFObject::externalName(decl);

if (declType->name.name == "DirectCounter") {
auto ctr = table->getDirectCounter(instanceName);
Expand All @@ -2091,6 +2120,18 @@ void ActionTranslationVisitorPNA::processMethod(const P4::ExternMethod *method)
::P4::error(ErrorType::ERR_NOT_FOUND,
"%1%: Table %2% does not own DirectCounter named %3%", method->expr,
table->table->container, instanceName);
} else if (declType->name.name == "DirectMeter") {
auto met = table->getMeter(instanceName);
auto pna_meter = dynamic_cast<EBPFMeterPNA *>(met);
if (pna_meter != nullptr) {
::P4::warning(ErrorType::WARN_UNUSED, "This Meter (%1%) return value is not used!",
name);
pna_meter->emitDirectMeterExecute(builder, method, this, nullptr);
} else {
::P4::error(ErrorType::ERR_NOT_FOUND,
"%1%: Table %2% does not own DirectMeter named %3%", method->expr,
table->table->container, instanceName);
}
} else {
ControlBodyTranslatorPNA::processMethod(method);
}
Expand Down
3 changes: 3 additions & 0 deletions backends/tc/ebpfCodeGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,15 @@ class EBPFTablePNA : public EBPF::EBPFTablePSA {
bool isDefaultAction) const;
void validateKeys() const override;
void initDirectCounters();
void initDirectMeters();
const ConvertToBackendIR *tcIR;

public:
EBPFTablePNA(const EBPF::EBPFProgram *program, const IR::TableBlock *table,
EBPF::CodeGenInspector *codeGen, const ConvertToBackendIR *tcIR)
: EBPF::EBPFTablePSA(program, table, codeGen), tcIR(tcIR) {
initDirectCounters();
initDirectMeters();
}
void emitInitializer(EBPF::CodeBuilder *builder) override;
void emitDefaultActionStruct(EBPF::CodeBuilder *builder);
Expand Down Expand Up @@ -295,6 +297,7 @@ class EBPFControlPNA : public EBPF::EBPFControlPSA {
builder->appendLine("struct p4tc_ext_bpf_val *ext_val_ptr;");
}
}
void emitTableTypes(EBPF::CodeBuilder *builder) { EBPF::EBPFControl::emitTableTypes(builder); }
};

// Similar to class ConvertToEBPFControlPSA in backends/ebpf/psa/ebpfPsaGen.h
Expand Down
39 changes: 25 additions & 14 deletions backends/tc/runtime/pna.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ xdp_p4tc_entry_delete(struct xdp_md *xdp_ctx,

#define P4TC_EXT_CNT_DIRECT 0x1
#define P4TC_EXT_CNT_INDIRECT 0x2
#define P4TC_EXT_METER_DIRECT (1 << 2)
#define P4TC_EXT_METER_INDIRECT (1 << 3)

struct p4tc_ext_bpf_params {
u32 pipe_id;
Expand Down Expand Up @@ -228,34 +230,43 @@ xdp_p4tc_extern_indirect_count_bytesonly(struct xdp_md *xdp_ctx,

extern int bpf_p4tc_extern_meter_bytes_color(struct __sk_buff *skb_ctx,
struct p4tc_ext_bpf_params *params,
const u32 params__sz) __ksym;

extern int bpf_p4tc_extern_meter_bytes(struct __sk_buff *skb_ctx,
struct p4tc_ext_bpf_params *params,
const u32 params__sz) __ksym;
const u32 params__sz, void *key,
const u32 key__sz) __ksym;
extern int
bpf_p4tc_extern_meter_bytes(struct __sk_buff *skb,
struct p4tc_ext_bpf_params *params,
const u32 params__sz, void *key,
const u32 key__sz) __ksym;

extern int bpf_p4tc_extern_meter_pkts_color(struct __sk_buff *skb_ctx,
struct p4tc_ext_bpf_params *params,
const u32 params__sz) __ksym;

extern int xdp_p4tc_extern_meter_pkts(struct xdp_md *xdp_ctx,
struct p4tc_ext_bpf_params *params,
const u32 params__sz) __ksym;
const u32 params__sz, void *key,
const u32 key__sz) __ksym;
extern int
bpf_p4tc_extern_meter_pkts(struct __sk_buff *skb,
struct p4tc_ext_bpf_params *params,
const u32 params__sz, void *key,
const u32 key__sz) __ksym;

extern int xdp_p4tc_extern_meter_bytes_color(struct xdp_md *xdp_ctx,
const u32 params__sz) __ksym;
struct p4tc_ext_bpf_params *params,
const u32 params__sz, void *key,
const u32 key__sz) __ksym;

extern int xdp_p4tc_extern_meter_bytes(struct xdp_md *xdp_ctx,
struct p4tc_ext_bpf_params *params,
const u32 params__sz) __ksym;
const u32 params__sz, void *key,
const u32 key__sz) __ksym;

extern int xdp_p4tc_extern_meter_pkts_color(struct xdp_md *xdp_ctx,
struct p4tc_ext_bpf_params *params,
const u32 params__sz) __ksym;
const u32 params__sz, void *key,
const u32 key__sz) __ksym;

extern int xdp_p4tc_extern_meter_pkts(struct xdp_md *xdp_ctx,
struct p4tc_ext_bpf_params *params,
const u32 params__sz) __ksym;
const u32 params__sz, void *key,
const u32 key__sz) __ksym;

/* Start checksum related kfuncs */
struct p4tc_ext_csum_params {
Expand Down
Loading

0 comments on commit c069b4c

Please sign in to comment.