Skip to content

Commit

Permalink
Implemented Counter extern in p4tc (#4734)
Browse files Browse the repository at this point in the history
  • Loading branch information
komaljai authored Jun 20, 2024
1 parent ef0657a commit 6ae2ebe
Show file tree
Hide file tree
Showing 23 changed files with 971 additions and 26 deletions.
13 changes: 9 additions & 4 deletions backends/tc/backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1037,9 +1037,14 @@ void ConvertToBackendIR::postorder(const IR::Declaration_Instance *decl) {
if (iterator == externsInfo.end()) {
struct ExternBlock *eb = new struct ExternBlock();
if (eName == "DirectCounter") {
eb->externId = 101;
eb->externId = "0x1A000000"_cs;
} else if (eName == "Counter") {
eb->externId = "0x19000000"_cs;
} else {
eb->externId = ++externCount;
externCount += 1;
std::stringstream value;
value << "0x" << std::hex << externCount;
eb->externId = value.str();
}
eb->permissions = processExternPermission(extn);
eb->no_of_instances += 1;
Expand Down Expand Up @@ -1200,11 +1205,11 @@ unsigned ConvertToBackendIR::getActionId(cstring actionName) const {
return 0;
}

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

unsigned ConvertToBackendIR::getExternInstanceId(cstring externName, cstring instanceName) const {
Expand Down
4 changes: 2 additions & 2 deletions backends/tc/backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class ConvertToBackendIR : public Inspector {
int num_elements;
};
struct ExternBlock {
unsigned externId;
cstring externId;
cstring control_name;
unsigned no_of_instances;
cstring permissions;
Expand Down Expand Up @@ -119,7 +119,7 @@ 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;
cstring getExternId(cstring externName) const;
unsigned getExternInstanceId(cstring externName, cstring instanceName) const;
cstring processExternPermission(const IR::Type_Extern *ext);
unsigned getTableKeysize(unsigned tableId) const;
Expand Down
9 changes: 9 additions & 0 deletions backends/tc/ebpfCodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1456,6 +1456,10 @@ bool ConvertToEBPFControlPNA::preorder(const IR::ExternBlock *instance) {
} else if (typeName == "DirectCounter") {
control->addExternDeclaration = true;
return false;
} else if (typeName == "Counter") {
control->addExternDeclaration = true;
auto ctr = new EBPFCounterPNA(program, di, name, control->codeGen);
control->counters.emplace(name, ctr);
} else {
::error(ErrorType::ERR_UNEXPECTED, "Unexpected block %s nested within control", instance);
}
Expand Down Expand Up @@ -1940,6 +1944,11 @@ void ControlBodyTranslatorPNA::processMethod(const P4::ExternMethod *method) {
reg->emitRegisterRead(builder, method, this, nullptr);
}
return;
} else if (declType->name.name == "Counter") {
auto counterMap = control->getCounter(name);
auto pna_ctr = dynamic_cast<EBPFCounterPNA *>(counterMap);
pna_ctr->emitMethodInvocation(builder, method, this);
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
2 changes: 1 addition & 1 deletion backends/tc/introspection.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ struct ExternInstancesAttributes {
struct ExternAttributes {
cstring name;
cstring permissions;
unsigned int id;
cstring id;
safe_vector<struct ExternInstancesAttributes *> instances;
ExternAttributes() {
name = nullptr;
Expand Down
6 changes: 3 additions & 3 deletions backends/tc/tc.def
Original file line number Diff line number Diff line change
Expand Up @@ -529,11 +529,11 @@ class TCExtern {
cstring externName;
cstring pipelineName;
cstring acl_permisson;
unsigned externID;
cstring externID;
unsigned numinstances;
safe_vector<TCExternInstance> externInstances;
bool has_exec_method;
TCExtern(unsigned eId, cstring eN, cstring pN, unsigned inst, cstring p, bool exec_method) {
TCExtern(cstring eId, cstring eN, cstring pN, unsigned inst, cstring p, bool exec_method) {
externID = eId;
externName = eN;
pipelineName = pN;
Expand All @@ -556,7 +556,7 @@ class TCExtern {
std::string tcExtern = "";
tcExtern += "\n$TC p4template create extern/";
tcExtern += "root/" + externName;
tcExtern += " extid " + Util::toString(externID);
tcExtern += " extid " + externID;
tcExtern += " numinstances " + Util::toString(numinstances);
tcExtern += " tc_acl " + acl_permisson;
if (has_exec_method) {
Expand Down
57 changes: 55 additions & 2 deletions backends/tc/tcExterns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ void EBPFRegisterPNA::emitInitializer(EBPF::CodeBuilder *builder, const P4::Exte
builder->appendLine("ext_params.pipe_id = p4tc_filter_fields.pipeid;");
builder->emitIndent();
auto extId = translator->tcIR->getExternId(externName);
BUG_CHECK(extId != 0, "Extern ID not found");
builder->appendFormat("ext_params.ext_id = %d;", extId);
BUG_CHECK(!extId.isNullOrEmpty(), "Extern ID not found");
builder->appendFormat("ext_params.ext_id = %s;", extId);
builder->newline();
builder->emitIndent();
auto instId = translator->tcIR->getExternInstanceId(externName, this->instanceName);
Expand Down Expand Up @@ -126,4 +126,57 @@ void EBPFCounterPNA::emitCounterUpdate(EBPF::CodeBuilder *builder, const Convert
}
}

void EBPFCounterPNA::emitMethodInvocation(EBPF::CodeBuilder *builder,
const P4::ExternMethod *method,
ControlBodyTranslatorPNA *translator) {
if (method->method->name.name != "count") {
::error(ErrorType::ERR_UNSUPPORTED, "Unexpected method %1%", method->expr);
return;
}
BUG_CHECK(!isDirect, "DirectCounter used outside of table");
BUG_CHECK(method->expr->arguments->size() == 1, "Expected just 1 argument for %1%",
method->expr);
emitCount(builder, method, translator);
}

void EBPFCounterPNA::emitCount(EBPF::CodeBuilder *builder, const P4::ExternMethod *method,
ControlBodyTranslatorPNA *translator) {
builder->emitIndent();
builder->appendLine("__builtin_memset(&ext_params, 0, sizeof(struct p4tc_ext_bpf_params));");
builder->emitIndent();
builder->appendLine("ext_params.pipe_id = p4tc_filter_fields.pipeid;");
auto externName = method->originalExternType->name.name;
auto instanceName = di->toString();
auto index = method->expr->arguments->at(0)->expression;
builder->emitIndent();
auto extId = translator->tcIR->getExternId(externName);
BUG_CHECK(!extId.isNullOrEmpty(), "Extern ID not found");
builder->appendFormat("ext_params.ext_id = %s;", extId);
builder->newline();
builder->emitIndent();
auto instId = translator->tcIR->getExternInstanceId(externName, instanceName);
BUG_CHECK(instId != 0, "Extern instance ID not found");
builder->appendFormat("ext_params.inst_id = %d;", instId);
builder->newline();
builder->emitIndent();
builder->append("ext_params.index = ");
translator->visit(index);
builder->endOfStatement(true);
builder->newline();
builder->emitIndent();
builder->appendLine("ext_params.flags = P4TC_EXT_CNT_INDIRECT;");
builder->emitIndent();

if (type == CounterType::BYTES) {
builder->append(
"bpf_p4tc_extern_count_bytes(skb, &ext_params, sizeof(ext_params), NULL, 0)");
} else if (type == CounterType::PACKETS) {
builder->append(
"bpf_p4tc_extern_count_pkts(skb, &ext_params, sizeof(ext_params), NULL, 0)");
} else if (type == CounterType::PACKETS_AND_BYTES) {
builder->append(
"bpf_p4tc_extern_count_pktsnbytes(skb, &ext_params, sizeof(ext_params), NULL, 0)");
}
}

} // namespace TC
12 changes: 12 additions & 0 deletions backends/tc/tcExterns.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,29 @@ class ControlBodyTranslatorPNA;
class ConvertToBackendIR;

class EBPFCounterPNA : public EBPF::EBPFCounterPSA {
const IR::Declaration_Instance *di;
cstring tblname;

public:
EBPFCounterPNA(const EBPF::EBPFProgram *program, const IR::Declaration_Instance *di,
cstring name, EBPF::CodeGenInspector *codeGen, cstring tblname)
: EBPF::EBPFCounterPSA(program, di, name, codeGen) {
this->tblname = tblname;
this->di = di;
}
EBPFCounterPNA(const EBPF::EBPFProgram *program, const IR::Declaration_Instance *di,
cstring name, EBPF::CodeGenInspector *codeGen)
: EBPF::EBPFCounterPSA(program, di, name, codeGen) {
this->di = di;
}

void emitDirectMethodInvocation(EBPF::CodeBuilder *builder, const P4::ExternMethod *method,
const ConvertToBackendIR *tcIR);
void emitMethodInvocation(EBPF::CodeBuilder *builder, const P4::ExternMethod *method,
ControlBodyTranslatorPNA *translator);
virtual void emitCounterUpdate(EBPF::CodeBuilder *builder, const ConvertToBackendIR *tcIR);
virtual void emitCount(EBPF::CodeBuilder *builder, const P4::ExternMethod *method,
ControlBodyTranslatorPNA *translator);
};

class EBPFRegisterPNA : public EBPF::EBPFTableBase {
Expand Down
12 changes: 9 additions & 3 deletions p4include/tc/pna.p4
Original file line number Diff line number Diff line change
Expand Up @@ -437,13 +437,19 @@ enum PNA_CounterType_t {
/// Indirect counter with n_counters independent counter values, where
/// every counter value has a data plane size specified by type W.

@noWarn("unused")
@noWarn("unused") @tc_acl("RP:RUXP")
extern Counter<W, S> {
Counter(bit<32> n_counters, PNA_CounterType_t type);
void count(in S index);
Counter(@tc_numel bit<32> n_counters, PNA_CounterType_t type);
@tc_md_exec void count(in S index);
}
// END:Counter_extern

struct tc_ControlPath_Counter<W, S> {
@tc_key S index;
@tc_data W pkts;
@tc_data W bytes;
}

// BEGIN:DirectCounter_extern
@noWarn("unused") @tc_acl("RP:RUXP")
extern DirectCounter<W> {
Expand Down
130 changes: 130 additions & 0 deletions testdata/p4tc_samples/indirect_counter_01_example.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/* -*- P4_16 -*- */

#include <core.p4>
#include <tc/pna.p4>

#define PORT_TABLE_SIZE 2048

/*
* Standard ethernet header
*/
header ethernet_t {
@tc_type ("macaddr") bit<48> dstAddr;
@tc_type ("macaddr") bit<48> 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;
bit<32> srcAddr;
bit<32> dstAddr;
}

struct my_ingress_headers_t {
ethernet_t ethernet;
ipv4_t ipv4;
}

/****** G L O B A L I N G R E S S M E T A D A T A *********/

struct my_ingress_metadata_t {
}

struct empty_metadata_t {
}

/*********************** P A R S E R **************************/

parser Ingress_Parser(
packet_in pkt,
out my_ingress_headers_t hdr,
inout my_ingress_metadata_t meta,
in pna_main_parser_input_metadata_t istd)
{
const bit<16> ETHERTYPE_IPV4 = 0x0800;

state start {
transition parse_ethernet;
}
state parse_ethernet {
pkt.extract(hdr.ethernet);
transition select(hdr.ethernet.etherType) {
ETHERTYPE_IPV4 : parse_ipv4;
default : reject;
}
}
state parse_ipv4 {
pkt.extract(hdr.ipv4);
transition accept;
}
}

/***************** M A T C H - A C T I O N *********************/

typedef bit<64> PacketByteCounter_t;

control ingress(
inout my_ingress_headers_t hdr,
inout my_ingress_metadata_t meta,
in pna_main_input_metadata_t istd,
inout pna_main_output_metadata_t ostd
)
{
Counter<bit<64>, bit<32>>(2048, PNA_CounterType_t.PACKETS) global_counter;

action send_nh(@tc_type("dev") PortId_t port_id, @tc_type("macaddr") bit<48> dmac, @tc_type("macaddr") bit<48> smac) {
hdr.ethernet.srcAddr = smac;
hdr.ethernet.dstAddr = dmac;
send_to_port(port_id);
global_counter.count(3);
}
action drop() {
drop_packet();
}
@tc_acl("CRUDPS:RX") table nh_table {
key = {
hdr.ipv4.srcAddr : exact @tc_type ("ipv4");
}
actions = {
send_nh;
drop;
}
size = PORT_TABLE_SIZE;
const default_action = drop;
}

apply {
nh_table.apply();
}
}

/********************* D E P A R S E R ************************/

control Ingress_Deparser(
packet_out pkt,
inout my_ingress_headers_t hdr,
in my_ingress_metadata_t meta,
in pna_main_output_metadata_t ostd)
{
apply {
pkt.emit(hdr.ethernet);
pkt.emit(hdr.ipv4);
}
}

/************ F I N A L P A C K A G E ******************************/

PNA_NIC(
Ingress_Parser(),
ingress(),
Ingress_Deparser()
) main;
2 changes: 1 addition & 1 deletion testdata/p4tc_samples_outputs/direct_counter_example.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"externs" : [
{
"name" : "DirectCounter",
"id" : 101,
"id" : "0x1A000000",
"permissions" : "0x1136",
"instances" : [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ $TC p4template update action/direct_counter_example/ingress/send_nh state active
$TC p4template create action/direct_counter_example/ingress/drop actid 2
$TC p4template update action/direct_counter_example/ingress/drop state active

$TC p4template create extern/root/DirectCounter extid 101 numinstances 1 tc_acl 0x1136 has_exec_method
$TC p4template create extern/root/DirectCounter extid 0x1A000000 numinstances 1 tc_acl 0x1136 has_exec_method

$TC p4template create extern_inst/direct_counter_example/DirectCounter/ingress.global_counter instid 1 \
tc_numel 2048 tbl_bindable constructor param type ptype bit32 0 \
Expand Down
Loading

0 comments on commit 6ae2ebe

Please sign in to comment.