Skip to content

Commit

Permalink
ASIC internal temperature sensors support (#1517)
Browse files Browse the repository at this point in the history
**What I did**
1) ASICs have multiple internal thermal sensors.
2) With the help of configuration, a poller is introduced in Orchagent that will periodically retrieve values of these sensors with the help of SAI APIs (opencomputeproject/SAI#880).
3) These retrieved values are being populated to the state DB (In "ASIC_TEMPERATURE_INFO" table).

**Why I did it**
As part of ASIC Thermal Monitoring HLD.
  • Loading branch information
santhosh-kt authored Jan 4, 2021
1 parent 0aa9ef2 commit f6c7422
Show file tree
Hide file tree
Showing 4 changed files with 311 additions and 7 deletions.
9 changes: 8 additions & 1 deletion orchagent/orchdaemon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,15 @@ bool OrchDaemon::init()

string platform = getenv("platform") ? getenv("platform") : "";
TableConnector stateDbSwitchTable(m_stateDb, "SWITCH_CAPABILITY");
TableConnector app_switch_table(m_applDb, APP_SWITCH_TABLE_NAME);
TableConnector conf_asic_sensors(m_configDb, CFG_ASIC_SENSORS_TABLE_NAME);

gSwitchOrch = new SwitchOrch(m_applDb, APP_SWITCH_TABLE_NAME, stateDbSwitchTable);
vector<TableConnector> switch_tables = {
conf_asic_sensors,
app_switch_table
};

gSwitchOrch = new SwitchOrch(m_applDb, switch_tables, stateDbSwitchTable);

const int portsorch_base_pri = 40;

Expand Down
276 changes: 272 additions & 4 deletions orchagent/switchorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,100 @@ const map<string, sai_packet_action_t> packet_action_map =
{"trap", SAI_PACKET_ACTION_TRAP}
};

SwitchOrch::SwitchOrch(DBConnector *db, string tableName, TableConnector switchTable):
Orch(db, tableName),
SwitchOrch::SwitchOrch(DBConnector *db, vector<TableConnector>& connectors, TableConnector switchTable):
Orch(connectors),
m_switchTable(switchTable.first, switchTable.second),
m_db(db)
m_db(db),
m_stateDb(new DBConnector(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0)),
m_asicSensorsTable(new Table(m_stateDb.get(), ASIC_TEMPERATURE_INFO_TABLE_NAME)),
m_sensorsPollerTimer (new SelectableTimer((timespec { .tv_sec = DEFAULT_ASIC_SENSORS_POLLER_INTERVAL, .tv_nsec = 0 })))
{
m_restartCheckNotificationConsumer = new NotificationConsumer(db, "RESTARTCHECK");
auto restartCheckNotifier = new Notifier(m_restartCheckNotificationConsumer, this, "RESTARTCHECK");
Orch::addExecutor(restartCheckNotifier);

initSensorsTable();
auto executorT = new ExecutableTimer(m_sensorsPollerTimer, this, "ASIC_SENSORS_POLL_TIMER");
Orch::addExecutor(executorT);
}

void SwitchOrch::doTask(Consumer &consumer)
void SwitchOrch::doCfgSensorsTableTask(Consumer &consumer)
{
SWSS_LOG_ENTER();

auto it = consumer.m_toSync.begin();
while (it != consumer.m_toSync.end())
{
KeyOpFieldsValuesTuple t = it->second;
string table_attr = kfvKey(t);
string op = kfvOp(t);

if (op == SET_COMMAND)
{
FieldValueTuple fvt = kfvFieldsValues(t)[0];
SWSS_LOG_NOTICE("ASIC sensors : set %s(%s) to %s", table_attr.c_str(), fvField(fvt).c_str(), fvValue(fvt).c_str());

if (table_attr == ASIC_SENSORS_POLLER_STATUS)
{
if (fvField(fvt) == "admin_status")
{
if (fvValue(fvt) == "enable" && !m_sensorsPollerEnabled)
{
m_sensorsPollerTimer->start();
m_sensorsPollerEnabled = true;
}
else if (fvValue(fvt) == "disable")
{
m_sensorsPollerEnabled = false;
}
else
{
SWSS_LOG_ERROR("ASIC sensors : unsupported operation for poller state %d",m_sensorsPollerEnabled);
}
}
else
{
SWSS_LOG_ERROR("ASIC sensors : unsupported field in attribute %s", ASIC_SENSORS_POLLER_STATUS);
}
}
else if (table_attr == ASIC_SENSORS_POLLER_INTERVAL)
{
uint32_t interval=to_uint<uint32_t>(fvValue(fvt));

if (fvField(fvt) == "interval")
{
if (interval != m_sensorsPollerInterval)
{
auto intervT = timespec { .tv_sec = interval , .tv_nsec = 0 };
m_sensorsPollerTimer->setInterval(intervT);
m_sensorsPollerInterval = interval;
m_sensorsPollerIntervalChanged = true;
}
else
{
SWSS_LOG_INFO("ASIC sensors : poller interval unchanged : %d seconds",m_sensorsPollerInterval);
}
}
else
{
SWSS_LOG_ERROR("ASIC sensors : unsupported field in attribute %s", ASIC_SENSORS_POLLER_INTERVAL);
}
}
else
{
SWSS_LOG_ERROR("ASIC sensors : unsupported attribute %s", table_attr.c_str());
}
}
else
{
SWSS_LOG_ERROR("ASIC sensors : unsupported operation %s",op.c_str());
}

it = consumer.m_toSync.erase(it);
}
}

void SwitchOrch::doAppSwitchTableTask(Consumer &consumer)
{
SWSS_LOG_ENTER();

Expand Down Expand Up @@ -145,6 +228,26 @@ void SwitchOrch::doTask(Consumer &consumer)
}
}

void SwitchOrch::doTask(Consumer &consumer)
{
SWSS_LOG_ENTER();
const string & table_name = consumer.getTableName();

if (table_name == APP_SWITCH_TABLE_NAME)
{
doAppSwitchTableTask(consumer);
}
else if (table_name == CFG_ASIC_SENSORS_TABLE_NAME)
{
doCfgSensorsTableTask(consumer);
}
else
{
SWSS_LOG_ERROR("Unknown table : %s", table_name.c_str());
}

}

void SwitchOrch::doTask(NotificationConsumer& consumer)
{
SWSS_LOG_ENTER();
Expand Down Expand Up @@ -209,6 +312,171 @@ bool SwitchOrch::setAgingFDB(uint32_t sec)
return true;
}

void SwitchOrch::doTask(SelectableTimer &timer)
{
SWSS_LOG_ENTER();

if (&timer == m_sensorsPollerTimer)
{
if (m_sensorsPollerIntervalChanged)
{
m_sensorsPollerTimer->reset();
m_sensorsPollerIntervalChanged = false;
}

if (!m_sensorsPollerEnabled)
{
m_sensorsPollerTimer->stop();
return;
}

sai_attribute_t attr;
sai_status_t status;
std::vector<FieldValueTuple> values;

if (m_numTempSensors)
{
std::vector<int32_t> temp_list(m_numTempSensors);

memset(&attr, 0, sizeof(attr));
attr.id = SAI_SWITCH_ATTR_TEMP_LIST;
attr.value.s32list.count = m_numTempSensors;
attr.value.s32list.list = temp_list.data();

status = sai_switch_api->get_switch_attribute(gSwitchId , 1, &attr);
if (status == SAI_STATUS_SUCCESS)
{
for (size_t i = 0; i < attr.value.s32list.count ; i++) {
const std::string &fieldName = "temperature_" + std::to_string(i);
values.emplace_back(fieldName, std::to_string(temp_list[i]));
}
m_asicSensorsTable->set("",values);
}
else
{
SWSS_LOG_ERROR("ASIC sensors : failed to get SAI_SWITCH_ATTR_TEMP_LIST: %d", status);
}
}

if (m_sensorsMaxTempSupported)
{
memset(&attr, 0, sizeof(attr));
attr.id = SAI_SWITCH_ATTR_MAX_TEMP;

status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr);
if (status == SAI_STATUS_SUCCESS)
{
const std::string &fieldName = "maximum_temperature";
values.emplace_back(fieldName, std::to_string(attr.value.s32));
m_asicSensorsTable->set("",values);
}
else if (status == SAI_STATUS_NOT_SUPPORTED || status == SAI_STATUS_NOT_IMPLEMENTED)
{
m_sensorsMaxTempSupported = false;
SWSS_LOG_INFO("ASIC sensors : SAI_SWITCH_ATTR_MAX_TEMP is not supported");
}
else
{
m_sensorsMaxTempSupported = false;
SWSS_LOG_ERROR("ASIC sensors : failed to get SAI_SWITCH_ATTR_MAX_TEMP: %d", status);
}
}

if (m_sensorsAvgTempSupported)
{
memset(&attr, 0, sizeof(attr));
attr.id = SAI_SWITCH_ATTR_AVERAGE_TEMP;

status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr);
if (status == SAI_STATUS_SUCCESS)
{
const std::string &fieldName = "average_temperature";
values.emplace_back(fieldName, std::to_string(attr.value.s32));
m_asicSensorsTable->set("",values);
}
else if (status == SAI_STATUS_NOT_SUPPORTED || status == SAI_STATUS_NOT_IMPLEMENTED)
{
m_sensorsAvgTempSupported = false;
SWSS_LOG_INFO("ASIC sensors : SAI_SWITCH_ATTR_AVERAGE_TEMP is not supported");
}
else
{
m_sensorsAvgTempSupported = false;
SWSS_LOG_ERROR("ASIC sensors : failed to get SAI_SWITCH_ATTR_AVERAGE_TEMP: %d", status);
}
}
}
}

void SwitchOrch::initSensorsTable()
{
SWSS_LOG_ENTER();

sai_attribute_t attr;
sai_status_t status;
std::vector<FieldValueTuple> values;

if (!m_numTempSensorsInitialized)
{
memset(&attr, 0, sizeof(attr));
attr.id = SAI_SWITCH_ATTR_MAX_NUMBER_OF_TEMP_SENSORS;

status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr);
if (status == SAI_STATUS_SUCCESS)
{
m_numTempSensors = attr.value.u8;
m_numTempSensorsInitialized = true;
}
else if (status == SAI_STATUS_NOT_SUPPORTED || status == SAI_STATUS_NOT_IMPLEMENTED)
{
m_numTempSensorsInitialized = true;
SWSS_LOG_INFO("ASIC sensors : SAI_SWITCH_ATTR_MAX_NUMBER_OF_TEMP_SENSORS is not supported");
}
else
{
SWSS_LOG_ERROR("ASIC sensors : failed to get SAI_SWITCH_ATTR_MAX_NUMBER_OF_TEMP_SENSORS: %d", status);
}
}

if (m_numTempSensors)
{
std::vector<int32_t> temp_list(m_numTempSensors);

memset(&attr, 0, sizeof(attr));
attr.id = SAI_SWITCH_ATTR_TEMP_LIST;
attr.value.s32list.count = m_numTempSensors;
attr.value.s32list.list = temp_list.data();

status = sai_switch_api->get_switch_attribute(gSwitchId , 1, &attr);
if (status == SAI_STATUS_SUCCESS)
{
for (size_t i = 0; i < attr.value.s32list.count ; i++) {
const std::string &fieldName = "temperature_" + std::to_string(i);
values.emplace_back(fieldName, std::to_string(0));
}
m_asicSensorsTable->set("",values);
}
else
{
SWSS_LOG_ERROR("ASIC sensors : failed to get SAI_SWITCH_ATTR_TEMP_LIST: %d", status);
}
}

if (m_sensorsMaxTempSupported)
{
const std::string &fieldName = "maximum_temperature";
values.emplace_back(fieldName, std::to_string(0));
m_asicSensorsTable->set("",values);
}

if (m_sensorsAvgTempSupported)
{
const std::string &fieldName = "average_temperature";
values.emplace_back(fieldName, std::to_string(0));
m_asicSensorsTable->set("",values);
}
}

void SwitchOrch::set_switch_capability(const std::vector<FieldValueTuple>& values)
{
m_switchTable.set("switch", values);
Expand Down
23 changes: 22 additions & 1 deletion orchagent/switchorch.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
#pragma once

#include "orch.h"
#include "timer.h"

#define DEFAULT_ASIC_SENSORS_POLLER_INTERVAL 60
#define ASIC_SENSORS_POLLER_STATUS "ASIC_SENSORS_POLLER_STATUS"
#define ASIC_SENSORS_POLLER_INTERVAL "ASIC_SENSORS_POLLER_INTERVAL"

struct WarmRestartCheck
{
Expand All @@ -12,7 +17,7 @@ struct WarmRestartCheck
class SwitchOrch : public Orch
{
public:
SwitchOrch(swss::DBConnector *db, std::string tableName, TableConnector switchTable);
SwitchOrch(swss::DBConnector *db, std::vector<TableConnector>& connectors, TableConnector switchTable);
bool checkRestartReady() { return m_warmRestartCheck.checkRestartReadyState; }
bool checkRestartNoFreeze() { return m_warmRestartCheck.noFreeze; }
bool skipPendingTaskCheck() { return m_warmRestartCheck.skipPendingTaskCheck; }
Expand All @@ -22,12 +27,28 @@ class SwitchOrch : public Orch
void set_switch_capability(const std::vector<swss::FieldValueTuple>& values);
private:
void doTask(Consumer &consumer);
void doTask(swss::SelectableTimer &timer);
void doCfgSensorsTableTask(Consumer &consumer);
void doAppSwitchTableTask(Consumer &consumer);
void initSensorsTable();

swss::NotificationConsumer* m_restartCheckNotificationConsumer;
void doTask(swss::NotificationConsumer& consumer);
swss::DBConnector *m_db;
swss::Table m_switchTable;

// ASIC temperature sensors
std::shared_ptr<swss::DBConnector> m_stateDb = nullptr;
std::shared_ptr<swss::Table> m_asicSensorsTable= nullptr;
swss::SelectableTimer* m_sensorsPollerTimer = nullptr;
bool m_sensorsPollerEnabled = false;
uint32_t m_sensorsPollerInterval = DEFAULT_ASIC_SENSORS_POLLER_INTERVAL;
bool m_sensorsPollerIntervalChanged = false;
uint8_t m_numTempSensors = 0;
bool m_numTempSensorsInitialized = false;
bool m_sensorsMaxTempSupported = true;
bool m_sensorsAvgTempSupported = true;

// Information contained in the request from
// external program for orchagent pre-shutdown state check
WarmRestartCheck m_warmRestartCheck = {false, false, false};
Expand Down
10 changes: 9 additions & 1 deletion tests/mock_tests/aclorch_ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,16 @@ namespace aclorch_test
gVirtualRouterId = attr.value.oid;

TableConnector stateDbSwitchTable(m_state_db.get(), "SWITCH_CAPABILITY");
TableConnector conf_asic_sensors(m_config_db.get(), CFG_ASIC_SENSORS_TABLE_NAME);
TableConnector app_switch_table(m_app_db.get(), APP_SWITCH_TABLE_NAME);

vector<TableConnector> switch_tables = {
conf_asic_sensors,
app_switch_table
};

ASSERT_EQ(gSwitchOrch, nullptr);
gSwitchOrch = new SwitchOrch(m_app_db.get(), APP_SWITCH_TABLE_NAME, stateDbSwitchTable);
gSwitchOrch = new SwitchOrch(m_app_db.get(), switch_tables, stateDbSwitchTable);

// Create dependencies ...

Expand Down

0 comments on commit f6c7422

Please sign in to comment.