From f6c7422a8a1efedc990cbd12e888f572508ad490 Mon Sep 17 00:00:00 2001 From: Santhosh Kumar T <53558409+santhosh-kt@users.noreply.github.com> Date: Tue, 5 Jan 2021 00:19:59 +0530 Subject: [PATCH] ASIC internal temperature sensors support (#1517) **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. --- orchagent/orchdaemon.cpp | 9 +- orchagent/switchorch.cpp | 276 +++++++++++++++++++++++++++++++- orchagent/switchorch.h | 23 ++- tests/mock_tests/aclorch_ut.cpp | 10 +- 4 files changed, 311 insertions(+), 7 deletions(-) diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index a1f77854e8..f7e3138153 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -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 switch_tables = { + conf_asic_sensors, + app_switch_table + }; + + gSwitchOrch = new SwitchOrch(m_applDb, switch_tables, stateDbSwitchTable); const int portsorch_base_pri = 40; diff --git a/orchagent/switchorch.cpp b/orchagent/switchorch.cpp index bac2c9a3af..c6c6bd812c 100644 --- a/orchagent/switchorch.cpp +++ b/orchagent/switchorch.cpp @@ -33,17 +33,100 @@ const map packet_action_map = {"trap", SAI_PACKET_ACTION_TRAP} }; -SwitchOrch::SwitchOrch(DBConnector *db, string tableName, TableConnector switchTable): - Orch(db, tableName), +SwitchOrch::SwitchOrch(DBConnector *db, vector& 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(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(); @@ -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(); @@ -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 values; + + if (m_numTempSensors) + { + std::vector 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 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 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& values) { m_switchTable.set("switch", values); diff --git a/orchagent/switchorch.h b/orchagent/switchorch.h index 579447ee19..c43bc41ae2 100644 --- a/orchagent/switchorch.h +++ b/orchagent/switchorch.h @@ -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 { @@ -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& connectors, TableConnector switchTable); bool checkRestartReady() { return m_warmRestartCheck.checkRestartReadyState; } bool checkRestartNoFreeze() { return m_warmRestartCheck.noFreeze; } bool skipPendingTaskCheck() { return m_warmRestartCheck.skipPendingTaskCheck; } @@ -22,12 +27,28 @@ class SwitchOrch : public Orch void set_switch_capability(const std::vector& 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 m_stateDb = nullptr; + std::shared_ptr 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}; diff --git a/tests/mock_tests/aclorch_ut.cpp b/tests/mock_tests/aclorch_ut.cpp index 5f71471a57..65c3c16f92 100644 --- a/tests/mock_tests/aclorch_ut.cpp +++ b/tests/mock_tests/aclorch_ut.cpp @@ -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 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 ...