Skip to content

Commit

Permalink
Implementation to add permisson annotation 'tc_acl' to P4Tables.
Browse files Browse the repository at this point in the history
  • Loading branch information
komaljai committed Apr 10, 2024
1 parent 24b0cd8 commit ebedafc
Show file tree
Hide file tree
Showing 53 changed files with 1,212 additions and 97 deletions.
125 changes: 116 additions & 9 deletions backends/tc/backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,109 @@ void ConvertToBackendIR::updateDefaultHitAction(const IR::P4Table *t, IR::TCTabl
}
}

void ConvertToBackendIR::updateAddOnMissTable(const IR::P4Table *t) {
auto tblname = t->name.originalName;
for (auto table : tcPipeline->tableDefs) {
if (table->tableName == tblname) {
add_on_miss_tables.push_back(t);
auto tableDefinition = ((IR::TCTable *)table);
tableDefinition->setTableAddOnMiss();
tableDefinition->setTablePermisson(HandleTableAccessPermisson(t));
}
}
}

unsigned ConvertToBackendIR::GetAccessNumericValue(cstring access) {
unsigned value = 0;
for (auto s : access) {
unsigned mask = 0;
switch (s) {
case 'C':
mask = 1 << 6;
break;
case 'R':
mask = 1 << 5;
break;
case 'U':
mask = 1 << 4;
break;
case 'D':
mask = 1 << 3;
break;
case 'X':
mask = 1 << 2;
break;
case 'P':
mask = 1 << 1;
break;
case 'S':
mask = 1;
break;
default:
::error(ErrorType::ERR_INVALID,
"tc_acl annotation cannot have '%1%' in access permisson", s);
}
value |= mask;
}
return value;
}

cstring ConvertToBackendIR::HandleTableAccessPermisson(const IR::P4Table *t) {
bool unused_ps[14], IsTableAddOnMiss = false;
cstring control_path, data_path;
memset(unused_ps, true, 14);
for (auto table : add_on_miss_tables) {
if (table->name.originalName == t->name.originalName) {
IsTableAddOnMiss = true;
}
}
auto find = tablePermissons.find(t->name.originalName);
if (find != tablePermissons.end()) {
auto paths = tablePermissons[t->name.originalName];
control_path = paths.first;
data_path = paths.second;
}
// Default access value of Control_path and Data_Path
if (control_path.isNullOrEmpty()) {
control_path = IsTableAddOnMiss ? DEFAULT_ADD_ON_MISS_TABLE_CONTROL_PATH_ACCESS
: DEFAULT_TABLE_CONTROL_PATH_ACCESS;
}
if (data_path.isNullOrEmpty()) {
data_path = IsTableAddOnMiss ? DEFAULT_ADD_ON_MISS_TABLE_DATA_PATH_ACCESS
: DEFAULT_TABLE_DATA_PATH_ACCESS;
}

if (IsTableAddOnMiss) {
auto access = data_path.find('C');
if (access == nullptr) {
::warning(
ErrorType::WARN_INVALID,
"Add on miss table '%1%' should have 'create' access permissons for data path.",
t->name.originalName);
}
}
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();
}

std::pair<cstring, cstring> ConvertToBackendIR::GetAnnotatedAccessPath(const IR::Annotation *anno) {
cstring control_path, data_path;
if (anno) {
auto expr = anno->expr[0];
if (auto typeLiteral = expr->to<IR::StringLiteral>()) {
auto permisson_str = typeLiteral->value;
auto char_pos = permisson_str.find(":");
control_path = permisson_str.before(char_pos);
data_path = permisson_str.substr(char_pos - permisson_str.begin() + 1);
}
}
return std::make_pair<cstring, cstring>(std::move(control_path), std::move(data_path));
}

void ConvertToBackendIR::postorder(const IR::P4Table *t) {
if (t != nullptr) {
tableCount++;
Expand Down Expand Up @@ -551,17 +654,21 @@ void ConvertToBackendIR::postorder(const IR::P4Table *t) {
tableKeysizeList.emplace(tId, keySize);
auto annoList = t->getAnnotations()->annotations;
for (auto anno : annoList) {
if (anno->name != ParseTCAnnotations::numMask) continue;
auto expr = anno->expr[0];
if (auto val = expr->to<IR::Constant>()) {
tableDefinition->setNumMask(val->asUint64());
} else {
::error(ErrorType::ERR_INVALID,
"nummask annotation cannot have '%1%' as value. Only integer "
"constants are allowed",
expr);
if (anno->name == ParseTCAnnotations::tc_acl) {
tablePermissons.emplace(t->name.originalName, GetAnnotatedAccessPath(anno));
} else if (anno->name == ParseTCAnnotations::numMask) {
auto expr = anno->expr[0];
if (auto val = expr->to<IR::Constant>()) {
tableDefinition->setNumMask(val->asUint64());
} else {
::error(ErrorType::ERR_INVALID,
"nummask annotation cannot have '%1%' as value. Only integer "
"constants are allowed",
expr);
}
}
}
tableDefinition->setTablePermisson(HandleTableAccessPermisson(t));
auto actionlist = t->getActionList();
for (auto action : actionlist->actionList) {
for (auto actionDef : tcPipeline->actionDefs) {
Expand Down
13 changes: 6 additions & 7 deletions backends/tc/backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ class ConvertToBackendIR : public Inspector {
ordered_map<unsigned, cstring> tableIDList;
ordered_map<unsigned, cstring> actionIDList;
ordered_map<unsigned, unsigned> tableKeysizeList;
safe_vector<const IR::P4Table *> add_on_miss_tables;
ordered_map<cstring, std::pair<cstring, cstring>> tablePermissons;

public:
ConvertToBackendIR(const IR::ToplevelBlock *tlb, IR::TCPipeline *pipe, P4::ReferenceMap *refMap,
Expand Down Expand Up @@ -89,13 +91,10 @@ 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();
}
}
}
cstring HandleTableAccessPermisson(const IR::P4Table *t);
std::pair<cstring, cstring> GetAnnotatedAccessPath(const IR::Annotation *anno);
unsigned GetAccessNumericValue(cstring access);
void updateAddOnMissTable(const IR::P4Table *t);
};

class Extern {
Expand Down
3 changes: 1 addition & 2 deletions backends/tc/ebpfCodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1525,7 +1525,6 @@ void ControlBodyTranslatorPNA::ValidateAddOnMissMissAction(const IR::P4Action *a
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);
Expand All @@ -1539,7 +1538,7 @@ void ControlBodyTranslatorPNA::ValidateAddOnMissMissAction(const IR::P4Action *a
"add_entry extern can only be used in an action"
" of a table with property add_on_miss equals to true.");
}
tcIR->updateAddOnMissTable(tblname);
((ConvertToBackendIR *)tcIR)->updateAddOnMissTable(t);
}

void ControlBodyTranslatorPNA::processFunction(const P4::ExternFunction *function) {
Expand Down
12 changes: 7 additions & 5 deletions backends/tc/tc.def
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ class TCTable {
cstring tableName;
cstring controlName;
cstring pipelineName;
cstring permissions;
unsigned keySize;
unsigned tableEntriesCount;
unsigned numMask;
Expand All @@ -244,6 +245,9 @@ class TCTable {
ordered_map<TCAction, unsigned> actionList;
safe_vector<TCEntry> const_entries;

void setTablePermisson(cstring p) {
permissions = p;
}
void setKeySize(unsigned k) {
keySize = k;
}
Expand Down Expand Up @@ -326,12 +330,10 @@ class TCTable {
tcTable += "\n\ttype " + printMatchType(matchType) + " \\";
tcTable += "\n\tkeysz " + Util::toString(keySize);
tcTable += " nummasks " + Util::toString(numMask);
tcTable += " permissions " + Util::toString(permissions);
tcTable += " tentries " + Util::toString(tableEntriesCount);
if (isTableAddOnMiss) {
tcTable += " permissions 0x3DE6";
if(timerProfiles > defaultTimerProfiles) {
tcTable += " num_timer_profiles " + Util::toString(timerProfiles);
}
if (isTableAddOnMiss && timerProfiles > defaultTimerProfiles) {
tcTable += " num_timer_profiles " + Util::toString(timerProfiles);
}

if (!actionList.empty()) {
Expand Down
1 change: 1 addition & 0 deletions backends/tc/tcAnnotations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@ const cstring ParseTCAnnotations::defaultHitConst = "default_hit_const";
const cstring ParseTCAnnotations::tcType = "tc_type";
const cstring ParseTCAnnotations::numMask = "nummask";
const cstring ParseTCAnnotations::tcMayOverride = "tc_may_override";
const cstring ParseTCAnnotations::tc_acl = "tc_acl";

} // namespace TC
3 changes: 2 additions & 1 deletion backends/tc/tcAnnotations.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@ class ParseTCAnnotations : public P4::ParseAnnotations {
static const cstring tcType;
static const cstring numMask;
static const cstring tcMayOverride;
static const cstring tc_acl;
ParseTCAnnotations()
: P4::ParseAnnotations(
"TC", true,
{PARSE_EMPTY(defaultHit), PARSE_EMPTY(defaultHitConst),
PARSE_CONSTANT_OR_STRING_LITERAL(tcType), PARSE_CONSTANT_OR_STRING_LITERAL(numMask),
PARSE_EMPTY(tcMayOverride)}) {}
PARSE_EMPTY(tcMayOverride), PARSE_CONSTANT_OR_STRING_LITERAL(tc_acl)}) {}
};

} // namespace TC
Expand Down
6 changes: 6 additions & 0 deletions backends/tc/tc_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ inline constexpr auto DEFAULT_METADATA_ID = 1;
inline constexpr auto BITWIDTH = 32;
inline constexpr auto DEFAULT_TIMER_PROFILES = 4;

// Default Access Permissons
inline constexpr auto DEFAULT_TABLE_CONTROL_PATH_ACCESS = "CDPS";
inline constexpr auto DEFAULT_TABLE_DATA_PATH_ACCESS = "RX";
inline constexpr auto DEFAULT_ADD_ON_MISS_TABLE_CONTROL_PATH_ACCESS = "CRUDPS";
inline constexpr auto DEFAULT_ADD_ON_MISS_TABLE_DATA_PATH_ACCESS = "CRXP";

// Supported data types.
inline constexpr auto BIT_TYPE = 0;
inline constexpr auto DEV_TYPE = 1;
Expand Down
2 changes: 1 addition & 1 deletion testdata/p4tc_samples/add_entry_1_example.p4
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ control MainControlImpl(
drop_packet();
}

table ipv4_tbl_1 {
@tc_acl("CRUS:CRXP") table ipv4_tbl_1 {
key = {
hdr.ipv4.dstAddr : exact @tc_type ("ipv4");
istd.input_port : exact;
Expand Down
131 changes: 131 additions & 0 deletions testdata/p4tc_samples/add_entry_3_example.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#include <core.p4>
#include <tc/pna.p4>

typedef bit<48> EthernetAddress;

header ethernet_t {
EthernetAddress dstAddr;
@tc_type("macaddr") EthernetAddress 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;
@tc_type ("ipv4") bit<32> srcAddr;
@tc_type ("ipv4") bit<32> dstAddr;
}

//////////////////////////////////////////////////////////////////////
// Struct types for holding user-defined collections of headers and
// metadata in the P4 developer's program.
//
// Note: The names of these struct types are completely up to the P4
// developer, as are their member fields, with the only restriction
// being that the structs intended to contain headers should only
// contain members whose types are header, header stack, or
// header_union.
//////////////////////////////////////////////////////////////////////

struct main_metadata_t {
// empty for this skeleton
}

// User-defined struct containing all of those headers parsed in the
// main parser.
struct headers_t {
ethernet_t ethernet;
ipv4_t ipv4;
}

const ExpireTimeProfileId_t EXPIRE_TIME_PROFILE_NOW = (ExpireTimeProfileId_t) 2;

parser MainParserImpl(
packet_in pkt,
out headers_t hdr,
inout main_metadata_t main_meta,
in pna_main_parser_input_metadata_t istd)
{
state start {
pkt.extract(hdr.ethernet);
transition select(hdr.ethernet.etherType) {
0x0800 : parse_ipv4;
default : accept;
}
}
state parse_ipv4 {
pkt.extract(hdr.ipv4);
transition accept;
}
}

control MainControlImpl(
inout headers_t hdr, // from main parser
inout main_metadata_t user_meta, // from main parser, to "next block"
in pna_main_input_metadata_t istd,
inout pna_main_output_metadata_t ostd)
{
action send_nh( @tc_type("macaddr") bit<48> dmac, bit<48> smac) {
hdr.ethernet.srcAddr = smac;
hdr.ethernet.dstAddr = dmac;
}
action next_hop() {
add_entry(action_name = "send_nh", // name of action
action_params = {hdr.ethernet.dstAddr, hdr.ethernet.srcAddr}, expire_time_profile_id = EXPIRE_TIME_PROFILE_NOW);

}

action dflt_route_drop() {
drop_packet();
}
action drop() {
drop_packet();
}

@tc_acl("CRUS:RXP") table ipv4_tbl_1 {
key = {
hdr.ipv4.dstAddr : exact @tc_type ("ipv4");
istd.input_port : exact;
}
actions = {
next_hop;
send_nh;
dflt_route_drop;
}
default_action = next_hop;
}

apply {
if (hdr.ipv4.isValid()) {
ipv4_tbl_1.apply();
}
}
}

control MainDeparserImpl(
packet_out pkt,
inout headers_t hdr, // from main control
in main_metadata_t user_meta, // from main control
in pna_main_output_metadata_t ostd)
{
apply {
pkt.emit(hdr.ethernet);
pkt.emit(hdr.ipv4);
}
}

// BEGIN:Package_Instantiation_Example
PNA_NIC(
MainParserImpl(),
MainControlImpl(),
MainDeparserImpl()
) main;
// END:Package_Instantiation_Example
Loading

0 comments on commit ebedafc

Please sign in to comment.