From 88a477182f2ea4d20e6ad32ddcdcb253ee6c292c Mon Sep 17 00:00:00 2001 From: Junhua Zhai Date: Thu, 9 Jan 2025 07:56:52 +0800 Subject: [PATCH] [libsai] Re-implement APIs create/remove (#653) Following https://github.com/sonic-net/DASH/pull/651, refactor APIs create/remove for easier read and maintenance: 1. Use common code `DashSai::create` and `DashSai::remove` to implement them for all SAI objects/entries 2. Fix issue https://github.com/sonic-net/DASH/issues/436, now only 1 SAI object is created for multiple bmv2 objects (each bmv2 object as a p4 table entry in p4 table for each stage). 3. Fix issue https://github.com/sonic-net/DASH/issues/654 The generated sample code of APIs create/remove attribute is as below: - SAI object objectID ![image](https://github.com/user-attachments/assets/1f300b7a-7750-43df-89e2-71570801cd06) - SAI object entry ![image](https://github.com/user-attachments/assets/d16a3bcc-0a41-4fd1-a23a-6f6663761a67) For the case of acl rule object, one acl rule is inserted into multiple p4 tables in different stages. These p4 stage tables are same and the only difference is `table id` and `table action id` in table entry, captured in struct P4MetaSiblingTable: ``` struct P4MetaSiblingTable { uint32_t id; // action enum id -> p4 action id std::map actions; }; ``` The generated code of sibling tables for acl rule is as below: ![image](https://github.com/user-attachments/assets/4dbf0725-1ca5-488f-bf08-62b032c2f66a) --- dash-pipeline/SAI/src/dashsai.cpp | 320 ++++++++++++++++-- dash-pipeline/SAI/src/dashsai.h | 31 ++ dash-pipeline/SAI/src/p4meta.cpp | 225 ++++++++---- dash-pipeline/SAI/src/p4meta.h | 114 +++++-- .../templates/impls/p4_table_action.cpp.j2 | 73 ---- .../impls/p4_table_object_match.cpp.j2 | 66 ---- .../templates/impls/sai_api_func_quad.cpp.j2 | 123 +------ .../SAI/templates/impls/sai_api_group.cpp.j2 | 14 + 8 files changed, 582 insertions(+), 384 deletions(-) delete mode 100644 dash-pipeline/SAI/templates/impls/p4_table_action.cpp.j2 delete mode 100644 dash-pipeline/SAI/templates/impls/p4_table_object_match.cpp.j2 diff --git a/dash-pipeline/SAI/src/dashsai.cpp b/dash-pipeline/SAI/src/dashsai.cpp index e61a1914d..4c281fd00 100644 --- a/dash-pipeline/SAI/src/dashsai.cpp +++ b/dash-pipeline/SAI/src/dashsai.cpp @@ -634,20 +634,26 @@ grpc::StatusCode DashSai::readTableEntry( assert(client_reader); p4::v1::ReadResponse rep; - if (client_reader->Read(&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()); } + else + { + entity->release_table_entry(); + } auto status = client_reader->Finish(); -exit: - if (status.ok()) { + if (status.ok()) + { DASH_LOG_NOTICE("GRPC call Read OK %s", entry->ShortDebugString().c_str()); } - else { + else + { DASH_LOG_ERROR("GRPC ERROR[%d]: %s, %s", status.error_code(), status.error_message().c_str(), status.error_details().c_str()); } @@ -1043,6 +1049,175 @@ sai_status_t DashSai::bulk_remove_objects( return agg_status; } +sai_status_t DashSai::create( + _In_ const P4MetaTable &meta_table, + _In_ sai_object_type_t objectType, + _Out_ sai_object_id_t* objectId, + _In_ sai_object_id_t switchId, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list) +{ + DASH_LOG_ENTER(); + DASH_CHECK_API_INITIALIZED(); + + auto attrs = DashSai::populateDefaultAttributes(objectType, attr_count, attr_list); + attr_count = (uint32_t)attrs.size(); + attr_list = attrs.data(); + + std::shared_ptr matchActionEntry; + matchActionEntry = std::make_shared(); + matchActionEntry->set_table_id(meta_table.id); + + sai_object_id_t objId = getNextObjectId(objectType); + if (objId == SAI_NULL_OBJECT_ID) + { + DASH_LOG_ERROR("getNextObjectId failed for OBJECT_TYPE %u", objectType); + return SAI_STATUS_FAILURE; + } + + auto meta_object_key = meta_table.get_meta_object_key(); + if (meta_object_key) + { + auto key_mf = matchActionEntry->add_match(); + auto key_mf_exact = key_mf->mutable_exact(); + + key_mf->set_field_id(meta_object_key->id); + u16SetVal((uint16_t)objId, key_mf_exact, 16); + } + + pi_p4_id_t action_id = meta_table.find_action_id(attr_count, attr_list); + if (!action_id) + { + DASH_LOG_ERROR("Not find p4 table action"); + return SAI_STATUS_FAILURE; + } + + auto action = matchActionEntry->mutable_action()->mutable_action(); + action->set_action_id(action_id); + + for (uint32_t i = 0; i < attr_count; i++) + { + auto meta_param = meta_table.get_meta_action_param(action_id, attr_list[i].id); + if (meta_param) + { + // attr in table action params + set_attr_to_p4_action(meta_param, &attr_list[i], action); + continue; + } + + auto meta_key = meta_table.get_meta_key(attr_list[i].id); + if (meta_key) + { + // attr in table keys + set_attr_to_p4_match(meta_key, &attr_list[i], matchActionEntry); + } + else + { + // attr in extra fields + set_attr_to_p4_misc(meta_table, &attr_list[i], matchActionEntry); + } + } + + if (insertInTable(matchActionEntry, objId)) + { + mutateSiblingTablesEntry(meta_table, matchActionEntry, p4::v1::Update_Type_INSERT, action_id); + *objectId = objId; + return SAI_STATUS_SUCCESS; + } + + return SAI_STATUS_FAILURE; +} + +sai_status_t DashSai::create( + _In_ const P4MetaTable &meta_table, + _In_ sai_object_type_t objectType, + _Inout_ std::shared_ptr matchActionEntry, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list) +{ + DASH_LOG_ENTER(); + DASH_CHECK_API_INITIALIZED(); + + auto attrs = DashSai::populateDefaultAttributes(objectType, attr_count, attr_list); + attr_count = (uint32_t)attrs.size(); + attr_list = attrs.data(); + + matchActionEntry->set_table_id(meta_table.id); + + pi_p4_id_t action_id = meta_table.find_action_id(attr_count, attr_list); + if (!action_id) + { + DASH_LOG_ERROR("Not find p4 table action"); + return SAI_STATUS_FAILURE; + } + auto action = matchActionEntry->mutable_action()->mutable_action(); + action->set_action_id(action_id); + + for (uint32_t i = 0; i < attr_count; i++) + { + auto meta_param = meta_table.get_meta_action_param(action_id, attr_list[i].id); + if (meta_param) + { + // attr in table action params + set_attr_to_p4_action(meta_param, &attr_list[i], action); + } + else + { + // attr in extra fields + set_attr_to_p4_misc(meta_table, &attr_list[i], matchActionEntry); + } + } + + auto ret = mutateTableEntry(matchActionEntry, p4::v1::Update_Type_INSERT); + if (grpc::StatusCode::OK == ret) + { + mutateSiblingTablesEntry(meta_table, matchActionEntry, p4::v1::Update_Type_INSERT, action_id); + return SAI_STATUS_SUCCESS; + } + + return SAI_STATUS_FAILURE; +} + +sai_status_t DashSai::remove( + _In_ const P4MetaTable &meta_table, + _In_ sai_object_id_t objectId) +{ + DASH_LOG_ENTER(); + DASH_CHECK_API_INITIALIZED(); + + std::shared_ptr matchActionEntry = nullptr; + if (!getFromTable(objectId, matchActionEntry)) + { + return SAI_STATUS_FAILURE; + } + + if (removeFromTable(objectId)) + { + mutateSiblingTablesEntry(meta_table, matchActionEntry, p4::v1::Update_Type_DELETE); + return SAI_STATUS_SUCCESS; + } + + return SAI_STATUS_FAILURE; +} + +sai_status_t DashSai::remove( + _In_ const P4MetaTable &meta_table, + _Inout_ std::shared_ptr matchActionEntry) +{ + DASH_LOG_ENTER(); + DASH_CHECK_API_INITIALIZED(); + + auto ret = mutateTableEntry(matchActionEntry, p4::v1::Update_Type_DELETE); + + if (grpc::StatusCode::OK == ret) + { + mutateSiblingTablesEntry(meta_table, matchActionEntry, p4::v1::Update_Type_DELETE); + return SAI_STATUS_SUCCESS; + } + + return SAI_STATUS_FAILURE; +} + sai_status_t DashSai::set( _In_ const P4MetaTable &meta_table, _In_ sai_object_id_t objectId, @@ -1052,7 +1227,8 @@ sai_status_t DashSai::set( DASH_CHECK_API_INITIALIZED(); std::shared_ptr matchActionEntry = nullptr; - if (!getFromTable(objectId, matchActionEntry)) { + if (!getFromTable(objectId, matchActionEntry)) + { return SAI_STATUS_FAILURE; } @@ -1060,9 +1236,11 @@ sai_status_t DashSai::set( 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) { + if (meta_param) + { + auto pair_param = get_action_param_with_is_v6_flag_from_p4_table_entry(meta_param, matchActionEntry); + if (pair_param.second) + { set_attr_ipaddr_family_to_p4(attr->value, pair_param.second); } @@ -1070,32 +1248,45 @@ sai_status_t DashSai::set( 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); + if (ret == grpc::StatusCode::OK) + { + mutateSiblingTablesEntry(meta_table, matchActionEntry, p4::v1::Update_Type_MODIFY, action_id); + } 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) { + if (meta_key) + { std::shared_ptr new_entry = std::make_shared(); new_entry->CopyFrom(*matchActionEntry); auto pair_key = get_match_pair_from_p4_table_entry(meta_key, new_entry); - if (pair_key.second) { + 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")) { + if (meta_key->match_type == "ternary" && string_ends_with(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 { + 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; + mutateSiblingTablesEntry(meta_table, matchActionEntry, p4::v1::Update_Type_DELETE); + + if (insertInTable(new_entry, objectId)) + { + mutateSiblingTablesEntry(meta_table, new_entry, p4::v1::Update_Type_INSERT, action_id); + return SAI_STATUS_SUCCESS; + } } return SAI_STATUS_FAILURE; @@ -1109,7 +1300,8 @@ sai_status_t DashSai::set( DASH_LOG_ENTER(); DASH_CHECK_API_INITIALIZED(); - if (grpc::StatusCode::OK != readTableEntry(matchActionEntry)) { + if (grpc::StatusCode::OK != readTableEntry(matchActionEntry)) + { return SAI_STATUS_FAILURE; } @@ -1117,9 +1309,11 @@ sai_status_t DashSai::set( 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) { + if (meta_param) + { + auto pair_param = get_action_param_with_is_v6_flag_from_p4_table_entry(meta_param, matchActionEntry); + if (pair_param.second) + { set_attr_ipaddr_family_to_p4(attr->value, pair_param.second); } @@ -1127,6 +1321,10 @@ sai_status_t DashSai::set( 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); + if (ret == grpc::StatusCode::OK) + { + mutateSiblingTablesEntry(meta_table, matchActionEntry, p4::v1::Update_Type_MODIFY, action_id); + } return ret == grpc::StatusCode::OK ? SAI_STATUS_SUCCESS : SAI_STATUS_FAILURE; } @@ -1143,42 +1341,55 @@ sai_status_t DashSai::get( DASH_CHECK_API_INITIALIZED(); std::shared_ptr matchActionEntry = nullptr; - if (!getFromTable(objectId, matchActionEntry)) { + 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)) { + for (uint32_t i = 0; i < attr_count; i++) + { + auto meta_param = meta_table.get_meta_action_param(action_id, attr_list[i].id); + if (meta_param) + { // attr in table action params - auto pair_param = get_action_param_pair_from_p4_table_entry(meta_param, matchActionEntry); - if (pair_param.second) { + auto pair_param = get_action_param_with_is_v6_flag_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); + continue; } - else if (auto meta_key = meta_table.get_meta_key(attr_list[i].id)) { + + auto meta_key = meta_table.get_meta_key(attr_list[i].id); + if (meta_key) + { // attr in table keys auto pair_key = get_match_pair_from_p4_table_entry(meta_key, matchActionEntry); - if (pair_key.second) { + 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")) { + if (meta_key->match_type == "ternary" && string_ends_with(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 { + 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); + else + { + get_attr_from_p4_misc(meta_table, matchActionEntry, &attr_list[i]); } } @@ -1194,29 +1405,66 @@ sai_status_t DashSai::get( DASH_LOG_ENTER(); DASH_CHECK_API_INITIALIZED(); - if (grpc::StatusCode::OK != readTableEntry(matchActionEntry)) { + 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)) { + for (uint32_t i = 0; i < attr_count; i++) + { + auto meta_param = meta_table.get_meta_action_param(action_id, attr_list[i].id); + if (meta_param) + { // attr in table action params - auto pair_param = get_action_param_pair_from_p4_table_entry(meta_param, matchActionEntry); - if (pair_param.second) { + auto pair_param = get_action_param_with_is_v6_flag_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); + else + { + get_attr_from_p4_misc(meta_table, matchActionEntry, &attr_list[i]); } } return SAI_STATUS_SUCCESS; } +void DashSai::mutateSiblingTablesEntry( + _In_ const P4MetaTable &meta_table, + _In_ std::shared_ptr matchActionEntry, + _In_ p4::v1::Update_Type updateType, + _In_ uint32_t action_id) +{ + if (meta_table.sibling_tables.empty()) + { + return; + } + + // Entry in sibling table is almost same as the original table entry, + // only table id and table action id are different. + std::shared_ptr entry = std::make_shared(); + entry->CopyFrom(*matchActionEntry); + auto action = entry->mutable_action()->mutable_action(); + + for (auto &sibling: meta_table.sibling_tables) + { + entry->set_table_id(sibling.id); + + if (updateType != p4::v1::Update_Type_DELETE) + { + auto enum_id = meta_table.find_action_enum_id(action_id); + auto sibling_action_id = sibling.actions.at(enum_id); + action->set_action_id(sibling_action_id); + } + + mutateTableEntry(entry, updateType); + } +} diff --git a/dash-pipeline/SAI/src/dashsai.h b/dash-pipeline/SAI/src/dashsai.h index 1d1517872..2c83810e6 100644 --- a/dash-pipeline/SAI/src/dashsai.h +++ b/dash-pipeline/SAI/src/dashsai.h @@ -53,6 +53,29 @@ namespace dash _Inout_ sai_attribute_t *attr_list); // QUAD api implementation, using p4 meta table + sai_status_t create( + _In_ const P4MetaTable &meta_table, + _In_ sai_object_type_t objectType, + _Out_ sai_object_id_t* objectId, + _In_ sai_object_id_t switchId, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); + + sai_status_t create( + _In_ const P4MetaTable &meta_table, + _In_ sai_object_type_t objectType, + _Inout_ std::shared_ptr matchActionEntry, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); + + sai_status_t remove( + _In_ const P4MetaTable &meta_table, + _In_ sai_object_id_t objectId); + + sai_status_t remove( + _In_ const P4MetaTable &meta_table, + _Inout_ std::shared_ptr matchActionEntry); + sai_status_t set( _In_ const P4MetaTable &meta_table, _In_ sai_object_id_t objectId, @@ -126,6 +149,14 @@ namespace dash _In_ sai_object_id_t id, _Out_ std::shared_ptr &entry); + private: // private helper methods + + void mutateSiblingTablesEntry( + _In_ const P4MetaTable &meta_table, + _In_ std::shared_ptr, + _In_ p4::v1::Update_Type updateType, + _In_ uint32_t action_id = 0); + public: // default attributes helper static std::vector populateDefaultAttributes( diff --git a/dash-pipeline/SAI/src/p4meta.cpp b/dash-pipeline/SAI/src/p4meta.cpp index 7c9b068e3..57b6c787e 100644 --- a/dash-pipeline/SAI/src/p4meta.cpp +++ b/dash-pipeline/SAI/src/p4meta.cpp @@ -13,8 +13,10 @@ namespace dash const P4MetaKey* P4MetaTable::get_meta_key( _In_ sai_attr_id_t attr_id) const { - for (auto i=0u; isecond.params; - for (auto i=0u; ifirst; } auto itr = extra_fields.find("ACTION"); assert(itr != extra_fields.end()); - for (uint32_t i = 0; i < attr_count; i++) { - if (attr_list[i].id == itr->second) { + for (uint32_t i = 0; i < attr_count; i++) + { + if (attr_list[i].id == itr->second) + { uint32_t action_enum_id = attr_list[i].value.u32; - for (auto &action: actions) { - if (action.second.enum_id == action_enum_id) { + for (auto &action: actions) + { + if (action.second.enum_id == action_enum_id) + { return action.first; } } @@ -88,6 +102,18 @@ namespace dash return 0; // invalid p4 action id } + uint32_t P4MetaTable::find_action_enum_id( + _In_ uint32_t action_id) const + { + auto itr = actions.find(action_id); + if (itr != actions.end()) + { + return itr->second.enum_id; + } + + return ~0u; + } + // // helper functions, set/get attr to/from p4 match|action // @@ -112,14 +138,16 @@ namespace dash const char *v = mf_lpm->value().c_str(); auto prefix_len = mf_lpm->prefix_len(); - if (value.ipprefix.addr_family == SAI_IP_ADDR_FAMILY_IPV4) { + if (value.ipprefix.addr_family == SAI_IP_ADDR_FAMILY_IPV4) + { uint32_t val = *(const uint32_t*)v; prefix_len -= 96; assert (prefix_len <= 32); value.ipprefix.addr.ip4 = val; value.ipprefix.mask.ip4 = 0xffffffff << (32 - prefix_len); } - else { + else + { assert (prefix_len <= 128); uint8_t netmask[16] = { 0 }; int i; @@ -146,7 +174,7 @@ namespace dash if (field == "u64") return u64SetMask(value, mf_ternary, bitwidth); - assert(0); + assert(0 && "unsupported field"); } void get_attr_value_mask_from_p4_ternary( @@ -158,30 +186,37 @@ namespace dash { const char *v = mf_ternary->mask().c_str(); - if (field == "ipaddr") { - if (value.ipaddr.addr_family == SAI_IP_ADDR_FAMILY_IPV4) { + if (field == "ipaddr") + { + if (value.ipaddr.addr_family == SAI_IP_ADDR_FAMILY_IPV4) + { uint32_t val = *(const uint32_t*)v; value.ipaddr.addr.ip4 = val; } - else { + else + { memcpy(value.ipaddr.addr.ip6, v, 16); } } - else if (field == "u32") { + else if (field == "u32") + { uint32_t val = *(const uint32_t*)v; value.u32 = ntohl(val) >> (32 - bitwidth); } - else if (field == "u64") { + else if (field == "u64") + { uint64_t val = *(const uint64_t*)v; - if (*reinterpret_cast("\0\x01") == 0) { // Little Endian - value.u64 = be64toh(val) >> (64 - bitwidth); - } - else { - value.u64 = val & ((1ul<> (64 - bitwidth); +#elif __BYTE_ORDER == __BIG_ENDIAN + value.u64 = val & ((1ul<" +#endif + } + else + { + assert(0 && "unsupported field"); } } @@ -191,11 +226,13 @@ namespace dash _In_ const sai_attribute_value_t &value, _Inout_ p4::v1::FieldMatch *mf) { - if (key.match_type == "exact") { + if (key.match_type == "exact") + { auto mf_exact = mf->mutable_exact(); set_attr_value_to_p4(key.field, key.bitwidth, value, mf_exact); } - else if (key.match_type == "lpm") { + else if (key.match_type == "lpm") + { auto mf_lpm = mf->mutable_lpm(); if (getPrefixLength(value) == 0) { @@ -205,37 +242,44 @@ namespace dash } set_attr_value_to_p4(key.field, key.bitwidth, value, mf_lpm); } - else if (key.match_type == "ternary") { + else if (key.match_type == "ternary") + { auto mf_ternary = mf->mutable_ternary(); set_attr_value_to_p4(key.field, key.bitwidth, value, mf_ternary); } - else if (key.match_type == "optional") { + else if (key.match_type == "optional") + { auto mf_optional = mf->mutable_optional(); set_attr_value_to_p4(key.field, key.bitwidth, value, mf_optional); } - else if (key.match_type == "list") { + else if (key.match_type == "list") + { // BMv2 doesn't support "list" match type, and we are using "optional" match in v1model as our implementation. // Hence, here we only take the first item from the list and program it as optional match. auto mf_optional = mf->mutable_optional(); - if (key.field == "ipprefixlist") { + if (key.field == "ipprefixlist") + { sai_attribute_value_t val; val.ipaddr.addr_family = value.ipprefixlist.list[0].addr_family; val.ipaddr.addr = value.ipprefixlist.list[0].addr; set_attr_value_to_p4("ipaddr", key.bitwidth, val, mf_optional); } - else { + else + { set_attr_value_to_p4(key.field, key.bitwidth, value, mf_optional); } } - else if (key.match_type == "range_list") { + else if (key.match_type == "range_list") + { // BMv2 doesn't support "range_list" match type, and we are using "optional" match in v1model as our implementation. // Hence, here we only take the first item from the list and program the range start as optional match. auto mf_optional = mf->mutable_optional(); // FIXME only u16rangelist in sai_attribute_value_t u16SetVal(value.u16rangelist.list[0].min, mf_optional, key.bitwidth); } - else { - assert(0); + else + { + assert(0 && "unsupported match type"); } } @@ -244,32 +288,39 @@ namespace dash _In_ p4::v1::FieldMatch *mf, _Out_ sai_attribute_value_t &value) { - if (key.match_type == "exact") { + if (key.match_type == "exact") + { auto mf_exact = mf->mutable_exact(); get_attr_value_from_p4(key.field, key.bitwidth, mf_exact, value); } - else if (key.match_type == "lpm") { + else if (key.match_type == "lpm") + { auto mf_lpm = mf->mutable_lpm(); get_attr_value_from_p4(key.field, key.bitwidth, mf_lpm, value); } - else if (key.match_type == "ternary") { + else if (key.match_type == "ternary") + { auto mf_ternary = mf->mutable_ternary(); get_attr_value_from_p4(key.field, key.bitwidth, mf_ternary, value); } - else if (key.match_type == "optional") { + else if (key.match_type == "optional") + { auto mf_optional = mf->mutable_optional(); get_attr_value_from_p4(key.field, key.bitwidth, mf_optional, value); } - else if (key.match_type == "list") { + else if (key.match_type == "list") + { auto mf_optional = mf->mutable_optional(); get_attr_value_from_p4(key.field, key.bitwidth, mf_optional, value); } - else if (key.match_type == "range_list") { + else if (key.match_type == "range_list") + { auto mf_optional = mf->mutable_optional(); get_attr_value_from_p4(key.field, key.bitwidth, mf_optional, value); } - else { - assert(0); + else + { + assert(0 && "unsupported match type"); } } @@ -278,7 +329,8 @@ namespace dash _In_ const sai_attribute_t *attr, _Inout_ std::shared_ptr matchActionEntry) { - if (meta_key->ip_is_v6_field_id) { + if (meta_key->ip_is_v6_field_id) + { auto mf = matchActionEntry->add_match(); mf->set_field_id(meta_key->ip_is_v6_field_id); set_attr_ipaddr_family_to_p4(attr->value, mf->mutable_exact()); @@ -286,11 +338,13 @@ namespace dash auto mf = matchActionEntry->add_match(); mf->set_field_id(meta_key->id); - if (meta_key->match_type == "ternary" && string_has_suffix(meta_key->name, "_MASK")) { + if (meta_key->match_type == "ternary" && string_ends_with(meta_key->name, "_MASK")) + { set_attr_value_mask_to_p4_ternary(meta_key->field, meta_key->bitwidth, attr->value, mf->mutable_ternary()); } - else { + else + { set_attr_value_to_p4_match(*meta_key, attr->value, mf); } } @@ -300,7 +354,8 @@ namespace dash _In_ const sai_attribute_t *attr, _Out_ p4::v1::Action *action) { - if (meta_param->ip_is_v6_field_id) { + if (meta_param->ip_is_v6_field_id) + { auto param = action->add_params(); param->set_param_id(meta_param->ip_is_v6_field_id); set_attr_ipaddr_family_to_p4(attr->value, param); @@ -311,18 +366,63 @@ namespace dash set_attr_value_to_p4(meta_param->field, meta_param->bitwidth, attr->value, param); } + void set_attr_to_p4_misc( + _In_ const P4MetaTable &meta_table, + _In_ const sai_attribute_t *attr, + _Inout_ std::shared_ptr matchActionEntry) + { + for (auto &extra_attr: meta_table.extra_fields) + { + if (extra_attr.second == attr->id) + { + if (extra_attr.first == "PRIORITY") + { + matchActionEntry->set_priority(attr->value.u32); + break; + } + } + } + } + + void get_attr_from_p4_misc( + _In_ const P4MetaTable &meta_table, + _In_ const std::shared_ptr matchActionEntry, + _Inout_ sai_attribute_t *attr) + { + for (auto &extra_attr: meta_table.extra_fields) + { + if (extra_attr.second == attr->id) + { + if (extra_attr.first == "ACTION") + { + auto action = matchActionEntry->mutable_action()->mutable_action(); + auto action_id = action->action_id(); + attr->value.u32 = meta_table.find_action_enum_id(action_id); + } + else if (extra_attr.first == "PRIORITY") + { + attr->value.u32 = matchActionEntry->priority(); + break; + } + } + } + } + std::pair get_match_pair_from_p4_table_entry( _In_ const P4MetaKey *meta_key, _In_ std::shared_ptr matchActionEntry) { std::pair pair_key = {nullptr, nullptr}; - for (int i = 0; i < matchActionEntry->match_size(); i++) { + for (int i = 0; i < matchActionEntry->match_size(); i++) + { auto mf = matchActionEntry->mutable_match(i); - if (mf->field_id() == meta_key->id) { + if (mf->field_id() == meta_key->id) + { pair_key.first = mf; } - else if (mf->field_id() == meta_key->ip_is_v6_field_id) { + else if (mf->field_id() == meta_key->ip_is_v6_field_id) + { pair_key.second = mf; } } @@ -330,19 +430,22 @@ namespace dash return pair_key; } - std::pair get_action_param_pair_from_p4_table_entry( + std::pair get_action_param_with_is_v6_flag_from_p4_table_entry( _In_ const P4MetaActionParam *meta_param, _In_ std::shared_ptr matchActionEntry) { auto action = matchActionEntry->mutable_action()->mutable_action(); std::pair pair_param = {nullptr, nullptr}; - for (int i = 0; i < action->params_size(); i++) { + for (int i = 0; i < action->params_size(); i++) + { auto param = action->mutable_params(i); - if (param->param_id() == meta_param->id) { + if (param->param_id() == meta_param->id) + { pair_param.first = param; } - else if (param->param_id() == meta_param->ip_is_v6_field_id) { + else if (param->param_id() == meta_param->ip_is_v6_field_id) + { pair_param.second = param; } } @@ -350,7 +453,7 @@ namespace dash return pair_param; } - bool string_has_suffix(const std::string &str, const std::string &suffix) + bool string_ends_with(const std::string &str, const std::string &suffix) { if (str.length() < suffix.length()) return false; diff --git a/dash-pipeline/SAI/src/p4meta.h b/dash-pipeline/SAI/src/p4meta.h index 219aab202..71d9a23ec 100644 --- a/dash-pipeline/SAI/src/p4meta.h +++ b/dash-pipeline/SAI/src/p4meta.h @@ -11,7 +11,8 @@ using namespace dash::utils; namespace dash { - struct P4MetaKey { + struct P4MetaKey + { sai_attr_id_t attr_id; std::string name; uint32_t id; @@ -21,7 +22,8 @@ namespace dash uint32_t ip_is_v6_field_id; }; - struct P4MetaActionParam { + struct P4MetaActionParam + { sai_attr_id_t attr_id; uint32_t id; std::string field; @@ -29,23 +31,35 @@ namespace dash uint32_t ip_is_v6_field_id; }; - struct P4MetaAction { + struct P4MetaAction + { uint32_t enum_id; std::vector params; }; - struct P4MetaTable { + struct P4MetaSiblingTable + { + uint32_t id; + // action enum id -> p4 action id + std::map actions; + }; + + struct P4MetaTable + { uint32_t id; std::vector keys; std::map actions; std::map extra_fields; + std::vector sibling_tables; P4MetaTable( uint32_t table_id, std::initializer_list init_keys, std::initializer_list::value_type> init_actions, - std::initializer_list::value_type> extras - ) : id(table_id), keys(init_keys), actions(init_actions), extra_fields(extras) + std::initializer_list::value_type> extras, + std::initializer_list sibling_list = {} + ) : id(table_id), keys(init_keys), actions(init_actions), + extra_fields(extras), sibling_tables(sibling_list) {} @@ -55,15 +69,18 @@ namespace dash const P4MetaKey* get_meta_key( _In_ const std::string &key_name) const; - const P4MetaKey* get_meta_object_key() const; + const P4MetaKey* get_meta_object_key() const; - const P4MetaActionParam* get_meta_action_param( - _In_ uint32_t action_id, - _In_ sai_attr_id_t attr_id) const; + const P4MetaActionParam* get_meta_action_param( + _In_ uint32_t action_id, + _In_ sai_attr_id_t attr_id) const; - pi_p4_id_t find_action_id( - _In_ uint32_t attr_count, - _In_ const sai_attribute_t *attr_list) const; + pi_p4_id_t find_action_id( + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list) const; + + uint32_t find_action_enum_id( + _In_ uint32_t action_id) const; }; @@ -81,6 +98,8 @@ namespace dash return u8SetVal(value, p4_key_or_param, bitwidth); if (field == "u16") return u16SetVal(value, p4_key_or_param, bitwidth); + if (field == "s32") + return s32SetVal(value, p4_key_or_param, bitwidth); if (field == "u32") return u32SetVal(value, p4_key_or_param, bitwidth); if (field == "u64") @@ -92,7 +111,7 @@ namespace dash if (field == "u8list") return u8listSetVal(value, p4_key_or_param, bitwidth); - assert(0); + assert(0 && "unsupported field"); } void set_attr_value_to_p4( @@ -111,46 +130,63 @@ namespace dash { const char *v = p4_key_or_param->value().c_str(); - if (field == "booldata") { + if (field == "booldata") + { value.booldata = *(const bool*)v; } - else if (field == "u8") { + else if (field == "u8") + { value.u8 = *(const uint8_t*)v; } - else if (field == "u16") { + else if (field == "u16") + { uint16_t val = *(const uint16_t*)v; value.u16 = ntohs(val); } - else if (field == "u32") { + else if (field == "s32") + { + int32_t val = *(const int32_t*)v; + value.s32 = ntohl(val) >> (32 - bitwidth); + } + else if (field == "u32") + { uint32_t val = *(const uint32_t*)v; value.u32 = ntohl(val) >> (32 - bitwidth); } - else if (field == "u64") { + else if (field == "u64") + { uint64_t val = *(const uint64_t*)v; - if (*reinterpret_cast("\0\x01") == 0) { // Little Endian - value.u64 = be64toh(val) >> (64 - bitwidth); - } - else { - value.u64 = val & ((1ul<> (64 - bitwidth); +#elif __BYTE_ORDER == __BIG_ENDIAN + value.u64 = val & ((1ul<" +#endif } - else if (field == "ipaddr") { - if (value.ipaddr.addr_family == SAI_IP_ADDR_FAMILY_IPV4) { + else if (field == "ipaddr") + { + if (value.ipaddr.addr_family == SAI_IP_ADDR_FAMILY_IPV4) + { uint32_t val = *(const uint32_t*)v; value.ipaddr.addr.ip4 = val; } - else { + else + { memcpy(value.ipaddr.addr.ip6, v, 16); } } - else if (field == "mac") { + else if (field == "mac") + { memcpy(value.mac, v, 6); } - else if (field == "u8list") { + else if (field == "u8list") + { memcpy(value.u8list.list, v, p4_key_or_param->value().size()); } - else { - assert(0); + else + { + assert(0 && "unsupported field"); } } @@ -216,13 +252,23 @@ namespace dash _In_ const sai_attribute_t *attr, _Out_ p4::v1::Action *action); + void set_attr_to_p4_misc( + _In_ const P4MetaTable &meta_table, + _In_ const sai_attribute_t *attr, + _Inout_ std::shared_ptr matchActionEntry); + + void get_attr_from_p4_misc( + _In_ const P4MetaTable &meta_table, + _In_ const std::shared_ptr matchActionEntry, + _Inout_ sai_attribute_t *attr); + std::pair get_match_pair_from_p4_table_entry( _In_ const P4MetaKey *meta_key, _In_ std::shared_ptr matchActionEntry); - std::pair get_action_param_pair_from_p4_table_entry( + std::pair get_action_param_with_is_v6_flag_from_p4_table_entry( _In_ const P4MetaActionParam *meta_param, _In_ std::shared_ptr matchActionEntry); - bool string_has_suffix(const std::string &str, const std::string &suffix); + bool string_ends_with(const std::string &str, const std::string &suffix); } diff --git a/dash-pipeline/SAI/templates/impls/p4_table_action.cpp.j2 b/dash-pipeline/SAI/templates/impls/p4_table_action.cpp.j2 deleted file mode 100644 index d0cbfec47..000000000 --- a/dash-pipeline/SAI/templates/impls/p4_table_action.cpp.j2 +++ /dev/null @@ -1,73 +0,0 @@ - {% if table.actions|length == 1 %} - {% for name, action in table.actions.items() %} - actionId = {{action.id}}; // {{name}} - //expectedParams = {{ action.attr_params|length }}; - {% endfor %} - {% else %} - // Search the action - for (uint32_t i = 0; i < attr_count; i++) - { - if (SAI_{{ api.name | upper }}_ATTR_ACTION == attr_list[i].id) - { - switch(attr_list[i].value.s32) - { - {% for name, action in table.actions.items() %} - case {{ name }}: - { - actionId = {{action.id}}; - //expectedParams = {{ action.attr_params|length }}; - break; - } - {% endfor %} - default: - DASH_LOG_ERROR("attribute value [%d] %d not supported yet", i, attr_list[i].value.s32); - break; - } - // only one action - break; - } - } - {% endif %} - action->set_action_id(actionId); - - for (uint32_t i = 0; i < attr_count; i++) - { - auto *md = sai_metadata_get_attr_metadata((sai_object_type_t)SAI_OBJECT_TYPE_{{ api.name | upper }}, attr_list[i].id); - - const char* attrName = md ? md->attridname : "unknown"; - - switch(attr_list[i].id) - { - {% set attr_id_list = [] %} - {% for name, action in table.actions.items() %} - {% for param_name, param in action.attr_params.items() %} - {% if param_name in attr_id_list %}{% continue %}{% endif %} - {% do attr_id_list.append( param_name ) %} - {% if param.skipattr == 'true' %} - {% else %} - case {{ param_name }}: - { - auto param = action->add_params(); - param->set_param_id({{param.id}}); - {{param.field}}SetVal(attr_list[i].value, param, {{param.bitwidth}}); - //matchedParams++; - {% if param.ip_is_v6_field_id != 0 %} - { - // set ip_is_v6_field_id field - auto param2 = action->add_params(); - param2->set_param_id({{param.ip_is_v6_field_id}}); - booldataSetVal((attr_list[i].value.ipaddr.addr_family == SAI_IP_ADDR_FAMILY_IPV4) ? 0 : 1, param2, 1); - //matchedParams++; - } - {% endif %} - break; - } - {% endif %} - {% endfor %} - {% endfor %} - default: - DASH_LOG_ERROR("attribute [%d] %d %s not supported yet", i, attr_list[i].id, attrName); - break; - } - } - diff --git a/dash-pipeline/SAI/templates/impls/p4_table_object_match.cpp.j2 b/dash-pipeline/SAI/templates/impls/p4_table_object_match.cpp.j2 deleted file mode 100644 index d6419e5f3..000000000 --- a/dash-pipeline/SAI/templates/impls/p4_table_object_match.cpp.j2 +++ /dev/null @@ -1,66 +0,0 @@ - {% import 'templates/impls/p4_table_util.cpp.j2' as util %} - {% for key in table['keys'] %} - {% if key.is_object_key %} - auto key_mf = matchActionEntry->add_match(); - key_mf->set_field_id({{key.id}}); - auto key_mf_exact = key_mf->mutable_exact(); - // {{key.field}}SetVal(objId, key_mf_exact, {{key.bitwidth}}); - {{key.field}}SetVal(static_cast(objId), key_mf_exact, {{ key.bitwidth }}); - {% endif %} - {% endfor %} - - // SAI object table with multiple P4 table keys - // Copy P4 table keys from appropriate SAI attributes - for (uint32_t i = 0; i < attr_count; i++) - { - auto *md = sai_metadata_get_attr_metadata((sai_object_type_t)SAI_OBJECT_TYPE_{{ api.name | upper }}, attr_list[i].id); - - const char* attrName = md ? md->attridname : "unknown"; - - switch(attr_list[i].id) - { - {% for key in table['keys'] %} - {% if not key.is_object_key %} - {% set value = 'attr_list[i].value' %} - case SAI_{{ api.name | upper }}_ATTR_{{ key.name | upper }}: - { - auto mf = matchActionEntry->add_match(); - mf->set_field_id({{key.id}}); - {% filter indent(8, True) %} - {% if key.match_type == 'exact' %}{{ util.set_key_in_attr_exact(key, value) }} - {% elif key.match_type == 'lpm' %}{{ util.set_key_lpm(key, value) }} - {% elif key.match_type == 'ternary' %}{{ util.set_key_in_attr_ternary(api, key, value) }} - {% elif key.match_type == 'optional' %}{{ util.set_key_optional(key, value) }} - {% elif key.match_type == 'list' %}{{ util.set_key_list(key, value) }} - {% elif key.match_type == 'range_list' %}{{ util.set_key_range_list(key, value) }} - {% endif %} - {% endfilter %} - {% if key.ip_is_v6_field_id != 0 %} - { - // set ip_is_v6_field_id field - auto mf = matchActionEntry->add_match(); - mf->set_field_id({{key.ip_is_v6_field_id}}); - auto mf_exact = mf->mutable_exact(); - booldataSetVal(({{value}}.ipaddr.addr_family == SAI_IP_ADDR_FAMILY_IPV4) ? 0 : 1, mf_exact, 1); - } - {% endif %} - break; - } - {% endif%} - {% endfor %} - {% if table['keys'] | selectattr('match_type', 'ne', 'exact') | list | length > 0 %} - {% if table['keys'] | selectattr('match_type', 'eq', 'lpm') | list | length == 0 %} - // Table has non lpm ternary keys - add priority field - case SAI_{{ api.name | upper }}_ATTR_PRIORITY: - { - matchActionEntry->set_priority(attr_list[i].value.u32); - break; - } - {% endif %} - {% endif %} - default: - DASH_LOG_ERROR("attribute [%d] %d %s not supported yet", i, attr_list[i].id, attrName); - break; - } - } - diff --git a/dash-pipeline/SAI/templates/impls/sai_api_func_quad.cpp.j2 b/dash-pipeline/SAI/templates/impls/sai_api_func_quad.cpp.j2 index 6903f5b68..41be79ab2 100644 --- a/dash-pipeline/SAI/templates/impls/sai_api_func_quad.cpp.j2 +++ b/dash-pipeline/SAI/templates/impls/sai_api_func_quad.cpp.j2 @@ -20,99 +20,16 @@ static sai_status_t dash_sai_create_{{ api.name }}( _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list) { - DASH_LOG_ENTER(); - - auto attrs = dash::DashSai::populateDefaultAttributes((sai_object_type_t)SAI_OBJECT_TYPE_{{ api.name | upper }}, attr_count, attr_list); - attr_count = (uint32_t)attrs.size(); - attr_list = attrs.data(); + auto obj_type = (sai_object_type_t)SAI_OBJECT_TYPE_{{ api.name | upper }}; {% if api.is_object %} - std::shared_ptr matchActionEntry; - pi_p4_id_t tableId = 0; - // There shall be one and only one action_type - p4::v1::TableAction* entry = nullptr; - p4::v1::Action* action = nullptr; - //auto expectedParams = 0; - //auto matchedParams = 0; - sai_object_id_t objId = 0; - // Search the action - pi_p4_id_t actionId = 0; - - {% for table in api.p4_meta.tables %} - {% if table.stage != None %} - // For stage {{ table.stage }} - {% endif %} - matchActionEntry = std::make_shared(); - tableId = {{table.id}}; - entry = matchActionEntry->mutable_action(); - action = entry->mutable_action(); - //expectedParams = 0; - //matchedParams = 0; - objId = dashSai->getNextObjectId((sai_object_type_t)SAI_OBJECT_TYPE_{{ api.name | upper }}); - - if (objId == SAI_NULL_OBJECT_ID) - { - DASH_LOG_ERROR("getNextObjectId failed for SAI_OBJECT_TYPE_{{ api.name | upper }}"); - // TODO clean resources - return SAI_STATUS_FAILURE; - } - - matchActionEntry->set_table_id(tableId); - - {% include 'templates/impls/p4_table_object_match.cpp.j2' %} - - // If there is only one action, simply set it. - // Else, search in the attrs. - {% include 'templates/impls/p4_table_action.cpp.j2' %} - - //assert((matchedParams == expectedParams)); - - //if (matchedParams != expectedParams) { - // goto ErrRet; - //} - if (false == dashSai->insertInTable(matchActionEntry, objId)) { - goto ErrRet; - } - - {% endfor %} - - *{{ api.name }}_id = objId; - return SAI_STATUS_SUCCESS; -ErrRet: - dashSai->removeFromTable(*{{ api.name }}_id); - return SAI_STATUS_FAILURE; + return dashSai->create({{meta_table}}, obj_type, {{ api.name }}_id, switch_id, attr_count, attr_list); {% else %} std::shared_ptr matchActionEntry = std::make_shared(); - pi_p4_id_t tableId = {{table.id}}; - matchActionEntry->set_table_id(tableId); - auto tableEntry = {{ api.name }}; - // There shall be one and only one action_type - auto entry = matchActionEntry->mutable_action(); - auto action = entry->mutable_action(); - //auto expectedParams = 0; - //auto matchedParams = 0; - pi_p4_id_t actionId; - grpc::StatusCode retCode; - - {% include 'templates/impls/p4_table_entry_match.cpp.j2' %} - - - {% include 'templates/impls/p4_table_action.cpp.j2' %} - - //assert((matchedParams == expectedParams)); - - //if (matchedParams != expectedParams) { - // goto ErrRet; - //} - // TODO: ternaly needs to set priority - retCode = dashSai->mutateTableEntry(matchActionEntry, p4::v1::Update_Type_INSERT); + matchActionEntry->set_table_id({{meta_table}}.id); - if (grpc::StatusCode::OK == retCode) - { - return SAI_STATUS_SUCCESS; - } -ErrRet: - return SAI_STATUS_FAILURE; + table_{{api.name}}_add_keys({{ api.name }}, matchActionEntry); + return dashSai->create({{meta_table}}, obj_type, matchActionEntry, attr_count, attr_list); {% endif %} } @@ -120,35 +37,13 @@ static sai_status_t dash_sai_remove_{{ api.name }}( {% include 'templates/headers/sai_api_param_object_id.j2' %}) { {% if api.is_object %} - DASH_LOG_ENTER(); - - if (dashSai->removeFromTable({{ api.name }}_id)) - { - return SAI_STATUS_SUCCESS; - } - - return SAI_STATUS_FAILURE; + return dashSai->remove({{meta_table}}, {{ api.name }}_id); {% else %} - DASH_LOG_ENTER(); - std::shared_ptr matchActionEntry = std::make_shared(); - pi_p4_id_t tableId = {{table.id}}; - matchActionEntry->set_table_id(tableId); - auto tableEntry = {{ api.name }}; - grpc::StatusCode retCode; - - {% include 'templates/impls/p4_table_entry_match.cpp.j2' %} - - retCode = dashSai->mutateTableEntry(matchActionEntry, p4::v1::Update_Type_DELETE); - - if (grpc::StatusCode::OK == retCode) - { - return SAI_STATUS_SUCCESS; - } - -ErrRet: + matchActionEntry->set_table_id({{meta_table}}.id); - return SAI_STATUS_FAILURE; + table_{{api.name}}_add_keys({{ api.name }}, matchActionEntry); + return dashSai->remove({{meta_table}}, matchActionEntry); {% endif %} } diff --git a/dash-pipeline/SAI/templates/impls/sai_api_group.cpp.j2 b/dash-pipeline/SAI/templates/impls/sai_api_group.cpp.j2 index 8308ecc49..1e2b7095f 100644 --- a/dash-pipeline/SAI/templates/impls/sai_api_group.cpp.j2 +++ b/dash-pipeline/SAI/templates/impls/sai_api_group.cpp.j2 @@ -90,6 +90,20 @@ static dash::P4MetaTable {{meta_table}} ( {% endfor %} {% endif%} } +{% if api.p4_meta.tables|length > 1 %} + ,{ // sibling table list for multiple stages + {% for sibling_table in api.p4_meta.tables[1:] %} + { + {{sibling_table.id}}, // {{ sibling_table.stage }} + { // map of action enum id -> action id + {% for name, action in sibling_table.actions.items() %} + { {{name}}, {{action.id}} }, + {% endfor %} + } + }, + {% endfor %} + } +{% endif %} ); {% include 'templates/impls/sai_api_func_quad.cpp.j2' %}