From 7da0894b4afaf3d004d44001d114c4ab326fb362 Mon Sep 17 00:00:00 2001 From: Kamil Cudnik Date: Thu, 1 Jul 2021 23:57:05 +0200 Subject: [PATCH] [sairedis] Client/Server support SAI query API (#848) --- lib/inc/ServerSai.h | 15 +++- lib/src/Makefile.am | 4 +- lib/src/ServerSai.cpp | 184 ++++++++++++++++++++++++++++++++++++++++-- tests/testclient.cpp | 77 ++++++++++++++++++ 4 files changed, 269 insertions(+), 11 deletions(-) diff --git a/lib/inc/ServerSai.h b/lib/inc/ServerSai.h index fc8500a2230a..00d11e050311 100644 --- a/lib/inc/ServerSai.h +++ b/lib/inc/ServerSai.h @@ -261,6 +261,8 @@ namespace sairedis sai_status_t processSingleEvent( _In_ const swss::KeyOpFieldsValuesTuple &kco); + // QUAD API + sai_status_t processQuadEvent( _In_ sai_common_api_t api, _In_ const swss::KeyOpFieldsValuesTuple &kco); @@ -291,7 +293,7 @@ namespace sairedis _In_ uint32_t attr_count, _In_ sai_attribute_t *attr_list); - // BULK + // BULK API sai_status_t processBulkQuadEvent( _In_ sai_common_api_t api, @@ -335,6 +337,17 @@ namespace sairedis _In_ const sai_object_id_t* object_ids, _In_ const sai_status_t* statuses); + // QUERY API + + sai_status_t processAttrCapabilityQuery( + _In_ const swss::KeyOpFieldsValuesTuple &kco); + + sai_status_t processAttrEnumValuesCapabilityQuery( + _In_ const swss::KeyOpFieldsValuesTuple &kco); + + sai_status_t processObjectTypeGetAvailabilityQuery( + _In_ const swss::KeyOpFieldsValuesTuple &kco); + private: bool m_apiInitialized; diff --git a/lib/src/Makefile.am b/lib/src/Makefile.am index 0f23a8f19d34..a936e0b59eb5 100644 --- a/lib/src/Makefile.am +++ b/lib/src/Makefile.am @@ -92,9 +92,9 @@ libsairedis_la_SOURCES = \ sai_redis_vlan.cpp \ sai_redis_wred.cpp -libSaiRedis_a_CPPFLAGS = $(DBGFLAGS) $(AM_CPPFLAGS) $(CFLAGS_COMMON) +libSaiRedis_a_CPPFLAGS = $(DBGFLAGS) $(AM_CPPFLAGS) $(CFLAGS_COMMON) -std=c++14 -libsairedis_la_CPPFLAGS = $(DBGFLAGS) $(AM_CPPFLAGS) $(CFLAGS_COMMON) +libsairedis_la_CPPFLAGS = $(DBGFLAGS) $(AM_CPPFLAGS) $(CFLAGS_COMMON) -std=c++14 libsairedis_la_LIBADD = -lhiredis -lswsscommon libSaiRedis.a diff --git a/lib/src/ServerSai.cpp b/lib/src/ServerSai.cpp index 8befd78f0ed3..f22e4f50e0aa 100644 --- a/lib/src/ServerSai.cpp +++ b/lib/src/ServerSai.cpp @@ -13,6 +13,9 @@ #include "swss/select.h" #include "swss/tokenize.h" +#include +#include + using namespace sairedis; using namespace saimeta; using namespace std::placeholders; @@ -698,14 +701,14 @@ sai_status_t ServerSai::processSingleEvent( // if (op == REDIS_ASIC_STATE_COMMAND_FLUSH) // return processFdbFlush(kco); // -// if (op == REDIS_ASIC_STATE_COMMAND_ATTR_CAPABILITY_QUERY) -// return processAttrCapabilityQuery(kco); -// -// if (op == REDIS_ASIC_STATE_COMMAND_ATTR_ENUM_VALUES_CAPABILITY_QUERY) -// return processAttrEnumValuesCapabilityQuery(kco); -// -// if (op == REDIS_ASIC_STATE_COMMAND_OBJECT_TYPE_GET_AVAILABILITY_QUERY) -// return processObjectTypeGetAvailabilityQuery(kco); + if (op == REDIS_ASIC_STATE_COMMAND_ATTR_CAPABILITY_QUERY) + return processAttrCapabilityQuery(kco); + + if (op == REDIS_ASIC_STATE_COMMAND_ATTR_ENUM_VALUES_CAPABILITY_QUERY) + return processAttrEnumValuesCapabilityQuery(kco); + + if (op == REDIS_ASIC_STATE_COMMAND_OBJECT_TYPE_GET_AVAILABILITY_QUERY) + return processObjectTypeGetAvailabilityQuery(kco); SWSS_LOG_THROW("event op '%s' is not implemented, FIXME", op.c_str()); } @@ -1539,3 +1542,168 @@ void ServerSai::sendBulkApiResponse( m_selectableChannel->set(strStatus, entry, REDIS_ASIC_STATE_COMMAND_GETRESPONSE); } + +sai_status_t ServerSai::processAttrCapabilityQuery( + _In_ const swss::KeyOpFieldsValuesTuple &kco) +{ + SWSS_LOG_ENTER(); + + auto& strSwitchOid = kfvKey(kco); + + sai_object_id_t switchOid; + sai_deserialize_object_id(strSwitchOid, switchOid); + + auto& values = kfvFieldsValues(kco); + + if (values.size() != 2) + { + SWSS_LOG_ERROR("Invalid input: expected 2 arguments, received %zu", values.size()); + + m_selectableChannel->set(sai_serialize_status(SAI_STATUS_INVALID_PARAMETER), {}, REDIS_ASIC_STATE_COMMAND_ATTR_CAPABILITY_RESPONSE); + + return SAI_STATUS_INVALID_PARAMETER; + } + + sai_object_type_t objectType; + sai_deserialize_object_type(fvValue(values[0]), objectType); + + sai_attr_id_t attrId; + sai_deserialize_attr_id(fvValue(values[1]), attrId); + + sai_attr_capability_t capability; + + sai_status_t status = m_sai->queryAttributeCapability(switchOid, objectType, attrId, &capability); + + std::vector entry; + + if (status == SAI_STATUS_SUCCESS) + { + entry = + { + swss::FieldValueTuple("CREATE_IMPLEMENTED", (capability.create_implemented ? "true" : "false")), + swss::FieldValueTuple("SET_IMPLEMENTED", (capability.set_implemented ? "true" : "false")), + swss::FieldValueTuple("GET_IMPLEMENTED", (capability.get_implemented ? "true" : "false")) + }; + + SWSS_LOG_INFO("Sending response: create_implemented:%d, set_implemented:%d, get_implemented:%d", + capability.create_implemented, capability.set_implemented, capability.get_implemented); + } + + m_selectableChannel->set(sai_serialize_status(status), entry, REDIS_ASIC_STATE_COMMAND_ATTR_CAPABILITY_RESPONSE); + + return status; +} + +sai_status_t ServerSai::processAttrEnumValuesCapabilityQuery( + _In_ const swss::KeyOpFieldsValuesTuple &kco) +{ + SWSS_LOG_ENTER(); + + auto& strSwitchOid = kfvKey(kco); + + sai_object_id_t switchOid; + sai_deserialize_object_id(strSwitchOid, switchOid); + + auto& values = kfvFieldsValues(kco); + + if (values.size() != 3) + { + SWSS_LOG_ERROR("Invalid input: expected 3 arguments, received %zu", values.size()); + + m_selectableChannel->set(sai_serialize_status(SAI_STATUS_INVALID_PARAMETER), {}, REDIS_ASIC_STATE_COMMAND_ATTR_ENUM_VALUES_CAPABILITY_RESPONSE); + + return SAI_STATUS_INVALID_PARAMETER; + } + + sai_object_type_t objectType; + sai_deserialize_object_type(fvValue(values[0]), objectType); + + sai_attr_id_t attrId; + sai_deserialize_attr_id(fvValue(values[1]), attrId); + + uint32_t list_size = std::stoi(fvValue(values[2])); + + std::vector enum_capabilities_list(list_size); + + sai_s32_list_t enumCapList; + + enumCapList.count = list_size; + enumCapList.list = enum_capabilities_list.data(); + + sai_status_t status = m_sai->queryAattributeEnumValuesCapability(switchOid, objectType, attrId, &enumCapList); + + std::vector entry; + + if (status == SAI_STATUS_SUCCESS) + { + std::vector vec; + std::transform(enumCapList.list, enumCapList.list + enumCapList.count, + std::back_inserter(vec), [](auto&e) { return std::to_string(e); }); + + std::ostringstream join; + std::copy(vec.begin(), vec.end(), std::ostream_iterator(join, ",")); + + auto strCap = join.str(); + + entry = + { + swss::FieldValueTuple("ENUM_CAPABILITIES", strCap), + swss::FieldValueTuple("ENUM_COUNT", std::to_string(enumCapList.count)) + }; + + SWSS_LOG_DEBUG("Sending response: capabilities = '%s', count = %d", strCap.c_str(), enumCapList.count); + } + + m_selectableChannel->set(sai_serialize_status(status), entry, REDIS_ASIC_STATE_COMMAND_ATTR_ENUM_VALUES_CAPABILITY_RESPONSE); + + return status; +} + +sai_status_t ServerSai::processObjectTypeGetAvailabilityQuery( + _In_ const swss::KeyOpFieldsValuesTuple &kco) +{ + SWSS_LOG_ENTER(); + + auto& strSwitchOid = kfvKey(kco); + + sai_object_id_t switchOid; + sai_deserialize_object_id(strSwitchOid, switchOid); + + std::vector values = kfvFieldsValues(kco); + + // needs to pop the object type off the end of the list in order to + // retrieve the attribute list + + sai_object_type_t objectType; + sai_deserialize_object_type(fvValue(values.back()), objectType); + + values.pop_back(); + + SaiAttributeList list(objectType, values, false); + + sai_attribute_t *attr_list = list.get_attr_list(); + + uint32_t attr_count = list.get_attr_count(); + + uint64_t count; + + sai_status_t status = m_sai->objectTypeGetAvailability( + switchOid, + objectType, + attr_count, + attr_list, + &count); + + std::vector entry; + + if (status == SAI_STATUS_SUCCESS) + { + entry.push_back(swss::FieldValueTuple("OBJECT_COUNT", std::to_string(count))); + + SWSS_LOG_DEBUG("Sending response: count = %lu", count); + } + + m_selectableChannel->set(sai_serialize_status(status), entry, REDIS_ASIC_STATE_COMMAND_OBJECT_TYPE_GET_AVAILABILITY_RESPONSE); + + return status; +} diff --git a/tests/testclient.cpp b/tests/testclient.cpp index 47230ab4d58c..9d508ecf33ab 100644 --- a/tests/testclient.cpp +++ b/tests/testclient.cpp @@ -23,6 +23,8 @@ class TestClient void test_bulk_create_vlan(); + void test_query_api(); + private: int profileGetNextValue( @@ -336,6 +338,79 @@ void TestClient::test_bulk_create_vlan() ASSERT_SUCCESS(sai_api_uninitialize()); } +void TestClient::test_query_api() +{ + SWSS_LOG_ENTER(); + + m_profileMap.clear(); + + m_profileMap[SAI_REDIS_KEY_ENABLE_CLIENT] = "true"; // act as a client + + m_profileIter = m_profileMap.begin(); + + m_smt.profileGetValue = std::bind(&TestClient::profileGetValue, this, _1, _2); + m_smt.profileGetNextValue = std::bind(&TestClient::profileGetNextValue, this, _1, _2, _3); + + m_test_services = m_smt.getServiceMethodTable(); + + ASSERT_SUCCESS(sai_api_initialize(0, &m_test_services)); + + sai_switch_api_t* switch_api; + + ASSERT_SUCCESS(sai_api_query(SAI_API_SWITCH, (void**)&switch_api)); + + sai_attribute_t attr; + + // connect to existing switch + attr.id = SAI_SWITCH_ATTR_INIT_SWITCH; + attr.value.booldata = false; + + sai_object_id_t switch_id = SAI_NULL_OBJECT_ID; + + ASSERT_SUCCESS(switch_api->create_switch(&switch_id, 1, &attr)); + + ASSERT_TRUE(switch_id != SAI_NULL_OBJECT_ID); + + SWSS_LOG_NOTICE("switchId: %s", sai_serialize_object_id(switch_id).c_str()); + + sai_attr_capability_t cap; + + SWSS_LOG_NOTICE(" * sai_query_attribute_capability"); + + ASSERT_SUCCESS(sai_query_attribute_capability( + switch_id, + SAI_OBJECT_TYPE_SWITCH, + SAI_SWITCH_ATTR_INIT_SWITCH, + &cap)); + + int32_t vec[3]; + sai_s32_list_t list; + + list.count = 3; + list.list = vec; + + SWSS_LOG_NOTICE(" * sai_query_attribute_enum_values_capability"); + + ASSERT_SUCCESS(sai_query_attribute_enum_values_capability( + switch_id, + SAI_OBJECT_TYPE_DEBUG_COUNTER, + SAI_DEBUG_COUNTER_ATTR_IN_DROP_REASON_LIST, + &list)); + + uint64_t count; + + SWSS_LOG_NOTICE(" * sai_object_type_get_availability"); + + ASSERT_SUCCESS(sai_object_type_get_availability( + switch_id, + SAI_OBJECT_TYPE_DEBUG_COUNTER, + 0, + NULL, + &count)); + + ASSERT_SUCCESS(sai_api_uninitialize()); +} + int main() { swss::Logger::getInstance().setMinPrio(swss::Logger::SWSS_DEBUG); @@ -350,5 +425,7 @@ int main() tc.test_bulk_create_vlan(); + tc.test_query_api(); + return EXIT_SUCCESS; }