proxylib/Proxy.cpp (832 lines of code) (raw):
#include "Proxy.h"
#include "swss/logger.h"
#include "swss/select.h"
#include "swss/table.h"
#include "meta/SaiAttributeList.h"
#include "meta/sai_serialize.h"
#include "meta/ZeroMQSelectableChannel.h"
#include "syncd/ZeroMQNotificationProducer.h"
#include "syncd/Workaround.h"
#include <inttypes.h>
#include <iterator>
#include <algorithm>
using namespace saiproxy;
using namespace std::placeholders;
// TODO handle diagnostic shell
Proxy::Proxy(
_In_ std::shared_ptr<sairedis::SaiInterface> vendorSai):
Proxy(vendorSai, std::make_shared<Options>())
{
SWSS_LOG_ENTER();
SWSS_LOG_NOTICE("using default options");
}
Proxy::Proxy(
_In_ std::shared_ptr<sairedis::SaiInterface> vendorSai,
_In_ std::shared_ptr<Options> options):
m_vendorSai(vendorSai),
m_options(options),
m_apiInitialized(false),
m_notificationsSentCount(0),
m_apiVersion(SAI_VERSION(0,0,0))
{
SWSS_LOG_ENTER();
SWSS_LOG_NOTICE("Options: %s", m_options->getString().c_str());
m_selectableChannel = std::make_shared<sairedis::ZeroMQSelectableChannel>(m_options->m_zmqChannel);
m_notifications = std::make_shared<syncd::ZeroMQNotificationProducer>(m_options->m_zmqNtfChannel);
loadProfileMap();
m_smt.profileGetValue = std::bind(&Proxy::profileGetValue, this, _1, _2);
m_smt.profileGetNextValue = std::bind(&Proxy::profileGetNextValue, this, _1, _2, _3);
m_test_services = m_smt.getServiceMethodTable();
memset(&m_sn, 0, sizeof(m_sn));
m_swNtf.onFdbEvent = std::bind(&Proxy::onFdbEvent, this, _1, _2);
m_swNtf.onNatEvent = std::bind(&Proxy::onNatEvent, this, _1, _2);
m_swNtf.onPortStateChange = std::bind(&Proxy::onPortStateChange, this, _1, _2);
m_swNtf.onQueuePfcDeadlock = std::bind(&Proxy::onQueuePfcDeadlock, this, _1, _2);
m_swNtf.onSwitchAsicSdkHealthEvent = std::bind(&Proxy::onSwitchAsicSdkHealthEvent, this, _1, _2, _3, _4, _5, _6);
m_swNtf.onSwitchShutdownRequest = std::bind(&Proxy::onSwitchShutdownRequest, this, _1);
m_swNtf.onSwitchStateChange = std::bind(&Proxy::onSwitchStateChange, this, _1, _2);
m_swNtf.onBfdSessionStateChange = std::bind(&Proxy::onBfdSessionStateChange, this, _1, _2);
m_swNtf.onPortHostTxReady = std::bind(&Proxy::onPortHostTxReady, this, _1, _2, _3);
m_swNtf.onTwampSessionEvent = std::bind(&Proxy::onTwampSessionEvent, this, _1, _2);
m_sn = m_swNtf.getSwitchNotifications();
sai_status_t status = m_vendorSai->apiInitialize(0, &m_test_services);
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_ERROR("FATAL: failed to sai_api_initialize: %s",
sai_serialize_status(status).c_str());
}
else
{
m_apiInitialized = true;
SWSS_LOG_NOTICE("api initialized success");
}
auto st = m_vendorSai->queryApiVersion(&m_apiVersion);
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_WARN("failed to obtain libsai api version: %s", sai_serialize_status(st).c_str());
}
else
{
SWSS_LOG_NOTICE("libsai api version: %lu", m_apiVersion);
}
}
Proxy::~Proxy()
{
SWSS_LOG_ENTER();
// TODO call stop()
if (m_apiInitialized)
{
SWSS_LOG_NOTICE("calling api uninitialize");
auto status = m_vendorSai->apiUninitialize();
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_ERROR("api uninitialize failed: %s", sai_serialize_status(status).c_str());
}
}
// TODO lock guard could be needed to wait for notifications destruction
// until all possible notification thread will be sent
m_notifications = nullptr;
}
void Proxy::loadProfileMap()
{
SWSS_LOG_ENTER();
std::ifstream profile(m_options->m_config);
if (!profile.is_open())
{
SWSS_LOG_WARN("failed to open profile map file: %s: %s",
m_options->m_config.c_str(),
strerror(errno));
return;
}
std::string line;
while (getline(profile, line))
{
if (line.size() > 0 && (line[0] == '#' || line[0] == ';'))
{
continue;
}
size_t pos = line.find("=");
if (pos == std::string::npos)
{
SWSS_LOG_WARN("not found '=' in line %s", line.c_str());
continue;
}
std::string key = line.substr(0, pos);
std::string value = line.substr(pos + 1);
m_profileMap[key] = value;
SWSS_LOG_NOTICE("insert: %s:%s", key.c_str(), value.c_str());
}
}
const char* Proxy::profileGetValue(
_In_ sai_switch_profile_id_t profile_id,
_In_ const char* variable)
{
SWSS_LOG_ENTER();
if (variable == NULL)
{
SWSS_LOG_WARN("variable is null");
return NULL;
}
auto it = m_profileMap.find(variable);
if (it == m_profileMap.end())
{
SWSS_LOG_NOTICE("%s: NULL", variable);
return NULL;
}
SWSS_LOG_NOTICE("%s: %s", variable, it->second.c_str());
return it->second.c_str();
}
int Proxy::profileGetNextValue(
_In_ sai_switch_profile_id_t profile_id,
_Out_ const char** variable,
_Out_ const char** value)
{
SWSS_LOG_ENTER();
if (value == NULL)
{
SWSS_LOG_INFO("resetting profile map iterator");
m_profileIter = m_profileMap.begin();
return 0;
}
if (variable == NULL)
{
SWSS_LOG_WARN("variable is null");
return -1;
}
if (m_profileIter == m_profileMap.end())
{
SWSS_LOG_INFO("iterator reached end");
return -1;
}
*variable = m_profileIter->first.c_str();
*value = m_profileIter->second.c_str();
SWSS_LOG_INFO("key: %s:%s", *variable, *value);
m_profileIter++;
return 0;
}
void Proxy::run()
{
SWSS_LOG_ENTER();
SWSS_LOG_NOTICE("thread start");
std::shared_ptr<swss::Select> s = std::make_shared<swss::Select>();
// TODO will we need this thread at all?, maybe just resend notification as they
// arrive ? could this potentially cause deadlock ? if we will be invoking
// some api under mutex and then that ntf would be called from same thread
// as api invoked that's why we have processing queue on syncd here we would
// need only protect ntf sender- notification channel
// m_processor->startNotificationsProcessingThread();
s->addSelectable(m_selectableChannel.get());
s->addSelectable(&m_stopEvent);
SWSS_LOG_NOTICE("entering main thread loop");
while (true)
{
swss::Selectable *sel = NULL;
int result = s->select(&sel);
if (sel == &m_stopEvent)
{
break;
}
else if (sel == m_selectableChannel.get())
{
processEvent(*m_selectableChannel.get());
}
else
{
SWSS_LOG_ERROR("select failed: %d", result);
}
}
SWSS_LOG_NOTICE("thread end");
}
void Proxy::stop()
{
SWSS_LOG_ENTER();
SWSS_LOG_NOTICE("stop thread requested");
// TODO maybe not needed
std::lock_guard<std::mutex> lock(m_mutex);
m_stopEvent.notify();
}
void Proxy::processEvent(
_In_ sairedis::SelectableChannel& consumer)
{
SWSS_LOG_ENTER();
std::lock_guard<std::mutex> lock(m_mutex);
do
{
swss::KeyOpFieldsValuesTuple kco;
consumer.pop(kco, false);
processSingleEvent(kco);
}
while (!consumer.empty());
}
void Proxy::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;
}
// TODO implement bulk create/remove/set/get
if (op == "create")
return processCreate(kco);
if (op == "remove")
return processRemove(kco);
if (op == "set")
return processSet(kco);
if (op == "get")
return processGet(kco);
if (op == "create_entry")
return processCreateEntry(kco);
if (op == "flush_fdb_entries")
return processFlushFdbEntries(kco);
if (op == "object_type_get_availability")
return processObjectTypeGetAvailability(kco);
if (op == "query_attribute_capability")
return processQueryAttributeCapability(kco);
if (op == "query_attribute_enum_values_capability")
return processQueryAttributeEnumValuesCapability(kco);
if (op == "object_type_query")
return processObjectTypeQuery(kco);
if (op == "switch_id_query")
return processSwitchIdQuery(kco);
if (op == "query_api_version")
return processQueryApiVersion(kco);
if (op == "log_set")
return processLogSet(kco);
if (op == "get_stats")
return processGetStats(kco);
if (op == "get_stats_ext")
return processGetStatsExt(kco);
if (op == "clear_stats")
return processClearStats(kco);
SWSS_LOG_THROW("event op '%s' is not implemented, FIXME", op.c_str());
}
void Proxy::processCreate(
_In_ const swss::KeyOpFieldsValuesTuple &kco)
{
SWSS_LOG_ENTER();
const std::string& key = kfvKey(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());
}
auto values = kfvFieldsValues(kco);
sai_object_id_t switchId = SAI_NULL_OBJECT_ID;
auto vv = values.back();
values.pop_back();
SWSS_LOG_NOTICE("removed last field: %s: %s", fvField(vv).c_str(), fvValue(vv).c_str());
sai_deserialize_object_id(fvValue(vv), switchId);
for (auto& v: values)
{
SWSS_LOG_DEBUG("attr: %s: %s", fvField(v).c_str(), fvValue(v).c_str());
}
saimeta::SaiAttributeList list(metaKey.objecttype, values, false);
sai_attribute_t *attr_list = list.get_attr_list();
uint32_t attr_count = list.get_attr_count();
if (metaKey.objecttype == SAI_OBJECT_TYPE_SWITCH)
{
/*
* TODO: must be done per switch, and switch may not exists yet
*/
updateAttributteNotificationPointers(attr_count, attr_list);
}
sai_object_id_t newObjectId = SAI_NULL_OBJECT_ID;;
sai_status_t status = m_vendorSai->create(metaKey.objecttype, &newObjectId, switchId, attr_count, attr_list);
std::vector<swss::FieldValueTuple> entry;
std::string strStatus = sai_serialize_status(status);
swss::FieldValueTuple fvt("OBJECT_ID", sai_serialize_object_id(newObjectId));
entry.push_back(fvt);
m_selectableChannel->set(strStatus, entry, "create_response");
}
void Proxy::processRemove(
_In_ const swss::KeyOpFieldsValuesTuple &kco)
{
SWSS_LOG_ENTER();
const std::string& key = kfvKey(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());
}
sai_status_t status = m_vendorSai->remove(metaKey);
std::string strStatus = sai_serialize_status(status);
m_selectableChannel->set(strStatus, {}, "remove_response");
}
void Proxy::processSet(
_In_ const swss::KeyOpFieldsValuesTuple &kco)
{
SWSS_LOG_ENTER();
const std::string& key = kfvKey(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());
}
auto values = kfvFieldsValues(kco);
for (auto& v: values)
{
SWSS_LOG_DEBUG("attr: %s: %s", fvField(v).c_str(), fvValue(v).c_str());
}
saimeta::SaiAttributeList list(metaKey.objecttype, values, false);
sai_attribute_t *attr_list = list.get_attr_list();
if (metaKey.objecttype == SAI_OBJECT_TYPE_SWITCH)
{
/*
* TODO: must be done per switch, and switch may not exists yet
*/
updateAttributteNotificationPointers(1, attr_list);
}
sai_status_t status = m_vendorSai->set(metaKey, attr_list);
std::vector<swss::FieldValueTuple> entry;
std::string strStatus = sai_serialize_status(status);
m_selectableChannel->set(strStatus, {}, "set_response");
}
void Proxy::processGet(
_In_ const swss::KeyOpFieldsValuesTuple &kco)
{
SWSS_LOG_ENTER();
const std::string& key = kfvKey(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());
}
auto& values = kfvFieldsValues(kco);
for (auto& v: values)
{
SWSS_LOG_DEBUG("attr: %s: %s", fvField(v).c_str(), fvValue(v).c_str());
}
saimeta::SaiAttributeList list(metaKey.objecttype, values, false);
sai_attribute_t *attr_list = list.get_attr_list();
uint32_t attr_count = list.get_attr_count();
auto status = m_vendorSai->get(metaKey, attr_count, attr_list);
std::vector<swss::FieldValueTuple> entry;
if (status == SAI_STATUS_SUCCESS)
{
entry = saimeta::SaiAttributeList::serialize_attr_list(
metaKey.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 = saimeta::SaiAttributeList::serialize_attr_list(
metaKey.objecttype,
attr_count,
attr_list,
true);
}
else
{
/*
* Some other error, don't send attributes at all.
*/
SWSS_LOG_WARN("api failed: %s", sai_serialize_status(status).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, "get_response");
}
void Proxy::processCreateEntry(
_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());
}
auto values = kfvFieldsValues(kco);
saimeta::SaiAttributeList list(metaKey.objecttype, values, false);
sai_attribute_t *attr_list = list.get_attr_list();
uint32_t attr_count = list.get_attr_count();
// since this is only used for create entries, there is no need for notification
// pointers translation, since object entries don't contain pointers
sai_status_t status = m_vendorSai->create(metaKey, SAI_NULL_OBJECT_ID, attr_count, attr_list);
std::string strStatus = sai_serialize_status(status);
m_selectableChannel->set(strStatus, {}, "create_entry_response");
}
void Proxy::processFlushFdbEntries(
_In_ const swss::KeyOpFieldsValuesTuple &kco)
{
SWSS_LOG_ENTER();
auto& key = kfvKey(kco);
auto strSwitchId = key.substr(key.find(":") + 1);
sai_object_id_t switchId;
sai_deserialize_object_id(strSwitchId, switchId);
auto& values = kfvFieldsValues(kco);
for (const auto &v: values)
{
SWSS_LOG_NOTICE("attr: %s: %s", fvField(v).c_str(), fvValue(v).c_str());
}
saimeta::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_vendorSai->flushFdbEntries(switchId, attr_count, attr_list);
std::string strStatus = sai_serialize_status(status);
m_selectableChannel->set(strStatus, {}, "flush_fdb_entries_response");
}
void Proxy::processObjectTypeGetAvailability(
_In_ const swss::KeyOpFieldsValuesTuple &kco)
{
SWSS_LOG_ENTER();
auto& strSwitchId = kfvKey(kco);
sai_object_id_t switchId;
sai_deserialize_object_id(strSwitchId, switchId);
std::vector<swss::FieldValueTuple> values = kfvFieldsValues(kco);
sai_object_type_t objectType;
sai_deserialize_object_type(fvValue(values.back()), objectType);
values.pop_back();
saimeta::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_vendorSai->objectTypeGetAvailability(
switchId,
objectType,
attr_count,
attr_list,
&count);
std::vector<swss::FieldValueTuple> entry;
if (status == SAI_STATUS_SUCCESS)
{
entry.emplace_back("COUNT", std::to_string(count));
}
std::string strStatus = sai_serialize_status(status);
m_selectableChannel->set(strStatus, entry, "object_type_get_availability_response");
}
void Proxy::processQueryAttributeCapability(
_In_ const swss::KeyOpFieldsValuesTuple &kco)
{
SWSS_LOG_ENTER();
auto& strSwitchId = kfvKey(kco);
sai_object_id_t switchId;
sai_deserialize_object_id(strSwitchId, switchId);
auto& values = kfvFieldsValues(kco);
if (values.size() != 2)
{
SWSS_LOG_ERROR("logic error, expected 2 arguments, received %zu", values.size());
auto strStatus = sai_serialize_status(SAI_STATUS_INVALID_PARAMETER);
m_selectableChannel->set(strStatus, {}, "query_attribute_capability_response");
return;
}
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_vendorSai->queryAttributeCapability(switchId, 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"))
};
}
auto strStatus = sai_serialize_status(status);
m_selectableChannel->set(strStatus, entry, "query_attribute_capability_response");
}
void Proxy::processQueryAttributeEnumValuesCapability(
_In_ const swss::KeyOpFieldsValuesTuple &kco)
{
SWSS_LOG_ENTER();
auto& strSwitchId = kfvKey(kco);
sai_object_id_t switchId;
sai_deserialize_object_id(strSwitchId, switchId);
auto& values = kfvFieldsValues(kco);
if (values.size() != 3)
{
SWSS_LOG_ERROR("logic error, expected 3 arguments, received %zu", values.size());
auto strStatus = sai_serialize_status(SAI_STATUS_INVALID_PARAMETER);
m_selectableChannel->set(strStatus, {}, "query_attribute_enum_values_capability_response");
return;
}
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_vendorSai->queryAttributeEnumValuesCapability(switchId, 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))
};
}
else if (status == SAI_STATUS_BUFFER_OVERFLOW)
{
entry =
{
swss::FieldValueTuple("ENUM_COUNT", std::to_string(enumCapList.count))
};
}
auto strStatus = sai_serialize_status(status);
m_selectableChannel->set(strStatus, entry, "query_attribute_enum_values_capability_response");
}
void Proxy::processObjectTypeQuery(
_In_ const swss::KeyOpFieldsValuesTuple &kco)
{
SWSS_LOG_ENTER();
const std::string& key = kfvKey(kco);
sai_object_id_t objectId;
sai_deserialize_object_id(key, objectId);
sai_object_type_t objectType = m_vendorSai->objectTypeQuery(objectId);
std::vector<swss::FieldValueTuple> entry;
std::string strStatus = sai_serialize_status(SAI_STATUS_SUCCESS); // we assume success
entry.emplace_back("OBJECT_TYPE", sai_serialize_object_type(objectType));
m_selectableChannel->set(strStatus, entry, "object_type_query_response");
}
void Proxy::processSwitchIdQuery(
_In_ const swss::KeyOpFieldsValuesTuple &kco)
{
SWSS_LOG_ENTER();
const std::string& key = kfvKey(kco);
sai_object_id_t objectId;
sai_deserialize_object_id(key, objectId);
sai_object_id_t switchId = m_vendorSai->switchIdQuery(objectId);
std::vector<swss::FieldValueTuple> entry;
std::string strStatus = sai_serialize_status(SAI_STATUS_SUCCESS); // we assume success
entry.emplace_back("OBJECT_ID", sai_serialize_object_id(switchId));
m_selectableChannel->set(strStatus, entry, "switch_id_query_response");
}
void Proxy::processQueryApiVersion(
_In_ const swss::KeyOpFieldsValuesTuple &kco)
{
SWSS_LOG_ENTER();
sai_api_version_t version;
sai_status_t status = m_vendorSai->queryApiVersion(&version);
std::vector<swss::FieldValueTuple> entry;
if (status == SAI_STATUS_SUCCESS)
{
entry.emplace_back("VERSION", std::to_string(version));
SWSS_LOG_NOTICE("query api version returned: %ld", version);
}
auto strStatus = sai_serialize_status(status);
m_selectableChannel->set(strStatus, entry, "query_api_version_response");
}
void Proxy::processLogSet(
_In_ const swss::KeyOpFieldsValuesTuple &kco)
{
SWSS_LOG_ENTER();
auto& key = kfvKey(kco);
auto strApi = key.substr(0, key.find(":"));
auto strLogLevel = key.substr(key.find(":") + 1);
sai_api_t api;
sai_deserialize_api(strApi, api);
sai_log_level_t level;
sai_deserialize_log_level(strLogLevel, level);
sai_status_t status = m_vendorSai->logSet(api, level);
auto strStatus = sai_serialize_status(status);
m_selectableChannel->set(strStatus, {}, "log_set_response");
}
void Proxy::processGetStats(
_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);
if (!sai_metadata_is_object_type_valid(metaKey.objecttype))
{
SWSS_LOG_THROW("invalid object type %s", key.c_str());
}
auto oi = sai_metadata_get_object_type_info(metaKey.objecttype);
if (oi == NULL)
{
SWSS_LOG_ERROR("invalid object type: %s", sai_serialize_object_type(metaKey.objecttype).c_str());
std::string strStatus = sai_serialize_status(SAI_STATUS_FAILURE);
m_selectableChannel->set(strStatus, {}, "get_stats_response");
return;
}
auto &values = kfvFieldsValues(kco);
uint32_t numberOfCounters = (uint32_t)values.size();
std::vector<sai_stat_id_t> counterIds;
std::vector<uint64_t> counters;
for (const auto&fv: values)
{
sai_stat_id_t stat;
sai_deserialize_enum(fvField(fv), oi->statenum, (int32_t&)stat);
counters.push_back(stat);
}
auto status = m_vendorSai->getStats(
metaKey.objecttype,
metaKey.objectkey.key.object_id,
numberOfCounters,
counterIds.data(),
counters.data());
std::vector<swss::FieldValueTuple> entry;
if (status == SAI_STATUS_SUCCESS)
{
for (auto c: counters)
{
entry.emplace_back("", std::to_string(c));
}
}
std::string strStatus = sai_serialize_status(status);
m_selectableChannel->set(strStatus, entry, "get_stats_response");
}
void Proxy::processGetStatsExt(
_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);
if (!sai_metadata_is_object_type_valid(metaKey.objecttype))
{
SWSS_LOG_THROW("invalid object type %s", key.c_str());
}
auto oi = sai_metadata_get_object_type_info(metaKey.objecttype);
if (oi == NULL)
{
SWSS_LOG_ERROR("invalid object type: %s", sai_serialize_object_type(metaKey.objecttype).c_str());
std::string strStatus = sai_serialize_status(SAI_STATUS_FAILURE);
m_selectableChannel->set(strStatus, {}, "get_stats_ext_response");
return;
}
auto values = kfvFieldsValues(kco);
sai_stats_mode_t mode = (sai_stats_mode_t)stoull(fvValue(values.back()));
values.pop_back();
uint32_t numberOfCounters = (uint32_t)values.size();
std::vector<sai_stat_id_t> counterIds;
std::vector<uint64_t> counters;
for (const auto&fv: values)
{
sai_stat_id_t stat;
sai_deserialize_enum(fvField(fv), oi->statenum, (int32_t&)stat);
counters.push_back(stat);
}
auto status = m_vendorSai->getStatsExt(
metaKey.objecttype,
metaKey.objectkey.key.object_id,
numberOfCounters,
counterIds.data(),
mode,
counters.data());
std::vector<swss::FieldValueTuple> entry;
if (status == SAI_STATUS_SUCCESS)
{
for (auto c: counters)
{
entry.emplace_back("", std::to_string(c));
}
}
std::string strStatus = sai_serialize_status(status);
m_selectableChannel->set(strStatus, entry, "get_stats_ext_response");
}
void Proxy::processClearStats(
_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);
if (!sai_metadata_is_object_type_valid(metaKey.objecttype))
{
SWSS_LOG_THROW("invalid object type %s", key.c_str());
}
auto oi = sai_metadata_get_object_type_info(metaKey.objecttype);
if (oi == NULL)
{
SWSS_LOG_ERROR("invalid object type: %s", sai_serialize_object_type(metaKey.objecttype).c_str());
std::string strStatus = sai_serialize_status(SAI_STATUS_FAILURE);
m_selectableChannel->set(strStatus, {}, "clear_stats_response");
return;
}
auto &values = kfvFieldsValues(kco);
uint32_t numberOfCounters = (uint32_t)values.size();
std::vector<sai_stat_id_t> counterIds;
std::vector<uint64_t> counters;
for (const auto&fv: values)
{
sai_stat_id_t stat;
sai_deserialize_enum(fvField(fv), oi->statenum, (int32_t&)stat);
counters.push_back(stat);
}
auto status = m_vendorSai->clearStats(
metaKey.objecttype,
metaKey.objectkey.key.object_id,
numberOfCounters,
counterIds.data());
std::vector<swss::FieldValueTuple> entry;
std::string strStatus = sai_serialize_status(status);
m_selectableChannel->set(strStatus, entry, "clear_stats_response");
}
void Proxy::updateAttributteNotificationPointers(
_In_ uint32_t count,
_Inout_ sai_attribute_t* attr_list)
{
SWSS_LOG_ENTER();
sai_metadata_update_attribute_notification_pointers(&m_sn, count, attr_list);
}
// TODO move to notification handler class
void Proxy::onFdbEvent(
_In_ uint32_t count,
_In_ const sai_fdb_event_notification_data_t *data)
{
SWSS_LOG_ENTER();
std::string s = sai_serialize_fdb_event_ntf(count, data);
sendNotification(SAI_SWITCH_NOTIFICATION_NAME_FDB_EVENT, s);
}
void Proxy::onNatEvent(
_In_ uint32_t count,
_In_ const sai_nat_event_notification_data_t *data)
{
SWSS_LOG_ENTER();
std::string s = sai_serialize_nat_event_ntf(count, data);
sendNotification(SAI_SWITCH_NOTIFICATION_NAME_NAT_EVENT, s);
}
void Proxy::onPortStateChange(
_In_ uint32_t count,
_In_ const sai_port_oper_status_notification_t *data)
{
SWSS_LOG_ENTER();
auto ntfdata = syncd::Workaround::convertPortOperStatusNotification(count, data, m_apiVersion);
auto s = sai_serialize_port_oper_status_ntf((uint32_t)ntfdata.size(), ntfdata.data());
sendNotification(SAI_SWITCH_NOTIFICATION_NAME_PORT_STATE_CHANGE, s);
}
void Proxy::onPortHostTxReady(
_In_ sai_object_id_t switch_id,
_In_ sai_object_id_t port_id,
_In_ sai_port_host_tx_ready_status_t host_tx_ready_status)
{
SWSS_LOG_ENTER();
auto s = sai_serialize_port_host_tx_ready_ntf(switch_id, port_id, host_tx_ready_status);
sendNotification(SAI_SWITCH_NOTIFICATION_NAME_PORT_HOST_TX_READY, s);
}
void Proxy::onQueuePfcDeadlock(
_In_ uint32_t count,
_In_ const sai_queue_deadlock_notification_data_t *data)
{
SWSS_LOG_ENTER();
auto s = sai_serialize_queue_deadlock_ntf(count, data);
sendNotification(SAI_SWITCH_NOTIFICATION_NAME_QUEUE_PFC_DEADLOCK, s);
}
void Proxy::onSwitchShutdownRequest(
_In_ sai_object_id_t switch_id)
{
SWSS_LOG_ENTER();
auto s = sai_serialize_switch_shutdown_request(switch_id);
sendNotification(SAI_SWITCH_NOTIFICATION_NAME_SWITCH_SHUTDOWN_REQUEST, s);
}
void Proxy::onSwitchAsicSdkHealthEvent(
_In_ sai_object_id_t switch_id,
_In_ sai_switch_asic_sdk_health_severity_t severity,
_In_ sai_timespec_t timestamp,
_In_ sai_switch_asic_sdk_health_category_t category,
_In_ sai_switch_health_data_t data,
_In_ const sai_u8_list_t description)
{
SWSS_LOG_ENTER();
std::string s = sai_serialize_switch_asic_sdk_health_event(switch_id, severity, timestamp, category, data, description);
sendNotification(SAI_SWITCH_NOTIFICATION_NAME_SWITCH_ASIC_SDK_HEALTH_EVENT, s);
}
void Proxy::onSwitchStateChange(
_In_ sai_object_id_t switch_id,
_In_ sai_switch_oper_status_t switch_oper_status)
{
SWSS_LOG_ENTER();
auto s = sai_serialize_switch_oper_status(switch_id, switch_oper_status);
sendNotification(SAI_SWITCH_NOTIFICATION_NAME_SWITCH_STATE_CHANGE, s);
}
void Proxy::onBfdSessionStateChange(
_In_ uint32_t count,
_In_ const sai_bfd_session_state_notification_t *data)
{
SWSS_LOG_ENTER();
std::string s = sai_serialize_bfd_session_state_ntf(count, data);
sendNotification(SAI_SWITCH_NOTIFICATION_NAME_BFD_SESSION_STATE_CHANGE, s);
}
void Proxy::onTwampSessionEvent(
_In_ uint32_t count,
_In_ const sai_twamp_session_event_notification_data_t *data)
{
SWSS_LOG_ENTER();
std::string s = sai_serialize_twamp_session_event_ntf(count, data);
sendNotification(SAI_SWITCH_NOTIFICATION_NAME_TWAMP_SESSION_EVENT, s);
}
void Proxy::sendNotification(
_In_ const std::string& op,
_In_ const std::string& data)
{
SWSS_LOG_ENTER();
std::vector<swss::FieldValueTuple> entry;
swss::KeyOpFieldsValuesTuple item(op, data, entry);
SWSS_LOG_INFO("%s %s", op.c_str(), data.c_str());
m_notificationsSentCount++;
m_notifications->send(op, data, entry);
}
uint64_t Proxy::getNotificationsSentCount() const
{
SWSS_LOG_ENTER();
return m_notificationsSentCount;
}