proxylib/Sai.cpp (851 lines of code) (raw):
#include "Sai.h"
#include "Utils.h"
#include "SaiInternal.h"
#include "ZeroMQChannel.h"
#include "SaiAttributeList.h"
#include "NotificationFactory.h"
#include "meta/Meta.h"
#include "meta/sai_serialize.h"
using namespace saiproxy;
using namespace std::placeholders;
#define PROXY_CHECK_API_INITIALIZED() \
if (!m_apiInitialized) { \
SWSS_LOG_ERROR("%s: api not initialized", __PRETTY_FUNCTION__); \
return SAI_STATUS_FAILURE; }
#define PROXY_CHECK_POINTER(pointer) \
if ((pointer) == nullptr) { \
SWSS_LOG_ERROR("entry pointer " # pointer " is null"); \
return SAI_STATUS_INVALID_PARAMETER; }
Sai::Sai()
{
SWSS_LOG_ENTER();
m_apiInitialized = false;
}
Sai::~Sai()
{
SWSS_LOG_ENTER();
if (m_apiInitialized)
{
apiUninitialize();
}
}
// INITIALIZE UNINITIALIZE
sai_status_t Sai::apiInitialize(
_In_ uint64_t flags,
_In_ const sai_service_method_table_t *service_method_table)
{
MUTEX();
SWSS_LOG_ENTER();
if (m_apiInitialized)
{
SWSS_LOG_ERROR("%s: api already initialized", __PRETTY_FUNCTION__);
return SAI_STATUS_FAILURE;
}
if (flags != 0)
{
SWSS_LOG_ERROR("invalid flags passed to SAI API initialize");
return SAI_STATUS_INVALID_PARAMETER;
}
if ((service_method_table == NULL) ||
(service_method_table->profile_get_next_value == NULL) ||
(service_method_table->profile_get_value == NULL))
{
SWSS_LOG_ERROR("invalid service_method_table handle passed to SAI API initialize");
return SAI_STATUS_INVALID_PARAMETER;
}
memcpy(&m_service_method_table, service_method_table, sizeof(m_service_method_table));
memset(&m_sn, 0, sizeof(m_sn));
m_options = std::make_shared<Options>(); // load default options
// TODO options should be obtained from service method table
m_communicationChannel = std::make_shared<sairedis::ZeroMQChannel>(
m_options->m_zmqChannel,
m_options->m_zmqNtfChannel,
std::bind(&Sai::handleNotification, this, _1, _2, _3));
m_apiInitialized = true;
return SAI_STATUS_SUCCESS;
}
sai_status_t Sai::apiUninitialize(void)
{
SWSS_LOG_ENTER();
PROXY_CHECK_API_INITIALIZED();
SWSS_LOG_NOTICE("begin");
m_communicationChannel = nullptr; // will stop the thread
m_apiInitialized = false;
SWSS_LOG_NOTICE("end");
return SAI_STATUS_SUCCESS;
}
// QUAD OID
sai_status_t Sai::create(
_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)
{
MUTEX();
SWSS_LOG_ENTER();
PROXY_CHECK_API_INITIALIZED();
auto entry = saimeta::SaiAttributeList::serialize_attr_list(objectType, attr_count, attr_list, false);
entry.emplace_back("SWITCH_ID", sai_serialize_object_id(switchId)); // last entry is switch_id
auto serializedObjectType = sai_serialize_object_type(objectType);
auto serializedObjectId = sai_serialize_object_id(SAI_NULL_OBJECT_ID);
std::string key = serializedObjectType + ":" + serializedObjectId;
m_communicationChannel->set(key, entry, "create");
swss::KeyOpFieldsValuesTuple kco;
auto status = m_communicationChannel->wait("create_response", kco);
if (status == SAI_STATUS_SUCCESS)
{
if (objectType == SAI_OBJECT_TYPE_SWITCH)
{
updateNotifications(attr_count, attr_list); // TODO should be per switch
}
auto& values = kfvFieldsValues(kco);
if (values.size() == 0)
{
SWSS_LOG_THROW("logic error, api returned 0 values!");
}
SWSS_LOG_NOTICE("deserialize new object id: %s", fvValue(values[0]).c_str());
sai_deserialize_object_id(fvValue(values[0]), *objectId);
}
return status;
}
sai_status_t Sai::remove(
_In_ sai_object_type_t objectType,
_In_ sai_object_id_t objectId)
{
MUTEX();
SWSS_LOG_ENTER();
PROXY_CHECK_API_INITIALIZED();
return remove(objectType, sai_serialize_object_id(objectId));
}
sai_status_t Sai::set(
_In_ sai_object_type_t objectType,
_In_ sai_object_id_t objectId,
_In_ const sai_attribute_t *attr)
{
MUTEX();
SWSS_LOG_ENTER();
PROXY_CHECK_API_INITIALIZED();
return set(objectType, sai_serialize_object_id(objectId), attr);
}
sai_status_t Sai::get(
_In_ sai_object_type_t objectType,
_In_ sai_object_id_t objectId,
_In_ uint32_t attr_count,
_Inout_ sai_attribute_t *attr_list)
{
MUTEX();
SWSS_LOG_ENTER();
PROXY_CHECK_API_INITIALIZED();
return get(objectType, sai_serialize_object_id(objectId), attr_count, attr_list);
}
// QUAD ENTRY
#define DECLARE_CREATE_ENTRY(OT,ot) \
sai_status_t Sai::create( \
_In_ const sai_ ## ot ## _t* entry, \
_In_ uint32_t attr_count, \
_In_ const sai_attribute_t *attr_list) \
{ \
MUTEX(); \
SWSS_LOG_ENTER(); \
PROXY_CHECK_API_INITIALIZED(); \
PROXY_CHECK_POINTER(entry) \
return create( \
(sai_object_type_t)SAI_OBJECT_TYPE_ ## OT, \
sai_serialize_ ## ot(*entry), \
attr_count, \
attr_list); \
}
SAIREDIS_DECLARE_EVERY_ENTRY(DECLARE_CREATE_ENTRY);
#define DECLARE_REMOVE_ENTRY(OT,ot) \
sai_status_t Sai::remove( \
_In_ const sai_ ## ot ## _t* entry) \
{ \
MUTEX(); \
SWSS_LOG_ENTER(); \
PROXY_CHECK_API_INITIALIZED(); \
PROXY_CHECK_POINTER(entry) \
return remove( \
(sai_object_type_t)SAI_OBJECT_TYPE_ ## OT, \
sai_serialize_ ## ot(*entry)); \
}
SAIREDIS_DECLARE_EVERY_ENTRY(DECLARE_REMOVE_ENTRY);
#define DECLARE_SET_ENTRY(OT,ot) \
sai_status_t Sai::set( \
_In_ const sai_ ## ot ## _t* entry, \
_In_ const sai_attribute_t *attr) \
{ \
MUTEX(); \
SWSS_LOG_ENTER(); \
PROXY_CHECK_API_INITIALIZED(); \
PROXY_CHECK_POINTER(entry) \
return set( \
(sai_object_type_t)SAI_OBJECT_TYPE_ ## OT, \
sai_serialize_ ## ot(*entry), \
attr); \
}
SAIREDIS_DECLARE_EVERY_ENTRY(DECLARE_SET_ENTRY);
#define DECLARE_GET_ENTRY(OT,ot) \
sai_status_t Sai::get( \
_In_ const sai_ ## ot ## _t* entry, \
_In_ uint32_t attr_count, \
_Inout_ sai_attribute_t *attr_list) \
{ \
MUTEX(); \
SWSS_LOG_ENTER(); \
PROXY_CHECK_API_INITIALIZED(); \
PROXY_CHECK_POINTER(entry) \
return get( \
(sai_object_type_t)SAI_OBJECT_TYPE_ ## OT, \
sai_serialize_ ## ot(*entry), \
attr_count, \
attr_list); \
}
SAIREDIS_DECLARE_EVERY_ENTRY(DECLARE_GET_ENTRY);
sai_status_t Sai::create(
_In_ sai_object_type_t objectType,
_In_ const std::string& entry,
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list)
{
SWSS_LOG_ENTER();
auto vals = saimeta::SaiAttributeList::serialize_attr_list(objectType, attr_count, attr_list, false);
auto serializedObjectType = sai_serialize_object_type(objectType);
std::string key = serializedObjectType + ":" + entry;
m_communicationChannel->set(key, vals, "create_entry");
swss::KeyOpFieldsValuesTuple kco;
return m_communicationChannel->wait("create_entry_response", kco);
}
sai_status_t Sai::remove(
_In_ sai_object_type_t objectType,
_In_ const std::string& entry)
{
SWSS_LOG_ENTER();
auto serializedObjectType = sai_serialize_object_type(objectType);
std::string key = serializedObjectType + ":" + entry;
m_communicationChannel->set(key, {}, "remove");
swss::KeyOpFieldsValuesTuple kco;
return m_communicationChannel->wait("remove_response", kco);
}
sai_status_t Sai::set(
_In_ sai_object_type_t objectType,
_In_ const std::string& entry,
_In_ const sai_attribute_t *attr)
{
SWSS_LOG_ENTER();
auto val = saimeta::SaiAttributeList::serialize_attr_list(objectType, 1, attr, false);
auto serializedObjectType = sai_serialize_object_type(objectType);
std::string key = serializedObjectType + ":" + entry;
m_communicationChannel->set(key, val, "set");
swss::KeyOpFieldsValuesTuple kco;
auto status = m_communicationChannel->wait("set_response", kco);
if (objectType == SAI_OBJECT_TYPE_SWITCH && status == SAI_STATUS_SUCCESS)
{
updateNotifications(1, attr);
}
return status;
}
sai_status_t Sai::get(
_In_ sai_object_type_t objectType,
_In_ const std::string& entry,
_In_ uint32_t attr_count,
_Inout_ sai_attribute_t *attr_list)
{
SWSS_LOG_ENTER();
/*
* Since user may reuse buffers, then oid list buffers maybe not cleared
* and contain some garbage, let's clean them so we send all oids as null to
* syncd.
*/
sairedis::Utils::clearOidValues(objectType, attr_count, attr_list);
auto vals = saimeta::SaiAttributeList::serialize_attr_list(objectType, attr_count, attr_list, false);
std::string serializedObjectType = sai_serialize_object_type(objectType);
std::string key = serializedObjectType + ":" + entry;
m_communicationChannel->set(key, vals, "get");
swss::KeyOpFieldsValuesTuple kco;
auto status = m_communicationChannel->wait("get_response", kco);
auto &values = kfvFieldsValues(kco);
if (status == SAI_STATUS_SUCCESS)
{
if (values.size() == 0)
{
SWSS_LOG_THROW("logic error, api returned 0 values!");
}
saimeta::SaiAttributeList list(objectType, values, false);
transfer_attributes(objectType, attr_count, list.get_attr_list(), attr_list, false);
}
else if (status == SAI_STATUS_BUFFER_OVERFLOW)
{
if (values.size() == 0)
{
SWSS_LOG_THROW("logic error, api returned 0 values!");
}
saimeta::SaiAttributeList list(objectType, values, true);
transfer_attributes(objectType, attr_count, list.get_attr_list(), attr_list, true);
}
return status;
}
// STATS
sai_status_t Sai::getStats(
_In_ sai_object_type_t object_type,
_In_ sai_object_id_t object_id,
_In_ uint32_t number_of_counters,
_In_ const sai_stat_id_t *counter_ids,
_Out_ uint64_t *counters)
{
MUTEX();
SWSS_LOG_ENTER();
PROXY_CHECK_API_INITIALIZED();
auto oi = sai_metadata_get_object_type_info(object_type);
if (oi == NULL)
{
SWSS_LOG_ERROR("invalid object type: %s", sai_serialize_object_type(object_type).c_str());
return SAI_STATUS_INVALID_PARAMETER;
}
auto strObjectType = sai_serialize_object_type(object_type);
auto strObjectId = sai_serialize_object_id(object_id);
std::string key = strObjectType + ":" + strObjectId;
std::vector<swss::FieldValueTuple> entry;
for (uint32_t i = 0; i < number_of_counters; i++)
{
entry.emplace_back(sai_serialize_enum(counter_ids[i], oi->statenum), "");
}
m_communicationChannel->set(key, entry, "get_stats");
swss::KeyOpFieldsValuesTuple kco;
auto status = m_communicationChannel->wait("get_stats_response", kco);
if (status == SAI_STATUS_SUCCESS)
{
auto &values = kfvFieldsValues(kco);
if (values.size () != number_of_counters)
{
SWSS_LOG_THROW("logic error, wrong number of counters, got %zu, expected %u", values.size(), number_of_counters);
}
for (uint32_t idx = 0; idx < number_of_counters; idx++)
{
counters[idx] = stoull(fvValue(values[idx]));
}
}
return status;
}
sai_status_t Sai::getStatsExt(
_In_ sai_object_type_t object_type,
_In_ sai_object_id_t object_id,
_In_ uint32_t number_of_counters,
_In_ const sai_stat_id_t *counter_ids,
_In_ sai_stats_mode_t mode,
_Out_ uint64_t *counters)
{
MUTEX();
SWSS_LOG_ENTER();
PROXY_CHECK_API_INITIALIZED();
auto oi = sai_metadata_get_object_type_info(object_type);
if (oi == NULL)
{
SWSS_LOG_ERROR("invalid object type: %s", sai_serialize_object_type(object_type).c_str());
return SAI_STATUS_INVALID_PARAMETER;
}
auto strObjectType = sai_serialize_object_type(object_type);
auto strObjectId = sai_serialize_object_id(object_id);
std::string key = strObjectType + ":" + strObjectId;
std::vector<swss::FieldValueTuple> entry;
for (uint32_t i = 0; i < number_of_counters; i++)
{
entry.emplace_back(sai_serialize_enum(counter_ids[i], oi->statenum), "");
}
entry.emplace_back("STATS_MODE", std::to_string(mode)); // TODO add serialize
m_communicationChannel->set(key, entry, "get_stats_ext");
swss::KeyOpFieldsValuesTuple kco;
auto status = m_communicationChannel->wait("get_stats_ext_response", kco);
if (status == SAI_STATUS_SUCCESS)
{
auto &values = kfvFieldsValues(kco);
if (values.size () != number_of_counters)
{
SWSS_LOG_THROW("logic error, wrong number of counters, got %zu, expected %u", values.size(), number_of_counters);
}
for (uint32_t idx = 0; idx < number_of_counters; idx++)
{
counters[idx] = stoull(fvValue(values[idx]));
}
}
return status;
}
sai_status_t Sai::clearStats(
_In_ sai_object_type_t object_type,
_In_ sai_object_id_t object_id,
_In_ uint32_t number_of_counters,
_In_ const sai_stat_id_t *counter_ids)
{
MUTEX();
SWSS_LOG_ENTER();
PROXY_CHECK_API_INITIALIZED();
auto oi = sai_metadata_get_object_type_info(object_type);
if (oi == NULL)
{
SWSS_LOG_ERROR("invalid object type: %s", sai_serialize_object_type(object_type).c_str());
return SAI_STATUS_INVALID_PARAMETER;
}
auto strObjectType = sai_serialize_object_type(object_type);
auto strObjectId = sai_serialize_object_id(object_id);
std::string key = strObjectType + ":" + strObjectId;
std::vector<swss::FieldValueTuple> entry;
for (uint32_t i = 0; i < number_of_counters; i++)
{
entry.emplace_back(sai_serialize_enum(counter_ids[i], oi->statenum), "");
}
m_communicationChannel->set(key, entry, "clear_stats");
swss::KeyOpFieldsValuesTuple kco;
return m_communicationChannel->wait("clear_stats_response", kco);
}
sai_status_t Sai::queryStatsCapability(
_In_ sai_object_id_t switchId,
_In_ sai_object_type_t objectType,
_Inout_ sai_stat_capability_list_t *stats_capability)
{
SWSS_LOG_ENTER();
SWSS_LOG_ERROR("not implemented, FIXME");
return SAI_STATUS_NOT_IMPLEMENTED;
}
sai_status_t Sai::queryStatsStCapability(
_In_ sai_object_id_t switchId,
_In_ sai_object_type_t objectType,
_Inout_ sai_stat_st_capability_list_t *stats_capability)
{
SWSS_LOG_ENTER();
SWSS_LOG_ERROR("not implemented, FIXME");
// TODO: Fix me
return SAI_STATUS_NOT_IMPLEMENTED;
}
// BULK STATS
sai_status_t Sai::bulkGetStats(
_In_ sai_object_id_t switchId,
_In_ sai_object_type_t object_type,
_In_ uint32_t object_count,
_In_ const sai_object_key_t *object_key,
_In_ uint32_t number_of_counters,
_In_ const sai_stat_id_t *counter_ids,
_In_ sai_stats_mode_t mode,
_Inout_ sai_status_t *object_statuses,
_Out_ uint64_t *counters)
{
SWSS_LOG_ENTER();
SWSS_LOG_ERROR("not implemented, FIXME");
return SAI_STATUS_NOT_IMPLEMENTED;
}
sai_status_t Sai::bulkClearStats(
_In_ sai_object_id_t switchId,
_In_ sai_object_type_t object_type,
_In_ uint32_t object_count,
_In_ const sai_object_key_t *object_key,
_In_ uint32_t number_of_counters,
_In_ const sai_stat_id_t *counter_ids,
_In_ sai_stats_mode_t mode,
_Inout_ sai_status_t *object_statuses)
{
SWSS_LOG_ENTER();
SWSS_LOG_ERROR("not implemented, FIXME");
return SAI_STATUS_NOT_IMPLEMENTED;
}
// BULK QUAD OID
sai_status_t Sai::bulkCreate(
_In_ sai_object_type_t object_type,
_In_ sai_object_id_t switch_id,
_In_ uint32_t object_count,
_In_ const uint32_t *attr_count,
_In_ const sai_attribute_t **attr_list,
_In_ sai_bulk_op_error_mode_t mode,
_Out_ sai_object_id_t *object_id,
_Out_ sai_status_t *object_statuses)
{
MUTEX();
SWSS_LOG_ENTER();
PROXY_CHECK_API_INITIALIZED();
PROXY_CHECK_POINTER(object_id);
PROXY_CHECK_POINTER(object_statuses);
SWSS_LOG_ERROR("not implemented, FIXME");
return SAI_STATUS_NOT_IMPLEMENTED;
}
sai_status_t Sai::bulkRemove(
_In_ sai_object_type_t object_type,
_In_ uint32_t object_count,
_In_ const sai_object_id_t *object_id,
_In_ sai_bulk_op_error_mode_t mode,
_Out_ sai_status_t *object_statuses)
{
MUTEX();
SWSS_LOG_ENTER();
PROXY_CHECK_API_INITIALIZED();
PROXY_CHECK_POINTER(object_id);
PROXY_CHECK_POINTER(object_statuses);
SWSS_LOG_ERROR("not implemented, FIXME");
return SAI_STATUS_NOT_IMPLEMENTED;
}
sai_status_t Sai::bulkSet(
_In_ sai_object_type_t object_type,
_In_ uint32_t object_count,
_In_ const sai_object_id_t *object_id,
_In_ const sai_attribute_t *attr_list,
_In_ sai_bulk_op_error_mode_t mode,
_Out_ sai_status_t *object_statuses)
{
MUTEX();
SWSS_LOG_ENTER();
PROXY_CHECK_API_INITIALIZED();
PROXY_CHECK_POINTER(object_statuses);
SWSS_LOG_ERROR("not implemented, FIXME");
return SAI_STATUS_NOT_IMPLEMENTED;
}
sai_status_t Sai::bulkGet(
_In_ sai_object_type_t object_type,
_In_ uint32_t object_count,
_In_ const sai_object_id_t *object_id,
_In_ const uint32_t *attr_count,
_Inout_ sai_attribute_t **attr_list,
_In_ sai_bulk_op_error_mode_t mode,
_Out_ sai_status_t *object_statuses)
{
MUTEX();
SWSS_LOG_ENTER();
SWSS_LOG_ERROR("not implemented, FIXME");
return SAI_STATUS_NOT_IMPLEMENTED;
}
// BULK QUAD ENTRY
#define DECLARE_BULK_CREATE_ENTRY(OT,ot) \
sai_status_t Sai::bulkCreate( \
_In_ uint32_t object_count, \
_In_ const sai_ ## ot ## _t* entries, \
_In_ const uint32_t *attr_count, \
_In_ const sai_attribute_t **attr_list, \
_In_ sai_bulk_op_error_mode_t mode, \
_Out_ sai_status_t *object_statuses) \
{ \
MUTEX(); \
SWSS_LOG_ENTER(); \
PROXY_CHECK_API_INITIALIZED(); \
PROXY_CHECK_POINTER(entries) \
SWSS_LOG_ERROR("not implemented, FIXME"); \
return SAI_STATUS_NOT_IMPLEMENTED; \
}
SAIREDIS_DECLARE_EVERY_BULK_ENTRY(DECLARE_BULK_CREATE_ENTRY);
// BULK REMOVE
#define DECLARE_BULK_REMOVE_ENTRY(OT,ot) \
sai_status_t Sai::bulkRemove( \
_In_ uint32_t object_count, \
_In_ const sai_ ## ot ## _t *entries, \
_In_ sai_bulk_op_error_mode_t mode, \
_Out_ sai_status_t *object_statuses) \
{ \
MUTEX(); \
SWSS_LOG_ENTER(); \
PROXY_CHECK_API_INITIALIZED(); \
PROXY_CHECK_POINTER(entries) \
SWSS_LOG_ERROR("not implemented, FIXME"); \
return SAI_STATUS_NOT_IMPLEMENTED; \
}
SAIREDIS_DECLARE_EVERY_BULK_ENTRY(DECLARE_BULK_REMOVE_ENTRY);
// BULK SET
#define DECLARE_BULK_SET_ENTRY(OT,ot) \
sai_status_t Sai::bulkSet( \
_In_ uint32_t object_count, \
_In_ const sai_ ## ot ## _t *entries, \
_In_ const sai_attribute_t *attr_list, \
_In_ sai_bulk_op_error_mode_t mode, \
_Out_ sai_status_t *object_statuses) \
{ \
MUTEX(); \
SWSS_LOG_ENTER(); \
PROXY_CHECK_API_INITIALIZED(); \
PROXY_CHECK_POINTER(entries) \
SWSS_LOG_ERROR("not implemented, FIXME"); \
return SAI_STATUS_NOT_IMPLEMENTED; \
}
SAIREDIS_DECLARE_EVERY_BULK_ENTRY(DECLARE_BULK_SET_ENTRY);
// BULK GET
#define DECLARE_BULK_GET_ENTRY(OT,ot) \
sai_status_t Sai::bulkGet( \
_In_ uint32_t object_count, \
_In_ const sai_ ## ot ## _t *ot, \
_In_ const uint32_t *attr_count, \
_Inout_ sai_attribute_t **attr_list, \
_In_ sai_bulk_op_error_mode_t mode, \
_Out_ sai_status_t *object_statuses) \
{ \
MUTEX(); \
SWSS_LOG_ENTER(); \
SWSS_LOG_ERROR("FIXME not implemented"); \
return SAI_STATUS_NOT_IMPLEMENTED; \
}
SAIREDIS_DECLARE_EVERY_BULK_ENTRY(DECLARE_BULK_GET_ENTRY);
// NON QUAD API
sai_status_t Sai::flushFdbEntries(
_In_ sai_object_id_t switch_id,
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list)
{
MUTEX();
SWSS_LOG_ENTER();
PROXY_CHECK_API_INITIALIZED();
auto entry = saimeta::SaiAttributeList::serialize_attr_list(
SAI_OBJECT_TYPE_FDB_FLUSH,
attr_count,
attr_list,
false);
std::string serializedObjectId = sai_serialize_object_type(SAI_OBJECT_TYPE_FDB_FLUSH);
// NOTE ! we actually give switch ID since FLUSH is not real object
std::string key = serializedObjectId + ":" + sai_serialize_object_id(switch_id);
SWSS_LOG_NOTICE("flush key: %s, fields: %lu", key.c_str(), entry.size());
m_communicationChannel->set(key, entry, "flush_fdb_entries");
swss::KeyOpFieldsValuesTuple kco;
return m_communicationChannel->wait("flush_fdb_entries_response", kco);
}
// SAI API
sai_status_t Sai::objectTypeGetAvailability(
_In_ sai_object_id_t switchId,
_In_ sai_object_type_t objectType,
_In_ uint32_t attrCount,
_In_ const sai_attribute_t *attrList,
_Out_ uint64_t *count)
{
MUTEX();
SWSS_LOG_ENTER();
PROXY_CHECK_API_INITIALIZED();
auto strSwitchId = sai_serialize_object_id(switchId);
auto entry = saimeta::SaiAttributeList::serialize_attr_list(objectType, attrCount, attrList, false);
entry.emplace_back("OBJECT_TYPE", sai_serialize_object_type(objectType));
m_communicationChannel->set(strSwitchId, entry, "object_type_get_availability");
swss::KeyOpFieldsValuesTuple kco;
auto status = m_communicationChannel->wait("object_type_get_availability_response", kco);
if (status == SAI_STATUS_SUCCESS)
{
auto& values = kfvFieldsValues(kco);
if (values.size() == 0)
{
SWSS_LOG_THROW("logic error, api returned 0 values!");
}
*count = std::stoull(fvValue(values[0]));
}
return status;
}
sai_status_t Sai::queryAttributeCapability(
_In_ sai_object_id_t switchId,
_In_ sai_object_type_t objectType,
_In_ sai_attr_id_t attrId,
_Out_ sai_attr_capability_t *capability)
{
MUTEX();
SWSS_LOG_ENTER();
PROXY_CHECK_API_INITIALIZED();
auto strSwitchId = sai_serialize_object_id(switchId);
auto strObjectType = sai_serialize_object_type(objectType);
auto meta = sai_metadata_get_attr_metadata(objectType, attrId);
if (meta == NULL)
{
SWSS_LOG_ERROR("Failed to find attribute metadata: object type %s, attr id %d", strObjectType.c_str(), attrId);
return SAI_STATUS_INVALID_PARAMETER;
}
const std::string attrIdStr = meta->attridname;
const std::vector<swss::FieldValueTuple> entry =
{
swss::FieldValueTuple("OBJECT_TYPE", strObjectType),
swss::FieldValueTuple("ATTR_ID", attrIdStr)
};
m_communicationChannel->set(strSwitchId, entry, "query_attribute_capability");
swss::KeyOpFieldsValuesTuple kco;
auto status = m_communicationChannel->wait("query_attribute_capability_response", kco);
if (status == SAI_STATUS_SUCCESS)
{
auto &values = kfvFieldsValues(kco);
if (values.size() != 3)
{
SWSS_LOG_ERROR("logic error, api returned invalin numer in response: expected 3 values, received %zu", values.size());
return SAI_STATUS_FAILURE;
}
capability->create_implemented = (fvValue(values[0]) == "true" ? true : false);
capability->set_implemented = (fvValue(values[1]) == "true" ? true : false);
capability->get_implemented = (fvValue(values[2]) == "true" ? true : false);
}
return status;
}
sai_status_t Sai::queryAttributeEnumValuesCapability(
_In_ sai_object_id_t switchId,
_In_ sai_object_type_t objectType,
_In_ sai_attr_id_t attrId,
_Inout_ sai_s32_list_t *enumValuesCapability)
{
MUTEX();
SWSS_LOG_ENTER();
PROXY_CHECK_API_INITIALIZED();
if (enumValuesCapability && enumValuesCapability->list)
{
// clear input list, since we use serialize to transfer values
for (uint32_t idx = 0; idx < enumValuesCapability->count; idx++)
{
enumValuesCapability->list[idx] = 0;
}
}
auto strSwitchId = sai_serialize_object_id(switchId);
auto strObjectType = sai_serialize_object_type(objectType);
auto meta = sai_metadata_get_attr_metadata(objectType, attrId);
if (meta == NULL)
{
SWSS_LOG_ERROR("Failed to find attribute metadata: object type %s, attr id %d", strObjectType.c_str(), attrId);
return SAI_STATUS_INVALID_PARAMETER;
}
const std::string strAttrId = meta->attridname;
const std::string listSize = std::to_string(enumValuesCapability->count);
const std::vector<swss::FieldValueTuple> entry =
{
swss::FieldValueTuple("OBJECT_TYPE", strObjectType),
swss::FieldValueTuple("ATTR_ID", strAttrId),
swss::FieldValueTuple("LIST_SIZE", listSize)
};
m_communicationChannel->set(strSwitchId, entry, "query_attribute_enum_values_capability");
swss::KeyOpFieldsValuesTuple kco;
auto status = m_communicationChannel->wait("query_attribute_enum_values_capability_response", kco);
if (status == SAI_STATUS_SUCCESS)
{
const std::vector<swss::FieldValueTuple> &values = kfvFieldsValues(kco);
if (values.size() != 2)
{
SWSS_LOG_ERROR("logic error, expected 2 values, received %zu", values.size());
return SAI_STATUS_FAILURE;
}
const std::string &capability_str = fvValue(values[0]);
const uint32_t num_capabilities = std::stoi(fvValue(values[1]));
enumValuesCapability->count = num_capabilities;
size_t position = 0;
for (uint32_t i = 0; i < num_capabilities; i++)
{
size_t old_position = position;
position = capability_str.find(",", old_position);
std::string capability = capability_str.substr(old_position, position - old_position);
enumValuesCapability->list[i] = std::stoi(capability);
// We have run out of values to add to our list
if (position == std::string::npos)
{
if (num_capabilities != i + 1)
{
SWSS_LOG_WARN("Query returned less attributes than expected: expected %d, received %d", num_capabilities, i+1);
}
break;
}
// Skip the commas
position++;
}
}
else if (status == SAI_STATUS_BUFFER_OVERFLOW)
{
const auto &values = kfvFieldsValues(kco);
if (values.size() != 1)
{
SWSS_LOG_ERROR("logic error, expected 1 value, received %zu", values.size());
return SAI_STATUS_FAILURE;
}
enumValuesCapability->count = std::stoi(fvValue(values[0]));
}
return status;
}
sai_object_type_t Sai::objectTypeQuery(
_In_ sai_object_id_t objectId)
{
MUTEX();
SWSS_LOG_ENTER();
if (!m_apiInitialized)
{
SWSS_LOG_ERROR("%s: api not initialized", __PRETTY_FUNCTION__);
return SAI_OBJECT_TYPE_NULL;
}
auto key = sai_serialize_object_id(objectId);
m_communicationChannel->set(key, {}, "object_type_query");
swss::KeyOpFieldsValuesTuple kco;
auto status = m_communicationChannel->wait("object_type_query_response", kco);
if (status == SAI_STATUS_SUCCESS)
{
auto& values = kfvFieldsValues(kco);
if (values.size() == 0)
{
SWSS_LOG_THROW("logic error, api returned 0 values!");
}
sai_object_type_t objectType;
sai_deserialize_object_type(fvValue(values[0]), objectType);
return objectType;
}
else
{
SWSS_LOG_ERROR("switchIdQuery failed: %s", sai_serialize_status(status).c_str());
}
return SAI_OBJECT_TYPE_NULL;
}
sai_object_id_t Sai::switchIdQuery(
_In_ sai_object_id_t objectId)
{
MUTEX();
SWSS_LOG_ENTER();
if (!m_apiInitialized)
{
SWSS_LOG_ERROR("%s: api not initialized", __PRETTY_FUNCTION__);
return SAI_NULL_OBJECT_ID;
}
auto key = sai_serialize_object_id(objectId);
m_communicationChannel->set(key, {}, "switch_id_query");
swss::KeyOpFieldsValuesTuple kco;
auto status = m_communicationChannel->wait("switch_id_query_response", kco);
if (status == SAI_STATUS_SUCCESS)
{
auto& values = kfvFieldsValues(kco);
if (values.size() == 0)
{
SWSS_LOG_THROW("logic error, api returned 0 values!");
}
sai_object_id_t switchId;
sai_deserialize_object_id(fvValue(values[0]), switchId);
return switchId;
}
else
{
SWSS_LOG_ERROR("switchIdQuery failed: %s", sai_serialize_status(status).c_str());
}
return SAI_NULL_OBJECT_ID;
}
sai_status_t Sai::logSet(
_In_ sai_api_t api,
_In_ sai_log_level_t log_level)
{
MUTEX();
SWSS_LOG_ENTER();
PROXY_CHECK_API_INITIALIZED();
auto key = sai_serialize_api(api) + ":" + sai_serialize_log_level(log_level);
m_communicationChannel->set(key, {}, "log_set");
swss::KeyOpFieldsValuesTuple kco;
return m_communicationChannel->wait("log_set_response", kco);
}
sai_status_t Sai::queryApiVersion(
_Out_ sai_api_version_t *version)
{
MUTEX();
SWSS_LOG_ENTER();
PROXY_CHECK_API_INITIALIZED();
SWSS_LOG_NOTICE("compiled proxy headers SAI API version: %d", SAI_API_VERSION);
if (version == NULL)
{
SWSS_LOG_ERROR("version parameter is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
m_communicationChannel->set("api", {}, "query_api_version");
swss::KeyOpFieldsValuesTuple kco;
auto status = m_communicationChannel->wait("query_api_version_response", kco);
if (status == SAI_STATUS_SUCCESS)
{
auto& values = kfvFieldsValues(kco);
if (values.size() == 0)
{
SWSS_LOG_THROW("logic error, api returned 0 values!");
}
SWSS_LOG_NOTICE("returned sai api version: %s", fvValue(values[0]).c_str());
*version = std::stoull(fvValue(values[0]));
}
return status;
}
// TODO use function from SAI metadata to populate those
void Sai::updateNotifications(
_In_ uint32_t attrCount,
_In_ const sai_attribute_t *attrList)
{
SWSS_LOG_ENTER();
/*
* This function should only be called on CREATE/SET
* api when object is SWITCH.
*/
sai_metadata_update_switch_notification_pointers(&m_sn, attrCount, attrList);
}
void Sai::handleNotification(
_In_ const std::string &name,
_In_ const std::string &serializedNotification,
_In_ const std::vector<swss::FieldValueTuple> &values)
{
MUTEX();
SWSS_LOG_ENTER();
if (!m_apiInitialized)
{
SWSS_LOG_ERROR("%s: api not initialized", __PRETTY_FUNCTION__);
return;
}
// TODO should be per switch, and we should know on which switch call notification
auto notification = sairedis::NotificationFactory::deserialize(name, serializedNotification);
if (notification)
{
SWSS_LOG_INFO("got notification: %s, executing callback!", serializedNotification.c_str());
// execute callback from notification thread
notification->executeCallback(m_sn);
}
}