lib/ServerSai.cpp (1,751 lines of code) (raw):
#include "ServerSai.h"
#include "SaiInternal.h"
#include "Sai.h"
#include "ServerConfig.h"
#include "sairediscommon.h"
#include "meta/sai_serialize.h"
#include "meta/SaiAttributeList.h"
#include "meta/ZeroMQSelectableChannel.h"
#include "swss/logger.h"
#include "swss/select.h"
#include "swss/tokenize.h"
#include <iterator>
#include <algorithm>
using namespace sairedis;
using namespace saimeta;
using namespace std::placeholders;
#define REDIS_CHECK_API_INITIALIZED() \
if (!m_apiInitialized) { \
SWSS_LOG_ERROR("%s: api not initialized", __PRETTY_FUNCTION__); \
return SAI_STATUS_FAILURE; }
ServerSai::ServerSai()
{
SWSS_LOG_ENTER();
m_apiInitialized = false;
m_runServerThread = false;
}
ServerSai::~ServerSai()
{
SWSS_LOG_ENTER();
if (m_apiInitialized)
{
apiUninitialize();
}
}
// INITIALIZE UNINITIALIZE
sai_status_t ServerSai::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));
m_sai = std::make_shared<Sai>(); // actual SAI to talk to syncd
auto status = m_sai->apiInitialize(flags, service_method_table);
SWSS_LOG_NOTICE("init client/server sai: %s", sai_serialize_status(status).c_str());
if (status == SAI_STATUS_SUCCESS)
{
auto serverConfig = service_method_table->profile_get_value(0, SAI_REDIS_KEY_SERVER_CONFIG);
auto cc = ServerConfig::loadFromFile(serverConfig);
m_selectableChannel = std::make_shared<ZeroMQSelectableChannel>(cc->m_zmqEndpoint);
SWSS_LOG_NOTICE("starting server thread");
m_runServerThread = true;
m_serverThread = std::make_shared<std::thread>(&ServerSai::serverThreadFunction, this);
m_apiInitialized = true;
}
return status;
}
sai_status_t ServerSai::apiUninitialize(void)
{
SWSS_LOG_ENTER();
REDIS_CHECK_API_INITIALIZED();
SWSS_LOG_NOTICE("begin");
m_apiInitialized = false;
if (m_serverThread)
{
SWSS_LOG_NOTICE("end server thread begin");
m_runServerThread = false;
m_serverThreadThreadShouldEndEvent.notify();
m_serverThread->join();
SWSS_LOG_NOTICE("end server thread end");
}
m_sai = nullptr;
SWSS_LOG_NOTICE("end");
return SAI_STATUS_SUCCESS;
}
// QUAD OID
sai_status_t ServerSai::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();
REDIS_CHECK_API_INITIALIZED();
return m_sai->create(
objectType,
objectId,
switchId,
attr_count,
attr_list);
}
sai_status_t ServerSai::remove(
_In_ sai_object_type_t objectType,
_In_ sai_object_id_t objectId)
{
MUTEX();
SWSS_LOG_ENTER();
REDIS_CHECK_API_INITIALIZED();
return m_sai->remove(objectType, objectId);
}
sai_status_t ServerSai::set(
_In_ sai_object_type_t objectType,
_In_ sai_object_id_t objectId,
_In_ const sai_attribute_t *attr)
{
MUTEX();
SWSS_LOG_ENTER();
REDIS_CHECK_API_INITIALIZED();
return m_sai->set(objectType, objectId, attr);
}
sai_status_t ServerSai::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();
REDIS_CHECK_API_INITIALIZED();
return m_sai->get(
objectType,
objectId,
attr_count,
attr_list);
}
// QUAD ENTRY
#define DECLARE_CREATE_ENTRY(OT,ot) \
sai_status_t ServerSai::create( \
_In_ const sai_ ## ot ## _t* entry, \
_In_ uint32_t attr_count, \
_In_ const sai_attribute_t *attr_list) \
{ \
MUTEX(); \
SWSS_LOG_ENTER(); \
REDIS_CHECK_API_INITIALIZED(); \
return m_sai->create(entry, attr_count, attr_list); \
}
SAIREDIS_DECLARE_EVERY_ENTRY(DECLARE_CREATE_ENTRY);
#define DECLARE_REMOVE_ENTRY(OT,ot) \
sai_status_t ServerSai::remove( \
_In_ const sai_ ## ot ## _t* entry) \
{ \
MUTEX(); \
SWSS_LOG_ENTER(); \
REDIS_CHECK_API_INITIALIZED(); \
return m_sai->remove(entry); \
}
SAIREDIS_DECLARE_EVERY_ENTRY(DECLARE_REMOVE_ENTRY);
#define DECLARE_SET_ENTRY(OT,ot) \
sai_status_t ServerSai::set( \
_In_ const sai_ ## ot ## _t* entry, \
_In_ const sai_attribute_t *attr) \
{ \
MUTEX(); \
SWSS_LOG_ENTER(); \
REDIS_CHECK_API_INITIALIZED(); \
return m_sai->set(entry, attr); \
}
SAIREDIS_DECLARE_EVERY_ENTRY(DECLARE_SET_ENTRY);
#define DECLARE_GET_ENTRY(OT,ot) \
sai_status_t ServerSai::get( \
_In_ const sai_ ## ot ## _t* entry, \
_In_ uint32_t attr_count, \
_Inout_ sai_attribute_t *attr_list) \
{ \
MUTEX(); \
SWSS_LOG_ENTER(); \
REDIS_CHECK_API_INITIALIZED(); \
return m_sai->get(entry, attr_count, attr_list); \
}
SAIREDIS_DECLARE_EVERY_ENTRY(DECLARE_GET_ENTRY);
// STATS
sai_status_t ServerSai::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();
REDIS_CHECK_API_INITIALIZED();
return m_sai->getStats(
object_type,
object_id,
number_of_counters,
counter_ids,
counters);
}
sai_status_t ServerSai::queryStatsCapability(
_In_ sai_object_id_t switchId,
_In_ sai_object_type_t objectType,
_Inout_ sai_stat_capability_list_t *stats_capability)
{
MUTEX();
SWSS_LOG_ENTER();
REDIS_CHECK_API_INITIALIZED();
return m_sai->queryStatsCapability(
switchId,
objectType,
stats_capability);
}
sai_status_t ServerSai::queryStatsStCapability(
_In_ sai_object_id_t switchId,
_In_ sai_object_type_t objectType,
_Inout_ sai_stat_st_capability_list_t *stats_capability)
{
MUTEX();
SWSS_LOG_ENTER();
REDIS_CHECK_API_INITIALIZED();
return m_sai->queryStatsStCapability(
switchId,
objectType,
stats_capability);
}
sai_status_t ServerSai::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();
REDIS_CHECK_API_INITIALIZED();
return m_sai->getStatsExt(
object_type,
object_id,
number_of_counters,
counter_ids,
mode,
counters);
}
sai_status_t ServerSai::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();
REDIS_CHECK_API_INITIALIZED();
return m_sai->clearStats(
object_type,
object_id,
number_of_counters,
counter_ids);
}
sai_status_t ServerSai::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)
{
MUTEX();
SWSS_LOG_ENTER();
REDIS_CHECK_API_INITIALIZED();
return m_sai->bulkGetStats(switchId,
object_type,
object_count,
object_key,
number_of_counters,
counter_ids,
mode,
object_statuses,
counters);
}
sai_status_t ServerSai::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)
{
MUTEX();
SWSS_LOG_ENTER();
REDIS_CHECK_API_INITIALIZED();
return m_sai->bulkClearStats(switchId,
object_type,
object_count,
object_key,
number_of_counters,
counter_ids,
mode,
object_statuses);
}
// BULK QUAD OID
sai_status_t ServerSai::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();
REDIS_CHECK_API_INITIALIZED();
return m_sai->bulkCreate(
object_type,
switch_id,
object_count,
attr_count,
attr_list,
mode,
object_id,
object_statuses);
}
sai_status_t ServerSai::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();
REDIS_CHECK_API_INITIALIZED();
return m_sai->bulkRemove(
object_type,
object_count,
object_id,
mode,
object_statuses);
}
sai_status_t ServerSai::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();
REDIS_CHECK_API_INITIALIZED();
return m_sai->bulkSet(
object_type,
object_count,
object_id,
attr_list,
mode,
object_statuses);
}
sai_status_t ServerSai::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();
REDIS_CHECK_API_INITIALIZED();
return m_sai->bulkGet(
object_type,
object_count,
object_id,
attr_count,
attr_list,
mode,
object_statuses);
}
// BULK QUAD ENTRY
#define DECLARE_BULK_CREATE_ENTRY(OT,ot) \
sai_status_t ServerSai::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(); \
REDIS_CHECK_API_INITIALIZED(); \
return m_sai->bulkCreate( \
object_count, \
entries, \
attr_count, \
attr_list, \
mode, \
object_statuses); \
}
SAIREDIS_DECLARE_EVERY_BULK_ENTRY(DECLARE_BULK_CREATE_ENTRY);
// BULK REMOVE
#define DECLARE_BULK_REMOVE_ENTRY(OT,ot) \
sai_status_t ServerSai::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(); \
REDIS_CHECK_API_INITIALIZED(); \
return m_sai->bulkRemove( \
object_count, \
entries, \
mode, \
object_statuses); \
}
SAIREDIS_DECLARE_EVERY_BULK_ENTRY(DECLARE_BULK_REMOVE_ENTRY);
// BULK SET
#define DECLARE_BULK_SET_ENTRY(OT,ot) \
sai_status_t ServerSai::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(); \
REDIS_CHECK_API_INITIALIZED(); \
return m_sai->bulkSet( \
object_count, \
entries, \
attr_list, \
mode, \
object_statuses); \
}
SAIREDIS_DECLARE_EVERY_BULK_ENTRY(DECLARE_BULK_SET_ENTRY);
// BULK GET
#define DECLARE_BULK_GET_ENTRY(OT,ot) \
sai_status_t ServerSai::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(); \
REDIS_CHECK_API_INITIALIZED(); \
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 ServerSai::flushFdbEntries(
_In_ sai_object_id_t switch_id,
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list)
{
MUTEX();
SWSS_LOG_ENTER();
REDIS_CHECK_API_INITIALIZED();
return m_sai->flushFdbEntries(switch_id, attr_count, attr_list);
}
// SAI API
sai_status_t ServerSai::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();
REDIS_CHECK_API_INITIALIZED();
return m_sai->objectTypeGetAvailability(
switchId,
objectType,
attrCount,
attrList,
count);
}
sai_status_t ServerSai::queryAttributeCapability(
_In_ sai_object_id_t switch_id,
_In_ sai_object_type_t object_type,
_In_ sai_attr_id_t attr_id,
_Out_ sai_attr_capability_t *capability)
{
MUTEX();
SWSS_LOG_ENTER();
REDIS_CHECK_API_INITIALIZED();
return m_sai->queryAttributeCapability(
switch_id,
object_type,
attr_id,
capability);
}
sai_status_t ServerSai::queryAttributeEnumValuesCapability(
_In_ sai_object_id_t switch_id,
_In_ sai_object_type_t object_type,
_In_ sai_attr_id_t attr_id,
_Inout_ sai_s32_list_t *enum_values_capability)
{
MUTEX();
SWSS_LOG_ENTER();
REDIS_CHECK_API_INITIALIZED();
return m_sai->queryAttributeEnumValuesCapability(
switch_id,
object_type,
attr_id,
enum_values_capability);
}
sai_object_type_t ServerSai::objectTypeQuery(
_In_ sai_object_id_t objectId)
{
SWSS_LOG_ENTER();
if (!m_apiInitialized)
{
SWSS_LOG_ERROR("%s: SAI API not initialized", __PRETTY_FUNCTION__);
return SAI_OBJECT_TYPE_NULL;
}
return m_sai->objectTypeQuery(objectId);
}
sai_object_id_t ServerSai::switchIdQuery(
_In_ sai_object_id_t objectId)
{
SWSS_LOG_ENTER();
if (!m_apiInitialized)
{
SWSS_LOG_ERROR("%s: SAI API not initialized", __PRETTY_FUNCTION__);
return SAI_NULL_OBJECT_ID;
}
return m_sai->switchIdQuery(objectId);
}
sai_status_t ServerSai::logSet(
_In_ sai_api_t api,
_In_ sai_log_level_t log_level)
{
MUTEX();
SWSS_LOG_ENTER();
REDIS_CHECK_API_INITIALIZED();
return m_sai->logSet(api, log_level);
}
sai_status_t ServerSai::queryApiVersion(
_Out_ sai_api_version_t *version)
{
MUTEX();
SWSS_LOG_ENTER();
REDIS_CHECK_API_INITIALIZED();
return m_sai->queryApiVersion(version);
}
void ServerSai::serverThreadFunction()
{
SWSS_LOG_ENTER();
SWSS_LOG_NOTICE("begin");
swss::Select s;
s.addSelectable(m_selectableChannel.get());
s.addSelectable(&m_serverThreadThreadShouldEndEvent);
while (m_runServerThread)
{
swss::Selectable *sel;
int result = s.select(&sel);
if (sel == &m_serverThreadThreadShouldEndEvent)
{
// user requested end server thread
break;
}
if (result == swss::Select::OBJECT)
{
processEvent(*m_selectableChannel.get());
}
else
{
SWSS_LOG_ERROR("select failed: %s", swss::Select::resultToString(result).c_str());
}
}
SWSS_LOG_NOTICE("end");
}
void ServerSai::processEvent(
_In_ SelectableChannel& consumer)
{
MUTEX();
SWSS_LOG_ENTER();
if (!m_apiInitialized)
{
SWSS_LOG_ERROR("%s: SAI API not initialized", __PRETTY_FUNCTION__);
return;
}
do
{
swss::KeyOpFieldsValuesTuple kco;
consumer.pop(kco, false);
processSingleEvent(kco);
}
while (!consumer.empty());
}
sai_status_t ServerSai::processSingleEvent(
_In_ const swss::KeyOpFieldsValuesTuple &kco)
{
SWSS_LOG_ENTER();
auto& key = kfvKey(kco);
auto& op = kfvOp(kco);
SWSS_LOG_INFO("key: %s op: %s", key.c_str(), op.c_str());
if (key.length() == 0)
{
SWSS_LOG_DEBUG("no elements in m_buffer");
return SAI_STATUS_SUCCESS;
}
if (op == REDIS_ASIC_STATE_COMMAND_CREATE)
return processQuadEvent(SAI_COMMON_API_CREATE, kco);
if (op == REDIS_ASIC_STATE_COMMAND_REMOVE)
return processQuadEvent(SAI_COMMON_API_REMOVE, kco);
if (op == REDIS_ASIC_STATE_COMMAND_SET)
return processQuadEvent(SAI_COMMON_API_SET, kco);
if (op == REDIS_ASIC_STATE_COMMAND_GET)
return processQuadEvent(SAI_COMMON_API_GET, kco);
if (op == REDIS_ASIC_STATE_COMMAND_BULK_CREATE)
return processBulkQuadEvent(SAI_COMMON_API_BULK_CREATE, kco);
if (op == REDIS_ASIC_STATE_COMMAND_BULK_REMOVE)
return processBulkQuadEvent(SAI_COMMON_API_BULK_REMOVE, kco);
if (op == REDIS_ASIC_STATE_COMMAND_BULK_SET)
return processBulkQuadEvent(SAI_COMMON_API_BULK_SET, kco);
if (op == REDIS_ASIC_STATE_COMMAND_GET_STATS)
return processGetStatsEvent(kco);
if (op == REDIS_ASIC_STATE_COMMAND_CLEAR_STATS)
return processClearStatsEvent(kco);
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_STATS_CAPABILITY_QUERY)
return processStatsCapabilityQuery(kco);
SWSS_LOG_THROW("event op '%s' is not implemented, FIXME", op.c_str());
}
sai_status_t ServerSai::processQuadEvent(
_In_ sai_common_api_t api,
_In_ const swss::KeyOpFieldsValuesTuple &kco)
{
SWSS_LOG_ENTER();
const std::string& key = kfvKey(kco);
const std::string& op = kfvOp(kco);
const std::string& strObjectId = key.substr(key.find(":") + 1);
sai_object_meta_key_t metaKey;
sai_deserialize_object_meta_key(key, metaKey);
if (!sai_metadata_is_object_type_valid(metaKey.objecttype))
{
SWSS_LOG_THROW("invalid object type %s", key.c_str());
}
SWSS_LOG_NOTICE("got server request: %s : %s", key.c_str(), op.c_str());
auto& values = kfvFieldsValues(kco);
for (auto& v: values)
{
SWSS_LOG_NOTICE(" - attr: %s: %s", fvField(v).c_str(), fvValue(v).c_str());
}
SaiAttributeList list(metaKey.objecttype, values, false);
sai_attribute_t *attr_list = list.get_attr_list();
uint32_t attr_count = list.get_attr_count();
/*
* NOTE: Need to translate client notification pointers to sairedis
* pointers since they reside in different memory space.
*/
if (metaKey.objecttype == SAI_OBJECT_TYPE_SWITCH && (api == SAI_COMMON_API_CREATE || api == SAI_COMMON_API_SET))
{
/*
* Since we will be operating on existing switch, it may happen that
* client will set notification pointer, which is not actually set in
* sairedis server. Then we would need to take extra steps in server
* to forward those notifications. We could also drop notification
* request on clients side, since it would be possible only to set only
* existing pointers.
*
* TODO: must be done per switch, and switch may not exists yet
*/
// TODO m_handler->updateNotificationsPointers(attr_count, attr_list);
SWSS_LOG_ERROR("TODO, update notification pointers, FIXME!");
}
auto info = sai_metadata_get_object_type_info(metaKey.objecttype);
sai_status_t status;
// NOTE: for create api (even switch) passed oid will be SAI_NULL_OBJECT_ID
sai_object_id_t oid = SAI_NULL_OBJECT_ID;
if (info->isnonobjectid)
{
status = processEntry(metaKey, api, attr_count, attr_list);
}
else
{
sai_deserialize_object_id(strObjectId, oid);
// In case of create oid object, client don't know what will be created
// object id before it receive it, so instead of that it will transfer
// switch id in that place since switch id is needed to create other
// object in the first place. If create method is for switch, this
// field will be SAI_NULL_OBJECT_ID.
sai_object_id_t switchOid = oid;
status = processOid(metaKey.objecttype, oid, switchOid, api, attr_count, attr_list);
}
if (api == SAI_COMMON_API_GET)
{
sendGetResponse(metaKey.objecttype, strObjectId, status, attr_count, attr_list);
}
else if (status != SAI_STATUS_SUCCESS)
{
sendApiResponse(api, status, oid);
SWSS_LOG_ERROR("api failed: %s (%s): %s",
key.c_str(),
op.c_str(),
sai_serialize_status(status).c_str());
for (const auto &v: values)
{
SWSS_LOG_ERROR("attr: %s: %s", fvField(v).c_str(), fvValue(v).c_str());
}
}
else // non GET api, status is SUCCESS
{
sendApiResponse(api, status, oid);
}
return status;
}
void ServerSai::sendApiResponse(
_In_ sai_common_api_t api,
_In_ sai_status_t status,
_In_ sai_object_id_t oid)
{
SWSS_LOG_ENTER();
switch (api)
{
case SAI_COMMON_API_CREATE:
case SAI_COMMON_API_REMOVE:
case SAI_COMMON_API_SET:
break;
default:
SWSS_LOG_THROW("api %s not supported by this function",
sai_serialize_common_api(api).c_str());
}
std::vector<swss::FieldValueTuple> entry;
if (api == SAI_COMMON_API_CREATE)
{
// in case of create api, we need to return OID value that was created
// to the client
entry.emplace_back("oid", sai_serialize_object_id(oid));
}
std::string strStatus = sai_serialize_status(status);
SWSS_LOG_INFO("sending response for %s api with status: %s",
sai_serialize_common_api(api).c_str(),
strStatus.c_str());
m_selectableChannel->set(strStatus, entry, REDIS_ASIC_STATE_COMMAND_GETRESPONSE);
}
void ServerSai::sendGetResponse(
_In_ sai_object_type_t objectType,
_In_ const std::string& strObjectId,
_In_ sai_status_t status,
_In_ uint32_t attr_count,
_In_ sai_attribute_t *attr_list)
{
SWSS_LOG_ENTER();
std::vector<swss::FieldValueTuple> entry;
if (status == SAI_STATUS_SUCCESS)
{
entry = SaiAttributeList::serialize_attr_list(
objectType,
attr_count,
attr_list,
false);
}
else if (status == SAI_STATUS_BUFFER_OVERFLOW)
{
/*
* In this case we got correct values for list, but list was too small
* so serialize only count without list itself, sairedis will need to
* take this into account when deserialize.
*
* If there was a list somewhere, count will be changed to actual value
* different attributes can have different lists, many of them may
* serialize only count, and will need to support that on the receiver.
*/
entry = SaiAttributeList::serialize_attr_list(
objectType,
attr_count,
attr_list,
true);
}
else
{
/*
* Some other error, don't send attributes at all.
*/
}
for (const auto &e: entry)
{
SWSS_LOG_DEBUG("attr: %s: %s", fvField(e).c_str(), fvValue(e).c_str());
}
std::string strStatus = sai_serialize_status(status);
SWSS_LOG_INFO("sending response for GET api with status: %s", strStatus.c_str());
/*
* Since we have only one get at a time, we don't have to serialize object
* type and object id, only get status is required to be returned. Get
* response will not put any data to table, only queue is used.
*/
m_selectableChannel->set(strStatus, entry, REDIS_ASIC_STATE_COMMAND_GETRESPONSE);
SWSS_LOG_INFO("response for GET api was send");
}
sai_status_t ServerSai::processEntry(
_In_ sai_object_meta_key_t metaKey,
_In_ sai_common_api_t api,
_In_ uint32_t attr_count,
_In_ sai_attribute_t *attr_list)
{
SWSS_LOG_ENTER();
switch (api)
{
case SAI_COMMON_API_CREATE:
return m_sai->create(metaKey, SAI_NULL_OBJECT_ID, attr_count, attr_list);
case SAI_COMMON_API_REMOVE:
return m_sai->remove(metaKey);
case SAI_COMMON_API_SET:
return m_sai->set(metaKey, attr_list);
case SAI_COMMON_API_GET:
return m_sai->get(metaKey, attr_count, attr_list);
default:
SWSS_LOG_THROW("api %s not supported", sai_serialize_common_api(api).c_str());
}
}
sai_status_t ServerSai::processOid(
_In_ sai_object_type_t objectType,
_Inout_ sai_object_id_t& oid,
_In_ sai_object_id_t switchOid,
_In_ sai_common_api_t api,
_In_ uint32_t attr_count,
_In_ sai_attribute_t *attr_list)
{
SWSS_LOG_ENTER();
SWSS_LOG_DEBUG("calling %s for %s",
sai_serialize_common_api(api).c_str(),
sai_serialize_object_type(objectType).c_str());
auto info = sai_metadata_get_object_type_info(objectType);
if (info->isnonobjectid)
{
SWSS_LOG_THROW("passing non object id %s as generic object", info->objecttypename);
}
switch (api)
{
case SAI_COMMON_API_CREATE:
return m_sai->create(objectType, &oid, switchOid, attr_count, attr_list);
case SAI_COMMON_API_REMOVE:
return m_sai->remove(objectType, oid);
case SAI_COMMON_API_SET:
return m_sai->set(objectType, oid, attr_list);
case SAI_COMMON_API_GET:
return m_sai->get(objectType, oid, attr_count, attr_list);
default:
SWSS_LOG_THROW("common api (%s) is not implemented", sai_serialize_common_api(api).c_str());
}
}
sai_status_t ServerSai::processBulkQuadEvent(
_In_ sai_common_api_t api,
_In_ const swss::KeyOpFieldsValuesTuple &kco)
{
SWSS_LOG_ENTER();
const std::string& key = kfvKey(kco); // objectType:count
std::string strObjectType = key.substr(0, key.find(":"));
sai_object_type_t objectType;
sai_deserialize_object_type(strObjectType, objectType);
const std::vector<swss::FieldValueTuple> &values = kfvFieldsValues(kco);
std::vector<std::vector<swss::FieldValueTuple>> strAttributes;
// field = objectId
// value = attrid=attrvalue|...
std::vector<std::string> objectIds;
std::vector<std::shared_ptr<SaiAttributeList>> attributes;
for (const auto &fvt: values)
{
std::string strObjectId = fvField(fvt);
std::string joined = fvValue(fvt);
// decode values
auto v = swss::tokenize(joined, '|');
objectIds.push_back(strObjectId);
std::vector<swss::FieldValueTuple> entries; // attributes per object id
for (size_t i = 0; i < v.size(); ++i)
{
const std::string item = v.at(i);
auto start = item.find_first_of("=");
auto field = item.substr(0, start);
auto value = item.substr(start + 1);
entries.emplace_back(field, value);
}
strAttributes.push_back(entries);
// since now we converted this to proper list, we can extract attributes
auto list = std::make_shared<SaiAttributeList>(objectType, entries, false);
attributes.push_back(list);
}
SWSS_LOG_INFO("bulk %s executing with %zu items",
strObjectType.c_str(),
objectIds.size());
auto info = sai_metadata_get_object_type_info(objectType);
if (info->isobjectid)
{
return processBulkOid(objectType, objectIds, api, attributes, strAttributes);
}
else
{
return processBulkEntry(objectType, objectIds, api, attributes, strAttributes);
}
}
sai_status_t ServerSai::processBulkOid(
_In_ sai_object_type_t objectType,
_In_ const std::vector<std::string>& strObjectIds,
_In_ sai_common_api_t api,
_In_ const std::vector<std::shared_ptr<SaiAttributeList>>& attributes,
_In_ const std::vector<std::vector<swss::FieldValueTuple>>& strAttributes)
{
SWSS_LOG_ENTER();
auto info = sai_metadata_get_object_type_info(objectType);
if (info->isnonobjectid)
{
SWSS_LOG_THROW("passing non object id to bulk oid object operation");
}
std::vector<sai_status_t> statuses(strObjectIds.size(), SAI_STATUS_FAILURE);
sai_status_t status = SAI_STATUS_FAILURE;
sai_bulk_op_error_mode_t mode = SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR;
std::vector<sai_object_id_t> objectIds(strObjectIds.size());
for (size_t idx = 0; idx < objectIds.size(); idx++)
{
sai_deserialize_object_id(strObjectIds[idx], objectIds[idx]);
}
size_t object_count = objectIds.size();
switch (api)
{
case SAI_COMMON_API_BULK_CREATE:
{
std::vector<uint32_t> attr_counts(object_count);
std::vector<const sai_attribute_t*> attr_lists(object_count);
for (size_t idx = 0; idx < object_count; idx++)
{
attr_counts[idx] = attributes[idx]->get_attr_count();
attr_lists[idx] = attributes[idx]->get_attr_list();
}
// in case of client/server, all passed oids are switch OID since
// client don't know what oid will be assigned to created object
sai_object_id_t switchId = objectIds.at(0);
status = m_sai->bulkCreate(
objectType,
switchId,
(uint32_t)object_count,
attr_counts.data(),
attr_lists.data(),
mode,
objectIds.data(),
statuses.data());
}
break;
case SAI_COMMON_API_BULK_REMOVE:
status = m_sai->bulkRemove(
objectType,
(uint32_t)objectIds.size(),
objectIds.data(),
mode,
statuses.data());
break;
default:
status = SAI_STATUS_NOT_SUPPORTED;
SWSS_LOG_ERROR("api %s is not supported in bulk mode", sai_serialize_common_api(api).c_str());
break;
}
sendBulkApiResponse(api, status, (uint32_t)objectIds.size(), objectIds.data(), statuses.data());
return status;
}
sai_status_t ServerSai::processBulkEntry(
_In_ sai_object_type_t objectType,
_In_ const std::vector<std::string>& objectIds,
_In_ sai_common_api_t api,
_In_ const std::vector<std::shared_ptr<SaiAttributeList>>& attributes,
_In_ const std::vector<std::vector<swss::FieldValueTuple>>& strAttributes)
{
SWSS_LOG_ENTER();
auto info = sai_metadata_get_object_type_info(objectType);
if (info->isobjectid)
{
SWSS_LOG_THROW("passing oid object to bulk non object id operation");
}
std::vector<sai_status_t> statuses(objectIds.size());
sai_status_t status = SAI_STATUS_SUCCESS;
switch (api)
{
case SAI_COMMON_API_BULK_CREATE:
status = processBulkCreateEntry(objectType, objectIds, attributes, statuses);
break;
case SAI_COMMON_API_BULK_REMOVE:
status = processBulkRemoveEntry(objectType, objectIds, statuses);
break;
case SAI_COMMON_API_BULK_SET:
status = processBulkSetEntry(objectType, objectIds, attributes, statuses);
break;
default:
SWSS_LOG_ERROR("api %s is not supported in bulk", sai_serialize_common_api(api).c_str());
status = SAI_STATUS_NOT_SUPPORTED;
}
std::vector<sai_object_id_t> oids(objectIds.size());
sendBulkApiResponse(api, status, (uint32_t)objectIds.size(), oids.data(), statuses.data());
return status;
}
sai_status_t ServerSai::processBulkCreateEntry(
_In_ sai_object_type_t objectType,
_In_ const std::vector<std::string>& objectIds,
_In_ const std::vector<std::shared_ptr<SaiAttributeList>>& attributes,
_Out_ std::vector<sai_status_t>& statuses)
{
SWSS_LOG_ENTER();
sai_status_t status = SAI_STATUS_SUCCESS;
uint32_t object_count = (uint32_t) objectIds.size();
sai_bulk_op_error_mode_t mode = SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR;
std::vector<uint32_t> attr_counts(object_count);
std::vector<const sai_attribute_t*> attr_lists(object_count);
for (uint32_t idx = 0; idx < object_count; idx++)
{
attr_counts[idx] = attributes[idx]->get_attr_count();
attr_lists[idx] = attributes[idx]->get_attr_list();
}
switch ((int)objectType)
{
case SAI_OBJECT_TYPE_ROUTE_ENTRY:
{
std::vector<sai_route_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_route_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkCreate(
object_count,
entries.data(),
attr_counts.data(),
attr_lists.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_FDB_ENTRY:
{
std::vector<sai_fdb_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_fdb_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkCreate(
object_count,
entries.data(),
attr_counts.data(),
attr_lists.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_NAT_ENTRY:
{
std::vector<sai_nat_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_nat_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkCreate(
object_count,
entries.data(),
attr_counts.data(),
attr_lists.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_INSEG_ENTRY:
{
std::vector<sai_inseg_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_inseg_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkCreate(
object_count,
entries.data(),
attr_counts.data(),
attr_lists.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_MY_SID_ENTRY:
{
std::vector<sai_my_sid_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_my_sid_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkCreate(
object_count,
entries.data(),
attr_counts.data(),
attr_lists.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_DIRECTION_LOOKUP_ENTRY:
{
std::vector<sai_direction_lookup_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_direction_lookup_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkCreate(
object_count,
entries.data(),
attr_counts.data(),
attr_lists.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_ENI_ETHER_ADDRESS_MAP_ENTRY:
{
std::vector<sai_eni_ether_address_map_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_eni_ether_address_map_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkCreate(
object_count,
entries.data(),
attr_counts.data(),
attr_lists.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_VIP_ENTRY:
{
std::vector<sai_vip_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_vip_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkCreate(
object_count,
entries.data(),
attr_counts.data(),
attr_lists.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_INBOUND_ROUTING_ENTRY:
{
std::vector<sai_inbound_routing_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_inbound_routing_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkCreate(
object_count,
entries.data(),
attr_counts.data(),
attr_lists.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_PA_VALIDATION_ENTRY:
{
std::vector<sai_pa_validation_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_pa_validation_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkCreate(
object_count,
entries.data(),
attr_counts.data(),
attr_lists.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_OUTBOUND_ROUTING_ENTRY:
{
std::vector<sai_outbound_routing_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_outbound_routing_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkCreate(
object_count,
entries.data(),
attr_counts.data(),
attr_lists.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_OUTBOUND_CA_TO_PA_ENTRY:
{
std::vector<sai_outbound_ca_to_pa_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_outbound_ca_to_pa_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkCreate(
object_count,
entries.data(),
attr_counts.data(),
attr_lists.data(),
mode,
statuses.data());
}
break;
default:
return SAI_STATUS_NOT_SUPPORTED;
}
return status;
}
sai_status_t ServerSai::processBulkRemoveEntry(
_In_ sai_object_type_t objectType,
_In_ const std::vector<std::string>& objectIds,
_Out_ std::vector<sai_status_t>& statuses)
{
SWSS_LOG_ENTER();
sai_status_t status = SAI_STATUS_SUCCESS;
uint32_t object_count = (uint32_t) objectIds.size();
sai_bulk_op_error_mode_t mode = SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR;
switch ((int)objectType)
{
case SAI_OBJECT_TYPE_ROUTE_ENTRY:
{
std::vector<sai_route_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_route_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkRemove(
object_count,
entries.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_FDB_ENTRY:
{
std::vector<sai_fdb_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_fdb_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkRemove(
object_count,
entries.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_NAT_ENTRY:
{
std::vector<sai_nat_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_nat_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkRemove(
object_count,
entries.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_INSEG_ENTRY:
{
std::vector<sai_inseg_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_inseg_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkRemove(
object_count,
entries.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_MY_SID_ENTRY:
{
std::vector<sai_my_sid_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_my_sid_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkRemove(
object_count,
entries.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_DIRECTION_LOOKUP_ENTRY:
{
std::vector<sai_direction_lookup_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_direction_lookup_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkRemove(
object_count,
entries.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_ENI_ETHER_ADDRESS_MAP_ENTRY:
{
std::vector<sai_eni_ether_address_map_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_eni_ether_address_map_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkRemove(
object_count,
entries.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_VIP_ENTRY:
{
std::vector<sai_vip_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_vip_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkRemove(
object_count,
entries.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_INBOUND_ROUTING_ENTRY:
{
std::vector<sai_inbound_routing_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_inbound_routing_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkRemove(
object_count,
entries.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_PA_VALIDATION_ENTRY:
{
std::vector<sai_pa_validation_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_pa_validation_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkRemove(
object_count,
entries.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_OUTBOUND_ROUTING_ENTRY:
{
std::vector<sai_outbound_routing_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_outbound_routing_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkRemove(
object_count,
entries.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_OUTBOUND_CA_TO_PA_ENTRY:
{
std::vector<sai_outbound_ca_to_pa_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_outbound_ca_to_pa_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkRemove(
object_count,
entries.data(),
mode,
statuses.data());
}
break;
default:
return SAI_STATUS_NOT_SUPPORTED;
}
return status;
}
sai_status_t ServerSai::processBulkSetEntry(
_In_ sai_object_type_t objectType,
_In_ const std::vector<std::string>& objectIds,
_In_ const std::vector<std::shared_ptr<SaiAttributeList>>& attributes,
_Out_ std::vector<sai_status_t>& statuses)
{
SWSS_LOG_ENTER();
sai_status_t status = SAI_STATUS_SUCCESS;
std::vector<sai_attribute_t> attr_lists;
uint32_t object_count = (uint32_t) objectIds.size();
sai_bulk_op_error_mode_t mode = SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR;
for (uint32_t it = 0; it < object_count; it++)
{
attr_lists.push_back(attributes[it]->get_attr_list()[0]);
}
switch (objectType)
{
case SAI_OBJECT_TYPE_ROUTE_ENTRY:
{
std::vector<sai_route_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_route_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkSet(
object_count,
entries.data(),
attr_lists.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_FDB_ENTRY:
{
std::vector<sai_fdb_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_fdb_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkSet(
object_count,
entries.data(),
attr_lists.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_NAT_ENTRY:
{
std::vector<sai_nat_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_nat_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkSet(
object_count,
entries.data(),
attr_lists.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_INSEG_ENTRY:
{
std::vector<sai_inseg_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_inseg_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkSet(
object_count,
entries.data(),
attr_lists.data(),
mode,
statuses.data());
}
break;
case SAI_OBJECT_TYPE_MY_SID_ENTRY:
{
std::vector<sai_my_sid_entry_t> entries(object_count);
for (uint32_t it = 0; it < object_count; it++)
{
sai_deserialize_my_sid_entry(objectIds[it], entries[it]);
}
status = m_sai->bulkSet(
object_count,
entries.data(),
attr_lists.data(),
mode,
statuses.data());
}
break;
default:
return SAI_STATUS_NOT_SUPPORTED;
}
return status;
}
void ServerSai::sendBulkApiResponse(
_In_ sai_common_api_t api,
_In_ sai_status_t status,
_In_ uint32_t object_count,
_In_ const sai_object_id_t* object_ids,
_In_ const sai_status_t* statuses)
{
SWSS_LOG_ENTER();
switch (api)
{
case SAI_COMMON_API_BULK_CREATE:
case SAI_COMMON_API_BULK_REMOVE:
case SAI_COMMON_API_BULK_SET:
break;
default:
SWSS_LOG_THROW("api %s not supported by this function",
sai_serialize_common_api(api).c_str());
}
std::vector<swss::FieldValueTuple> entry;
for (uint32_t idx = 0; idx < object_count; idx++)
{
entry.emplace_back(sai_serialize_status(statuses[idx]), "");
}
if (api == SAI_COMMON_API_BULK_CREATE)
{
// in case of bulk create api, we need to return oids values that was
// created to the client
for (uint32_t idx = 0; idx < object_count; idx++)
{
entry.emplace_back("oid", sai_serialize_object_id(object_ids[idx]));
}
}
std::string strStatus = sai_serialize_status(status);
SWSS_LOG_INFO("sending response for %s api with status: %s",
sai_serialize_common_api(api).c_str(),
strStatus.c_str());
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<swss::FieldValueTuple> 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<int32_t> 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->queryAttributeEnumValuesCapability(switchOid, objectType, attrId, &enumCapList);
std::vector<swss::FieldValueTuple> entry;
if (status == SAI_STATUS_SUCCESS)
{
std::vector<std::string> 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<std::string>(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<swss::FieldValueTuple> 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<swss::FieldValueTuple> 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;
}
sai_status_t ServerSai::processStatsCapabilityQuery(
_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_STATS_CAPABILITY_RESPONSE);
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_type_t objectType;
sai_deserialize_object_type(fvValue(values[0]), objectType);
uint32_t list_size = std::stoi(fvValue(values[1]));
std::vector<sai_stat_capability_t> stat_capability_list(list_size);
sai_stat_capability_list_t statCapList;
statCapList.count = list_size;
statCapList.list = stat_capability_list.data();
sai_status_t status = m_sai->queryStatsCapability(switchOid, objectType, &statCapList);
std::vector<swss::FieldValueTuple> entry;
if (status == SAI_STATUS_SUCCESS)
{
std::vector<std::string> vec_stat_enum;
std::vector<std::string> vec_stat_modes;
for (uint32_t it = 0; it < statCapList.count; it++)
{
vec_stat_enum.push_back(std::to_string(statCapList.list[it].stat_enum));
vec_stat_modes.push_back(std::to_string(statCapList.list[it].stat_modes));
}
std::ostringstream join_stat_enum;
std::copy(vec_stat_enum.begin(), vec_stat_enum.end(), std::ostream_iterator<std::string>(join_stat_enum, ","));
auto strCapEnum = join_stat_enum.str();
std::ostringstream join_stat_modes;
std::copy(vec_stat_modes.begin(), vec_stat_modes.end(), std::ostream_iterator<std::string>(join_stat_modes, ","));
auto strCapModes = join_stat_modes.str();
entry =
{
swss::FieldValueTuple("STAT_ENUM", strCapEnum),
swss::FieldValueTuple("STAT_MODES", strCapModes),
swss::FieldValueTuple("STAT_COUNT", std::to_string(statCapList.count))
};
SWSS_LOG_DEBUG("Sending response: stat_enums = '%s', stat_modes = '%s', count = %d",
strCapEnum.c_str(), strCapModes.c_str(), statCapList.count);
}
else if (status == SAI_STATUS_BUFFER_OVERFLOW)
{
entry =
{
swss::FieldValueTuple("STAT_COUNT", std::to_string(statCapList.count))
};
SWSS_LOG_DEBUG("Sending response: count = %u", statCapList.count);
}
m_selectableChannel->set(sai_serialize_status(status), entry, REDIS_ASIC_STATE_COMMAND_STATS_CAPABILITY_RESPONSE);
return status;
}
sai_status_t ServerSai::processFdbFlush(
_In_ const swss::KeyOpFieldsValuesTuple &kco)
{
SWSS_LOG_ENTER();
auto& key = kfvKey(kco);
auto strSwitchOid = key.substr(key.find(":") + 1);
sai_object_id_t switchOid;
sai_deserialize_object_id(strSwitchOid, switchOid);
auto& values = kfvFieldsValues(kco);
for (const auto &v: values)
{
SWSS_LOG_DEBUG("attr: %s: %s", fvField(v).c_str(), fvValue(v).c_str());
}
SaiAttributeList list(SAI_OBJECT_TYPE_FDB_FLUSH, values, false);
sai_attribute_t *attr_list = list.get_attr_list();
uint32_t attr_count = list.get_attr_count();
sai_status_t status = m_sai->flushFdbEntries(switchOid, attr_count, attr_list);
m_selectableChannel->set(sai_serialize_status(status), {} , REDIS_ASIC_STATE_COMMAND_FLUSHRESPONSE);
return status;
}
sai_status_t ServerSai::processClearStatsEvent(
_In_ const swss::KeyOpFieldsValuesTuple &kco)
{
SWSS_LOG_ENTER();
const std::string &key = kfvKey(kco);
sai_object_meta_key_t metaKey;
sai_deserialize_object_meta_key(key, metaKey);
auto info = sai_metadata_get_object_type_info(metaKey.objecttype);
if (info->isnonobjectid)
{
SWSS_LOG_THROW("non object id not supported on clear stats: %s, FIXME", key.c_str());
}
std::vector<sai_stat_id_t> counter_ids;
for (auto&v: kfvFieldsValues(kco))
{
int32_t val;
sai_deserialize_enum(fvField(v), info->statenum, val);
counter_ids.push_back(val);
}
auto status = m_sai->clearStats(
metaKey.objecttype,
metaKey.objectkey.key.object_id,
(uint32_t)counter_ids.size(),
counter_ids.data());
m_selectableChannel->set(sai_serialize_status(status), {}, REDIS_ASIC_STATE_COMMAND_GETRESPONSE);
return status;
}
sai_status_t ServerSai::processGetStatsEvent(
_In_ const swss::KeyOpFieldsValuesTuple &kco)
{
SWSS_LOG_ENTER();
const std::string &key = kfvKey(kco);
sai_object_meta_key_t metaKey;
sai_deserialize_object_meta_key(key, metaKey);
// TODO get stats on created object in init view mode could fail
auto info = sai_metadata_get_object_type_info(metaKey.objecttype);
if (info->isnonobjectid)
{
SWSS_LOG_THROW("non object id not supported on clear stats: %s, FIXME", key.c_str());
}
std::vector<sai_stat_id_t> counter_ids;
for (auto&v: kfvFieldsValues(kco))
{
int32_t val;
sai_deserialize_enum(fvField(v), info->statenum, val);
counter_ids.push_back(val);
}
std::vector<uint64_t> result(counter_ids.size());
auto status = m_sai->getStats(
metaKey.objecttype,
metaKey.objectkey.key.object_id,
(uint32_t)counter_ids.size(),
counter_ids.data(),
result.data());
std::vector<swss::FieldValueTuple> entry;
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_ERROR("Failed to get stats");
}
else
{
const auto& values = kfvFieldsValues(kco);
for (size_t i = 0; i < values.size(); i++)
{
entry.emplace_back(fvField(values[i]), std::to_string(result[i]));
}
}
m_selectableChannel->set(sai_serialize_status(status), entry, REDIS_ASIC_STATE_COMMAND_GETRESPONSE);
return status;
}