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: Direct counter and direct meter support #3631

Merged
merged 8 commits into from
Nov 4, 2022

Conversation

usha1830
Copy link
Contributor

This PR adds support for DirectCounter and DirectMeter extern in .spec file and context json output files for dpdk compiler

In the spec file

  • For direct counter , a new regarray is declared for direct counter extern with size equal to the owner table size + 1 for regular tables and table_size *4 + 1 for learner tables.
  • Similarly, for direct meter, a new metarray is declared for direct counter extern with size equal to the owner table size + 1 for regular tables and table_size *4 + 1 for learner tables.

For the count method of direct counter, the following instructions should be emitted.

entryid m.table_entry_index
regadd per_prefix_pkt_bytes_count_0_packets m.table_entry_index 1

In case of PACKETS_AND_BYTES counter, two regarrays should be emitted with the counter name suffixed with "_packets" and "_bytes"
Similarly, the count method also should have "regadd" instruction for packets and bytes counter.

For the execute method of direct meter, the following instructions should be emitted.

entryid m.table_entry_index
meter <metername> m.table_entry_index <packet_length> <color_in> <color_out>

Following tests are added:

  • Valid case for regular table using Direct Counter
  • Valid case for regular table using Direct Meter
  • Valid case for learner table using Direct Counter
  • Valid case for learner table using Direct Meter
  • Error cases for coexistence of action selector and direct counter/direct meter
  • Error for default action not having count/execute method
  • Error for calling count/execute of multiple extern instances in same action
  • Error for calling count/execute from non-owner table action
  • Error for using Direct Meter/Direct Counter extern with tables having wildcard/lpm match kind
  • Error for calling count/execute from apply block

@jfingerh
Copy link

@usha1830 Out of curiosity, why "table_size *4 + 1 for learner tables" ? Why not "table_size + 1" for learner tables?

@usha1830
Copy link
Contributor Author

@usha1830 Out of curiosity, why "table_size *4 + 1 for learner tables" ? Why not "table_size + 1" for learner tables?

This is based on internal implementation in dpdk target. There are 4 buckets for each index.
Reference : https://git.dpdk.org/dpdk/tree/lib/table/rte_swx_table_learner.c#n243

@@ -61,7 +61,7 @@ action next_hop2 args instanceof next_hop2_arg_t {

action add_on_miss_action2 args none {
mov m.MainControlT_tmp 0x0
mov m.MainControlT_tmp_0 0x4d2
mov m.MainControlT_tmp_0 0x4D2
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't know why this change is occurring.
After syncing with main, I regenerated the output file and see this. All hex constants are changed to uppercase.

found = true;
}
if (oneInstance == "")
oneInstance = instanceName;
Copy link
Contributor

Choose a reason for hiding this comment

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

indentation

cstring method, cstring instancename) {
cstring oneInstance = "";
bool found = false;
for (auto stmt : a->body->components) {
Copy link
Contributor

Choose a reason for hiding this comment

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

you could do this by using a small visitor. it would be more robust and handle nested blocks, etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't get this comment correctly.
A visitor for BlockStatement and then calling visit(a->body) here?
Visitors for MethodCallStatement and AssignmentStatement would also be needed I guess.

Copy link
Contributor

Choose a reason for hiding this comment

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

You should probably create a new visitor instead of a loop

}

void CollectDirectCounterMeter::postorder(const IR::P4Action* a) {
ifMethodFound(a, "count");
Copy link
Contributor

Choose a reason for hiding this comment

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

you ignore the result, that's strange

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ifMethodFound function is called from 2 places.
One for making sure that the default action of owner table of the Direct Meter/Counter extern instance has a execute/count method. In this case, the return value is checked to issue error if specified method call doesn't exist in default action.
Second, for making sure that an action only contains count/execute method calls for only one Direct counter/meter instance. In this case, the error is emitted in the ifMethodFound function itself and hence we are not using the return value here.

Copy link
Contributor

Choose a reason for hiding this comment

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

This would be a good comment

return;
}
if (table_type == InternalTableType::LEARNER)
table_size *= 4;
Copy link
Contributor

Choose a reason for hiding this comment

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

inconsistent indentation

if ((a->originalExternType->getName().name == "DirectCounter" &&
a->method->getName().name == "count") ||
(a->originalExternType->getName().name == "DirectMeter" &&
a->method->getName().name == "execute")) {
Copy link
Contributor

Choose a reason for hiding this comment

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

what if the method does not have this name?

Copy link
Contributor

Choose a reason for hiding this comment

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

I suspect the answer is "this is implementing the PSA/PNA architecture definitions of DirectCounter and DirectMeter, and the method names are defined in the spec". So the methods won't have any other names.

Copy link
Contributor

Choose a reason for hiding this comment

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

that's why an error should be given

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, I misunderstood the reason for your question. Carry on :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. I will add error here

for (auto action : ownerTable->getActionList()->actionList) {
auto action_decl = refMap->getDeclaration(action->getPath())->to<IR::P4Action>();
if (act->name.name == action_decl->name.name) {
invokedFromOwnerTable = true;
Copy link
Contributor

Choose a reason for hiding this comment

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

indentation


// DPDK target needs packet length as mandatory parameters
if (argSize < 1) {
::error(ErrorType::ERR_UNEXPECTED, "Expected atleast 1 argument "
Copy link
Contributor

Choose a reason for hiding this comment

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

missing space

auto declArgs = di->arguments;
unsigned value = 0;
auto counter_type = declArgs->at(0)->expression;
if (counter_type->is<IR::Constant>())
Copy link
Contributor

Choose a reason for hiding this comment

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

usually you write if (auto c = counter_type->toIR::Constant()) value = c->asUnsigned().

value = counter_type->to<IR::Constant>()->asUnsigned();
if (a->method->getName().name == "count") {
auto args = a->expr->arguments;
if (args->size() > 1){
Copy link
Contributor

Choose a reason for hiding this comment

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

we usually use spaces before {

} else {
IR::Expression *n_meters =nullptr;
if (directMeterCounterSizeMap.count(this->Name())) {
n_meters = new IR::Constant(directMeterCounterSizeMap.at(this->Name()));
Copy link
Contributor

Choose a reason for hiding this comment

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

we usually omit this-> if it is not ambiguous

@mihaibudiu
Copy link
Contributor

You should rebase this

@usha1830
Copy link
Contributor Author

usha1830 commented Nov 4, 2022

@mbudiu-vmw Addressed all review comments. Please check.
Last commit ea75b39 is a minor change on top the existing PR. It adds table id for the table with which the direct meter or counter is associated. Please review.

@mihaibudiu mihaibudiu merged commit 1bf14ca into p4lang:main Nov 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants