Skip to content

Commit

Permalink
[libsai] Implement APIs set/get attribute (#651)
Browse files Browse the repository at this point in the history
Following #648, continue to
refactor libsai implementation for easier read and maintenance:

1. Avoid using compilated j2 template as best
2. Use c++ code directly to express the logic of API implementation,
based on p4 table metadata info (p4meta.[h, cpp])
3. Implement APIs set/get attribute by using common `DashSai::set` and
`DashSai::get`, which fix the issue
#650
4. Update libsai test (vnet_out.cpp) to cover sanity test of APIs
set/get attribute

Note: To refactor APIs create/remove with current approach in next PR. 

The generated sample code of APIs set/get attribute is as below:

- SAI object objectID

![image](https://github.com/user-attachments/assets/2df7e786-6d7b-4503-a26f-6f2463748867)
p4meta `outbound_routing_group_meta_table` definition

![image](https://github.com/user-attachments/assets/ddf3e5ee-6fab-4ede-b589-48600b885088)

- SAI object entry

![image](https://github.com/user-attachments/assets/c4d47442-c4bf-4c88-9e8f-14b54f03668e)
p4meta `outbound_routing_entry_meta_table`  definition

![image](https://github.com/user-attachments/assets/deb64ef6-e90c-4d2d-9aad-9aa6db133521)
  • Loading branch information
jimmyzhai authored Dec 23, 2024
1 parent e16ceb4 commit 65b42a8
Show file tree
Hide file tree
Showing 8 changed files with 1,021 additions and 14 deletions.
261 changes: 260 additions & 1 deletion dash-pipeline/SAI/src/dashsai.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ extern "C" {
#include <cstdlib>

using namespace dash;
using namespace dash::utils;

#define DASH_BMV2_CPU_QOS_NUMBER_OF_QUEUES 0

Expand Down Expand Up @@ -607,6 +608,52 @@ grpc::StatusCode DashSai::mutateTableEntry(
return status.error_code();
}

grpc::StatusCode DashSai::readTableEntry(
_Inout_ std::shared_ptr<p4::v1::TableEntry> entry)
{
DASH_LOG_ENTER();

if (!m_apiInitialized)
{
DASH_LOG_ERROR("api not initialized");

return grpc::StatusCode::CANCELLED;
}

p4::v1::ReadRequest request;

request.set_device_id(m_cfg->m_deviceId);

auto entity = request.add_entities();

entity->set_allocated_table_entry(entry.get());

grpc::ClientContext context;

auto client_reader = m_stub->Read(&context, request);
assert(client_reader);

p4::v1::ReadResponse rep;
if (client_reader->Read(&rep)) {
assert(rep.entities_size() == 1);
entity->release_table_entry();
entity = rep.mutable_entities(0);
entry->CopyFrom(entity->table_entry());
}

auto status = client_reader->Finish();

exit:
if (status.ok()) {
DASH_LOG_NOTICE("GRPC call Read OK %s", entry->ShortDebugString().c_str());
}
else {
DASH_LOG_ERROR("GRPC ERROR[%d]: %s, %s", status.error_code(), status.error_message().c_str(), status.error_details().c_str());
}

return status.error_code();
}

bool DashSai::insertInTable(
_In_ std::shared_ptr<p4::v1::TableEntry> entry,
_In_ sai_object_id_t objId)
Expand Down Expand Up @@ -705,6 +752,40 @@ bool DashSai::removeFromTable(
return retCode == grpc::StatusCode::OK;
}

bool DashSai::getFromTable(
_In_ sai_object_id_t id,
_Out_ std::shared_ptr<p4::v1::TableEntry> &entry)
{
DASH_LOG_ENTER();

if (!m_apiInitialized)
{
DASH_LOG_ERROR("api not initialized");

return false;
}

MUTEX;

auto range = m_tableEntryMap.equal_range(id);

if (range.first == range.second)
{
DASH_LOG_ERROR("id: 0x%lx not present in the table for deletion!", id);

return false;
}

for (auto itr = range.first; itr != range.second; ++itr)
{
entry = itr->second;
return true;

}

return false;
}

// QUAD generic api implementation

sai_status_t DashSai::create(
Expand Down Expand Up @@ -960,4 +1041,182 @@ sai_status_t DashSai::bulk_remove_objects(
}

return agg_status;
}
}

sai_status_t DashSai::set(
_In_ const P4MetaTable &meta_table,
_In_ sai_object_id_t objectId,
_In_ const sai_attribute_t *attr)
{
DASH_LOG_ENTER();
DASH_CHECK_API_INITIALIZED();

std::shared_ptr<p4::v1::TableEntry> matchActionEntry = nullptr;
if (!getFromTable(objectId, matchActionEntry)) {
return SAI_STATUS_FAILURE;
}

// Search attr in table action params
auto action = matchActionEntry->mutable_action()->mutable_action();
pi_p4_id_t action_id = action->action_id();
auto meta_param = meta_table.get_meta_action_param(action_id, attr->id);
if (meta_param) {
auto pair_param = get_action_param_pair_from_p4_table_entry(meta_param, matchActionEntry);
if (pair_param.second) {
set_attr_ipaddr_family_to_p4(attr->value, pair_param.second);
}

assert(pair_param.first);
set_attr_value_to_p4(meta_param->field, meta_param->bitwidth, attr->value, pair_param.first);

auto ret = mutateTableEntry(matchActionEntry, p4::v1::Update_Type_MODIFY);
return ret == grpc::StatusCode::OK ? SAI_STATUS_SUCCESS : SAI_STATUS_FAILURE;
}

// Search attr in table match fields
auto meta_key = meta_table.get_meta_key(attr->id);
if (meta_key) {
std::shared_ptr<p4::v1::TableEntry> new_entry = std::make_shared<p4::v1::TableEntry>();
new_entry->CopyFrom(*matchActionEntry);

auto pair_key = get_match_pair_from_p4_table_entry(meta_key, new_entry);
if (pair_key.second) {
set_attr_ipaddr_family_to_p4(attr->value, pair_key.second->mutable_exact());
}

assert(pair_key.first);
if (meta_key->match_type == "ternary" && string_has_suffix(meta_key->name, "_MASK")) {
set_attr_value_mask_to_p4_ternary(meta_key->field, meta_key->bitwidth, attr->value,
pair_key.first->mutable_ternary());
}
else {
set_attr_value_to_p4_match(*meta_key, attr->value, pair_key.first);
}

removeFromTable(objectId);
auto ret = insertInTable(new_entry, objectId);
return ret ? SAI_STATUS_SUCCESS : SAI_STATUS_FAILURE;
}

return SAI_STATUS_FAILURE;
}

sai_status_t DashSai::set(
_In_ const P4MetaTable &meta_table,
_Inout_ std::shared_ptr<p4::v1::TableEntry> matchActionEntry,
_In_ const sai_attribute_t *attr)
{
DASH_LOG_ENTER();
DASH_CHECK_API_INITIALIZED();

if (grpc::StatusCode::OK != readTableEntry(matchActionEntry)) {
return SAI_STATUS_FAILURE;
}

// Search attr in table action params
auto action = matchActionEntry->mutable_action()->mutable_action();
pi_p4_id_t action_id = action->action_id();
auto meta_param = meta_table.get_meta_action_param(action_id, attr->id);
if (meta_param) {
auto pair_param = get_action_param_pair_from_p4_table_entry(meta_param, matchActionEntry);
if (pair_param.second) {
set_attr_ipaddr_family_to_p4(attr->value, pair_param.second);
}

assert(pair_param.first);
set_attr_value_to_p4(meta_param->field, meta_param->bitwidth, attr->value, pair_param.first);

auto ret = mutateTableEntry(matchActionEntry, p4::v1::Update_Type_MODIFY);
return ret == grpc::StatusCode::OK ? SAI_STATUS_SUCCESS : SAI_STATUS_FAILURE;
}

return SAI_STATUS_FAILURE;
}

sai_status_t DashSai::get(
_In_ const P4MetaTable &meta_table,
_In_ sai_object_id_t objectId,
_In_ uint32_t attr_count,
_Inout_ sai_attribute_t *attr_list)
{
DASH_LOG_ENTER();
DASH_CHECK_API_INITIALIZED();

std::shared_ptr<p4::v1::TableEntry> matchActionEntry = nullptr;
if (!getFromTable(objectId, matchActionEntry)) {
return SAI_STATUS_FAILURE;
}

auto action = matchActionEntry->mutable_action()->mutable_action();
pi_p4_id_t action_id = action->action_id();

for (uint32_t i = 0; i < attr_count; i++) {
if (auto meta_param = meta_table.get_meta_action_param(action_id, attr_list[i].id)) {
// attr in table action params
auto pair_param = get_action_param_pair_from_p4_table_entry(meta_param, matchActionEntry);
if (pair_param.second) {
get_attr_ipaddr_family_from_p4(pair_param.second, attr_list[i].value);
}

assert(pair_param.first);
get_attr_value_from_p4(meta_param->field, meta_param->bitwidth, pair_param.first, attr_list[i].value);
}
else if (auto meta_key = meta_table.get_meta_key(attr_list[i].id)) {
// attr in table keys
auto pair_key = get_match_pair_from_p4_table_entry(meta_key, matchActionEntry);
if (pair_key.second) {
get_attr_ipaddr_family_from_p4(pair_key.second->mutable_exact(), attr_list[i].value);
}

assert(pair_key.first);
if (meta_key->match_type == "ternary" && string_has_suffix(meta_key->name, "_MASK")) {
get_attr_value_mask_from_p4_ternary(meta_key->field, meta_key->bitwidth,
pair_key.first->mutable_ternary(), attr_list[i].value);
}
else {
get_attr_value_from_p4_match(*meta_key, pair_key.first, attr_list[i].value);
}
}
else {
DASH_LOG_ERROR("failed to get value for attr %d", attr_list[i].id);
}
}

return SAI_STATUS_SUCCESS;
}

sai_status_t DashSai::get(
_In_ const P4MetaTable &meta_table,
_Inout_ std::shared_ptr<p4::v1::TableEntry> matchActionEntry,
_In_ uint32_t attr_count,
_Inout_ sai_attribute_t *attr_list)
{
DASH_LOG_ENTER();
DASH_CHECK_API_INITIALIZED();

if (grpc::StatusCode::OK != readTableEntry(matchActionEntry)) {
return SAI_STATUS_FAILURE;
}

auto action = matchActionEntry->mutable_action()->mutable_action();
pi_p4_id_t action_id = action->action_id();

for (uint32_t i = 0; i < attr_count; i++) {
if (auto meta_param = meta_table.get_meta_action_param(action_id, attr_list[i].id)) {
// attr in table action params
auto pair_param = get_action_param_pair_from_p4_table_entry(meta_param, matchActionEntry);
if (pair_param.second) {
get_attr_ipaddr_family_from_p4(pair_param.second, attr_list[i].value);
}

assert(pair_param.first);
get_attr_value_from_p4(meta_param->field, meta_param->bitwidth, pair_param.first, attr_list[i].value);
}
else {
DASH_LOG_ERROR("failed to get value for attr %d", attr_list[i].id);
}
}

return SAI_STATUS_SUCCESS;
}

31 changes: 31 additions & 0 deletions dash-pipeline/SAI/src/dashsai.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "utils.h"
#include "config.h"
#include "objectidmanager.h"
#include "p4meta.h"

namespace dash
{
Expand Down Expand Up @@ -51,6 +52,29 @@ namespace dash
_In_ uint32_t attr_count,
_Inout_ sai_attribute_t *attr_list);

// QUAD api implementation, using p4 meta table
sai_status_t set(
_In_ const P4MetaTable &meta_table,
_In_ sai_object_id_t objectId,
_In_ const sai_attribute_t *attr);

sai_status_t set(
_In_ const P4MetaTable &meta_table,
_Inout_ std::shared_ptr<p4::v1::TableEntry> matchActionEntry,
_In_ const sai_attribute_t *attr);

sai_status_t get(
_In_ const P4MetaTable &meta_table,
_In_ sai_object_id_t objectId,
_In_ uint32_t attr_count,
_Inout_ sai_attribute_t *attr_list);

sai_status_t get(
_In_ const P4MetaTable &meta_table,
_Inout_ std::shared_ptr<p4::v1::TableEntry> matchActionEntry,
_In_ uint32_t attr_count,
_Inout_ sai_attribute_t *attr_list);

private: // QUAD api implementation

// switch
Expand Down Expand Up @@ -85,6 +109,9 @@ namespace dash
_In_ std::shared_ptr<p4::v1::TableEntry>,
_In_ p4::v1::Update_Type updateType);

grpc::StatusCode readTableEntry(
_Inout_ std::shared_ptr<p4::v1::TableEntry>);

sai_object_id_t getNextObjectId(
_In_ sai_object_type_t objectType);

Expand All @@ -95,6 +122,10 @@ namespace dash
bool removeFromTable(
_In_ sai_object_id_t id);

bool getFromTable(
_In_ sai_object_id_t id,
_Out_ std::shared_ptr<p4::v1::TableEntry> &entry);

public: // default attributes helper

static std::vector<sai_attribute_t> populateDefaultAttributes(
Expand Down
Loading

0 comments on commit 65b42a8

Please sign in to comment.