diff --git a/cfgmgr/Makefile.am b/cfgmgr/Makefile.am index 0f71ad7b0bb..c2f063d0406 100644 --- a/cfgmgr/Makefile.am +++ b/cfgmgr/Makefile.am @@ -5,7 +5,7 @@ LIBNL_LIBS = -lnl-genl-3 -lnl-route-3 -lnl-3 SAIMETA_LIBS = -lsaimeta -lsaimetadata -lzmq COMMON_LIBS = -lswsscommon -lpthread -bin_PROGRAMS = vlanmgrd teammgrd portmgrd intfmgrd buffermgrd vrfmgrd nbrmgrd vxlanmgrd sflowmgrd natmgrd coppmgrd tunnelmgrd macsecmgrd fabricmgrd stpmgrd +bin_PROGRAMS = vlanmgrd teammgrd portmgrd intfmgrd buffermgrd vrfmgrd nbrmgrd vxlanmgrd sflowmgrd natmgrd coppmgrd tunnelmgrd macsecmgrd fabricmgrd stpmgrd otnmgrd cfgmgrdir = $(datadir)/swss @@ -107,6 +107,11 @@ stpmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAG stpmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) stpmgrd_LDADD = $(LDFLAGS_ASAN) $(COMMON_LIBS) $(SAIMETA_LIBS) +otnmgrd_SOURCES = otnmgrd.cpp otnmgr.cpp $(COMMON_ORCH_SOURCE) shellcmd.h +otnmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +otnmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +otnmgrd_LDADD = $(LDFLAGS_ASAN) $(COMMON_LIBS) $(SAIMETA_LIBS) + if GCOV_ENABLED vlanmgrd_SOURCES += ../gcovpreload/gcovpreload.cpp teammgrd_SOURCES += ../gcovpreload/gcovpreload.cpp @@ -123,6 +128,7 @@ coppmgrd_SOURCES += ../gcovpreload/gcovpreload.cpp tunnelmgrd_SOURCES += ../gcovpreload/gcovpreload.cpp macsecmgrd_SOURCES += ../gcovpreload/gcovpreload.cpp stpmgrd_SOURCES += ../gcovpreload/gcovpreload.cpp +otnmgrd_SOURCES += ../gcovpreload/gcovpreload.cpp endif if ASAN_ENABLED @@ -141,5 +147,6 @@ tunnelmgrd_SOURCES += $(top_srcdir)/lib/asan.cpp macsecmgrd_SOURCES += $(top_srcdir)/lib/asan.cpp fabricmgrd_SOURCES += $(top_srcdir)/lib/asan.cpp stpmgrd_SOURCES += $(top_srcdir)/lib/asan.cpp +otnmgrd_SOURCES += $(top_srcdir)/lib/asan.cpp endif diff --git a/cfgmgr/otnmgr.cpp b/cfgmgr/otnmgr.cpp new file mode 100644 index 00000000000..af2a326ccf9 --- /dev/null +++ b/cfgmgr/otnmgr.cpp @@ -0,0 +1,75 @@ +#include "otnmgr.h" + +using namespace std; +using namespace swss; + +OtnMgr::OtnMgr(DBConnector *cfgDb, DBConnector *appDb, const std::vector &tableNames, const std::map &tableMaps) : + Orch(cfgDb, tableNames), + m_appl_db(appDb), + m_tableMaps(tableMaps) +{ +} + +void OtnMgr::doTask(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + + string cfgName = consumer.getTableName(); + + /* get app table by name */ + auto itApp = m_tableMaps.find(cfgName); + if (itApp == m_tableMaps.end()) + { + SWSS_LOG_ERROR("OtnMgr|%s is invalid", cfgName.c_str()); + return; + } + const string &appName = itApp->second; + shared_ptr appTable; + auto itTable = m_appTables.find(appName); + if (itTable == m_appTables.end()) + { + appTable = make_shared(m_appl_db, appName); + m_appTables[appName] = appTable; + } + else + { + appTable = itTable->second; + } + + auto it = consumer.m_toSync.begin(); + while (it != consumer.m_toSync.end()) + { + auto &t = it->second; + string alias = kfvKey(t); + string op = kfvOp(t); + + SWSS_LOG_NOTICE("OtnMgr doTask, cfg=%s, app=%s, key=%s, op=%s", cfgName.c_str(), appName.c_str(), alias.c_str(), op.c_str()); + + if (op == SET_COMMAND) + { + auto values = kfvFieldsValues(t); + for (const auto &value : values) + { + SWSS_LOG_NOTICE("OtnMgr doTask, key=%s, value=%s", value.first.c_str(), value.second.c_str()); + } + if (!values.empty()) + { + writeConfigToAppDb(appTable, alias, values); + } + } + else if (op == DEL_COMMAND) + { + SWSS_LOG_NOTICE("Delete component: %s", alias.c_str()); + appTable->del(alias); + } + + it = consumer.m_toSync.erase(it); + } +} + +void OtnMgr::writeConfigToAppDb(std::shared_ptr &table, const std::string &alias, const std::vector &field_values) +{ + SWSS_LOG_ENTER(); + + table->set(alias, field_values); +} diff --git a/cfgmgr/otnmgr.h b/cfgmgr/otnmgr.h new file mode 100644 index 00000000000..d1f07d228b7 --- /dev/null +++ b/cfgmgr/otnmgr.h @@ -0,0 +1,29 @@ +#pragma once + +#include "dbconnector.h" +#include "orch.h" +#include "producerstatetable.h" + +#include +#include +#include +#include + +namespace swss { + +class OtnMgr : public Orch +{ +public: + OtnMgr(DBConnector *cfgDb, DBConnector *appDb, const std::vector &tableNames, const std::map &tableMaps); + + using Orch::doTask; +private: + DBConnector *m_appl_db; + std::map m_tableMaps; + std::map> m_appTables; + + void doTask(Consumer &consumer); + void writeConfigToAppDb(std::shared_ptr &table, const std::string &alias, const std::vector &field_values); +}; + +} diff --git a/cfgmgr/otnmgrd.cpp b/cfgmgr/otnmgrd.cpp new file mode 100644 index 00000000000..c411b525c8c --- /dev/null +++ b/cfgmgr/otnmgrd.cpp @@ -0,0 +1,72 @@ +#include + +#include "otnmgr.h" +#include "schema.h" +#include "select.h" + +using namespace std; +using namespace swss; + +#define SELECT_TIMEOUT 1000 + +int main(int argc, char **argv) +{ + Logger::linkToDbNative("otnmgrd"); + SWSS_LOG_ENTER(); + + SWSS_LOG_NOTICE("--- Starting otnmgrd ---"); + + try + { + map cfg_maps = + { + { CFG_OTN_ATTENUATOR_TABLE_NAME, APP_OTN_ATTENUATOR_TABLE_NAME }, + { CFG_OTN_OA_TABLE_NAME, APP_OTN_OA_TABLE_NAME }, + }; + + vector cfg_tables; + for (const auto &it : cfg_maps) + { + cfg_tables.push_back(it.first); + } + + DBConnector cfgDb("CONFIG_DB", 0); + DBConnector appDb("APPL_DB", 0); + + OtnMgr otnMgr(&cfgDb, &appDb, cfg_tables, cfg_maps); + + vector cfgOrchList = { &otnMgr }; + + swss::Select s; + for (Orch *o : cfgOrchList) + { + s.addSelectables(o->getSelectables()); + } + + while (true) + { + Selectable *sel; + int ret; + + ret = s.select(&sel, SELECT_TIMEOUT); + if (ret == Select::ERROR) + { + SWSS_LOG_NOTICE("Error: %s!", strerror(errno)); + continue; + } + if (ret == Select::TIMEOUT) + { + otnMgr.doTask(); + continue; + } + + auto *c = static_cast(sel); + c->execute(); + } + } + catch (const exception &e) + { + SWSS_LOG_ERROR("Runtime error: %s", e.what()); + } + return EXIT_FAILURE; +} diff --git a/orchagent/Makefile.am b/orchagent/Makefile.am index b0cbceb2414..6c9aa6e5963 100644 --- a/orchagent/Makefile.am +++ b/orchagent/Makefile.am @@ -6,7 +6,8 @@ INCLUDES = -I $(top_srcdir)/lib \ -I debug_counter \ -I port \ -I pbh \ - -I nhg + -I nhg \ + -I otn SUBDIRS = p4orch/tests @@ -171,6 +172,11 @@ orchagent_SOURCES += p4orch/p4orch.cpp \ p4orch/ip_multicast_manager.cpp \ p4orch/ext_tables_manager.cpp +orchagent_SOURCES += otn/otnorchdaemon.cpp \ + otn/objectorch.cpp \ + otn/attenuatororch.cpp \ + otn/oaorch.cpp + orchagent_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) orchagent_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) orchagent_LDADD = $(LDFLAGS_ASAN) -lnl-3 -lnl-route-3 -lpthread -lsairedis -lsaimeta -lsaimetadata -lswsscommon -lzmq -lprotobuf -ldashapi -ljemalloc diff --git a/orchagent/flex_counter/flex_counter_manager.cpp b/orchagent/flex_counter/flex_counter_manager.cpp index a7504fe5e6c..3b99b34617a 100644 --- a/orchagent/flex_counter/flex_counter_manager.cpp +++ b/orchagent/flex_counter/flex_counter_manager.cpp @@ -56,6 +56,8 @@ const unordered_map FlexCounterManager::counter_id_field_lo { CounterType::SRV6, SRV6_COUNTER_ID_LIST }, { CounterType::SWITCH, SWITCH_COUNTER_ID_LIST }, { CounterType::HA_SET, HA_SET_COUNTER_ID_LIST }, + { CounterType::OTN_ATTENUATOR_ATTR, OTN_ATTENUATOR_ATTR_ID_LIST }, + { CounterType::OTN_OA_ATTR, OTN_OA_ATTR_ID_LIST }, }; FlexManagerDirectory g_FlexManagerDirectory; diff --git a/orchagent/flex_counter/flex_counter_manager.h b/orchagent/flex_counter/flex_counter_manager.h index 99479d5685e..11fa76b2945 100644 --- a/orchagent/flex_counter/flex_counter_manager.h +++ b/orchagent/flex_counter/flex_counter_manager.h @@ -46,6 +46,8 @@ enum class CounterType SRV6, SWITCH, HA_SET, + OTN_ATTENUATOR_ATTR, + OTN_OA_ATTR, }; extern bool gTraditionalFlexCounter; diff --git a/orchagent/main.cpp b/orchagent/main.cpp index 6e80c33449a..c9d95eb36c8 100644 --- a/orchagent/main.cpp +++ b/orchagent/main.cpp @@ -34,6 +34,8 @@ extern "C" { #include "gearboxutils.h" #include "macsecpost.h" +#include "otnorchdaemon.h" + using namespace std; using namespace swss; @@ -255,7 +257,7 @@ void getCfgSwitchType(DBConnector *cfgDb, string &switch_type, string &switch_su switch_type = "switch"; } - if (switch_type != "voq" && switch_type != "fabric" && switch_type != "chassis-packet" && switch_type != "switch" && switch_type != "dpu") + if (switch_type != "voq" && switch_type != "fabric" && switch_type != "chassis-packet" && switch_type != "switch" && switch_type != "dpu" && switch_type != "otn") { SWSS_LOG_ERROR("Invalid switch type %s configured", switch_type.c_str()); //If configured switch type is none of the supported, assume regular switch @@ -995,7 +997,10 @@ int main(int argc, char **argv) dpu_app_state_db = make_shared("DPU_APPL_STATE_DB", 0, true); orchDaemon = make_shared(&appl_db, &config_db, &state_db, chassis_app_db.get(), dpu_app_db.get(), dpu_app_state_db.get(), zmq_server.get()); } - + else if (gMySwitchType == "otn") + { + orchDaemon = make_shared(&appl_db, &config_db, &state_db, chassis_db, zmq_server.get()); + } else if (gMySwitchType != "fabric") { orchDaemon = make_shared(&appl_db, &config_db, &state_db, chassis_db, zmq_server.get()); diff --git a/orchagent/otn/attenuatororch.cpp b/orchagent/otn/attenuatororch.cpp new file mode 100644 index 00000000000..ca0ac1dedc2 --- /dev/null +++ b/orchagent/otn/attenuatororch.cpp @@ -0,0 +1,39 @@ +#include "attenuatororch.h" +#include "schema.h" + + +extern sai_otn_attenuator_api_t *sai_otn_attenuator_api; + +#define OTN_ATTENUATOR_NOTIFICATION "OTN_ATTENUATOR_NOTIFICATION" +#define OTN_ATTENUATOR_REPLY "OTN_ATTENUATOR_REPLY" +#define OTN_ATTENUATOR_FLEX_COUNTER_GROUP "OTN_ATTENUATOR_FLEX_COUNTER" +#define OTN_ATTENUATOR_PLUGIN_DEFAULT_POLLING_INTERVAL_MS 1000 // ms +#define OTN_ATTENUATOR_PLUGIN_DEFAULT_ENABLED_STATE true + +AttenuatorOrch::AttenuatorOrch(DBConnector *db, const std::vector &table_names) : + ObjectOrch(db, table_names, (sai_object_type_t)SAI_OBJECT_TYPE_OTN_ATTENUATOR, CounterType::OTN_ATTENUATOR_ATTR) +{ + SWSS_LOG_ENTER(); + + std::string scriptPath = "otn_attenuator_pluggin.lua"; + createFlexCounter(scriptPath, + OTN_ATTENUATOR_PLUGIN_FIELD, + OTN_ATTENUATOR_FLEX_COUNTER_GROUP, + StatsMode::READ, + OTN_ATTENUATOR_PLUGIN_DEFAULT_POLLING_INTERVAL_MS, + OTN_ATTENUATOR_PLUGIN_DEFAULT_ENABLED_STATE); + + m_stateTable = std::unique_ptr(new Table(m_stateDb.get(), STATE_OTN_ATTENUATOR_TABLE_NAME)); + m_nameMapTable = std::unique_ptr
(new Table(m_countersDb.get(), COUNTERS_OTN_ATTENUATOR_NAME_MAP)); + + m_notificationConsumer = new NotificationConsumer(db, OTN_ATTENUATOR_NOTIFICATION); + auto notifier = new Notifier(m_notificationConsumer, this, OTN_ATTENUATOR_NOTIFICATION); + Orch::addExecutor(notifier); + m_notificationProducer = new NotificationProducer(db, OTN_ATTENUATOR_REPLY); + + m_createFunc = sai_otn_attenuator_api->create_otn_attenuator; + m_removeFunc = sai_otn_attenuator_api->remove_otn_attenuator; + m_setFunc = sai_otn_attenuator_api->set_otn_attenuator_attribute; + m_getFunc = sai_otn_attenuator_api->get_otn_attenuator_attribute; + +} diff --git a/orchagent/otn/attenuatororch.h b/orchagent/otn/attenuatororch.h new file mode 100644 index 00000000000..498168e99ba --- /dev/null +++ b/orchagent/otn/attenuatororch.h @@ -0,0 +1,9 @@ +#pragma once + +#include "objectorch.h" + +class AttenuatorOrch: public ObjectOrch +{ +public: + AttenuatorOrch(DBConnector *db, const std::vector &table_names); +}; diff --git a/orchagent/otn/oaorch.cpp b/orchagent/otn/oaorch.cpp new file mode 100644 index 00000000000..4a94a4076b1 --- /dev/null +++ b/orchagent/otn/oaorch.cpp @@ -0,0 +1,39 @@ +#include "oaorch.h" +#include "schema.h" + + +extern sai_otn_oa_api_t *sai_otn_oa_api; + +#define OTN_OA_NOTIFICATION "OTN_OA_NOTIFICATION" +#define OTN_OA_REPLY "OTN_OA_REPLY" +#define OTN_OA_FLEX_COUNTER_GROUP "OTN_OA_FLEX_COUNTER" +#define OTN_OA_DEFAULT_POLLING_INTERVAL_MS 1000 // ms +#define OTN_OA_DEFAULT_ENABLED_STATE true + +OaOrch::OaOrch(DBConnector *db, const std::vector &table_names) : + ObjectOrch(db, table_names, (sai_object_type_t)SAI_OBJECT_TYPE_OTN_OA, CounterType::OTN_OA_ATTR) +{ + SWSS_LOG_ENTER(); + + std::string scriptPath = "otn_oa_pluggin.lua"; + createFlexCounter(scriptPath, + OTN_OA_PLUGIN_FIELD, + OTN_OA_FLEX_COUNTER_GROUP, + StatsMode::READ, + OTN_OA_DEFAULT_POLLING_INTERVAL_MS, + OTN_OA_DEFAULT_ENABLED_STATE); + + m_stateTable = std::unique_ptr
(new Table(m_stateDb.get(), STATE_OTN_OA_TABLE_NAME)); + m_nameMapTable = std::unique_ptr
(new Table(m_countersDb.get(), COUNTERS_OTN_OA_NAME_MAP)); + + m_notificationConsumer = new NotificationConsumer(db, OTN_OA_NOTIFICATION); + auto notifier = new Notifier(m_notificationConsumer, this, OTN_OA_NOTIFICATION); + Orch::addExecutor(notifier); + m_notificationProducer = new NotificationProducer(db, OTN_OA_REPLY); + + m_createFunc = sai_otn_oa_api->create_otn_oa; + m_removeFunc = sai_otn_oa_api->remove_otn_oa; + m_setFunc = sai_otn_oa_api->set_otn_oa_attribute; + m_getFunc = sai_otn_oa_api->get_otn_oa_attribute; + +} diff --git a/orchagent/otn/oaorch.h b/orchagent/otn/oaorch.h new file mode 100644 index 00000000000..7e21b8fcb82 --- /dev/null +++ b/orchagent/otn/oaorch.h @@ -0,0 +1,9 @@ +#pragma once + +#include "objectorch.h" + +class OaOrch: public ObjectOrch +{ +public: + OaOrch(DBConnector *db, const std::vector &table_names); +}; diff --git a/orchagent/otn/objectorch.cpp b/orchagent/otn/objectorch.cpp new file mode 100644 index 00000000000..9c98f1addda --- /dev/null +++ b/orchagent/otn/objectorch.cpp @@ -0,0 +1,841 @@ +#include +#include +#include + +#include + +#include "objectorch.h" +#include "otnutil.h" +#include "sai_serialize.h" +#include "redisapi.h" + + +extern sai_object_id_t gSwitchId; + +void ObjectOrch::loadExtraFlexCounterAttrs() +{ + std::ifstream file("/usr/share/sonic/platform/flex_counter_extra_attrs.json"); + if (!file.good()) + { + return; + } + + try + { + nlohmann::json j; + file >> j; + + const char *shortName = sai_metadata_get_enum_value_short_name( + &sai_metadata_enum_sai_object_type_t, m_objectType); + if (shortName == nullptr) + { + SWSS_LOG_WARN("Unknown object type %d, skip loading extra FlexCounter attrs", m_objectType); + return; + } + + std::string tableName(shortName); + + if (!j.contains(tableName) || !j[tableName].is_array()) + { + return; + } + + for (const auto &attrName : j[tableName]) + { + std::string name = attrName.get(); + sai_attr_id_t attr_id; + + if (m_createandsetAttrs.count(name)) + { + attr_id = m_createandsetAttrs[name]; + } + else if (m_createonlyAttrs.count(name)) + { + attr_id = m_createonlyAttrs[name]; + } + else + { + SWSS_LOG_WARN("Unknown extra FlexCounter attr '%s' for %s, skipped", + name.c_str(), tableName.c_str()); + continue; + } + + auto meta = sai_metadata_get_attr_metadata(m_objectType, attr_id); + if (meta == nullptr) + { + SWSS_LOG_WARN("Failed to get metadata for attr '%s', skipped", name.c_str()); + continue; + } + + m_extraFlexCounterAttrs.push_back(meta->attridname); + SWSS_LOG_NOTICE("Extra FlexCounter attr: %s -> %s", name.c_str(), meta->attridname); + } + } + catch (const std::exception &e) + { + SWSS_LOG_WARN("Failed to parse flex_counter_extra_attrs.json: %s", e.what()); + } +} + +void ObjectOrch::localDataInit(DBConnector *db) +{ + SWSS_LOG_ENTER(); + + const char *objectName = sai_metadata_get_object_type_name(m_objectType); + if (objectName == NULL) + { + SWSS_LOG_ERROR("Invalid object type %u", m_objectType); + return; + } + + m_objectName = objectName; + m_stateDb = std::make_shared("STATE_DB", 0); + m_countersDb = std::make_shared("COUNTERS_DB", 0); + m_vid2NameTable = std::unique_ptr
(new Table(m_countersDb.get(), "VID2NAME")); + + SWSS_LOG_NOTICE("ObjectOrch init, object type=%u, object name=%s", m_objectType, objectName); + + /* Initialize local data from meta data, save the short names to match openconfig keys */ + const sai_object_type_info_t *oi = sai_metadata_get_object_type_info(m_objectType); + if (oi == NULL) { + SWSS_LOG_ERROR("Invalid object type %u, object name=%s", m_objectType, objectName); + return; + } + + for (size_t index = 0; index < oi->enummetadata->valuescount; index++) + { + /** + * Record the attribute short name and id. + * The default name format from sai meta data is underline. + */ + std::string name(oi->enummetadata->valuesshortnames[index]); + std::transform(name.begin(), name.end(), name.begin(), ::tolower); + + /** + * To compatible with both hyphen and underline naming. + * e.g. + * 1. leaf-name + * 2. leaf_name + */ + std::string hyphen_name(name); + std::replace(hyphen_name.begin(), hyphen_name.end(), '_', '-'); + sai_attr_id_t id = oi->enummetadata->values[index]; + const sai_attr_metadata_t *const attr = oi->attrmetadata[index]; + + SWSS_LOG_DEBUG("localDataInit, enum index=%zu, attr valueprecision: %zu", index, attr->valueprecision); + // Save precision value for each attribuite if precision is valid. + if (attr->valueprecision > 0) { + m_attrPrecisions[name] = attr->valueprecision; + m_attrPrecisions[hyphen_name] = attr->valueprecision; + } + + // Save attribute id for each different type attribute. + auto addAttrToMap = [&](std::map& attr_map) { + attr_map[name] = id; + attr_map[hyphen_name] = id; + return; + }; + + if (attr->ismandatoryoncreate) + { + addAttrToMap(m_mandatoryAttrs); + } + + if (attr->iscreateonly) + { + addAttrToMap(m_createonlyAttrs); + } + else if (attr->iscreateandset) + { + addAttrToMap(m_createandsetAttrs); + } + else if (attr->isreadonly) + { + addAttrToMap(m_readonlyAttrs); + + /* add original name for flex counter */ + m_readonlyOrgAttrs[oi->enummetadata->valuesnames[index]] = id; + } + + if (attr->isenum) + { + for (size_t i = 0; i < attr->enummetadata->valuescount; i++) + { + /* enum original name */ + std::string enum_name(attr->enummetadata->valuesshortnames[i]); + m_enumValues[enum_name] = attr->enummetadata->valuesnames[i]; + + /* support enum name with lower case */ + std::transform(enum_name.begin(), enum_name.end(), enum_name.begin(), ::tolower); + m_enumValues[enum_name] = attr->enummetadata->valuesnames[i]; + } + } + } + + /* Set create and set, create only attributes to state cache list */ + for (const auto &it : m_createandsetAttrs) + { + m_needToCache.insert(it.first); + } + + for (const auto &it : m_createonlyAttrs) + { + m_needToCache.insert(it.first); + } + + loadExtraFlexCounterAttrs(); + + SWSS_LOG_DEBUG("localDataInit, exit"); +} + +ObjectOrch::ObjectOrch(DBConnector *db, + const std::vector& table_names, + sai_object_type_t obj_type, + CounterType flex_counter_type) : + Orch(db, table_names), + m_objectType(obj_type), + m_flex_counter_type(flex_counter_type), + m_notificationConsumer(nullptr), + m_notificationProducer(nullptr) +{ + SWSS_LOG_ENTER(); + + localDataInit(db); +} + +ObjectOrch::ObjectOrch(DBConnector *db, + std::vector &connectors, + sai_object_type_t obj_type, + CounterType flex_counter_type) : + Orch(connectors), + m_objectType(obj_type), + m_flex_counter_type(flex_counter_type), + m_notificationConsumer(nullptr), + m_notificationProducer(nullptr) +{ + SWSS_LOG_ENTER(); + + localDataInit(db); +} + +void ObjectOrch::doTask(NotificationConsumer& consumer) +{ + SWSS_LOG_ENTER(); + + std::string op; + std::string data; + sai_status_t status; + std::vector values; + sai_object_id_t oid = SAI_NULL_OBJECT_ID; + + if (&consumer != m_notificationConsumer) + { + return; + } + + consumer.pop(op, data, values); + + if (m_key2oid.find(data) == m_key2oid.end()) + { + SWSS_LOG_ERROR("Failed to get oid, key=%s|%s", m_objectName.c_str(), data.c_str()); + goto error; + } + + oid = m_key2oid[data]; + + if (op == "set") + { + for (unsigned i = 0; i < values.size(); i++) + { + std::string &value = fvValue(values[i]); + std::string &field = fvField(values[i]); + + status = setObjectAttr(oid, field, value); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set attr, field=%s, value=%s, status=%d", + field.c_str(), value.c_str(), status); + goto error; + } + } + op = "SUCCESS"; + m_notificationProducer->send(op, data, values); + + return; + } + else if (op == "get") + { + for (unsigned i = 0; i < values.size(); i++) + { + std::string &value = fvValue(values[i]); + std::string &field = fvField(values[i]); + + status = getObjectAttr(oid, field, value); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to get attr, field=%s, status=%d", + field.c_str(), status); + goto error; + } + } + op = "SUCCESS"; + m_notificationProducer->send(op, data, values); + + return; + } + +error: + op = "FAILED"; + m_notificationProducer->send(op, data, values); + + return; +} + +bool ObjectOrch::createObject(const std::string &key) +{ + SWSS_LOG_ENTER(); + + std::vector attrs; + std::map &createonly_attrs = m_key2createonlyAttrs[key]; + for (const auto &fv : createonly_attrs) + { + sai_attribute_t attr; + if (translateObjectAttr(fv.first, fv.second, attr) == false) + { + SWSS_LOG_ERROR("Failed to translate attr, %s|%s", + m_objectName.c_str(), fv.first.c_str()); + continue; + } + attrs.push_back(attr); + } + + addExtraAttrsOnCreate(key, attrs); + + sai_object_id_t oid; + sai_status_t status = m_createFunc(&oid, gSwitchId, static_cast(attrs.size()), attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create %s|%s, rv=%d", m_objectName.c_str(), key.c_str(), status); + return false; + } + + /* Copy config to state */ + copyConfigToState(key, createonly_attrs); + + SWSS_LOG_NOTICE("Create %s|%s oid:%" PRIx64, m_objectName.c_str(), key.c_str(), oid); + + m_key2oid[key] = oid; + + if (!setObjectAttrs(key, m_key2createandsetAttrs[key])) + { + SWSS_LOG_ERROR("Failed to set fields, %s", key.c_str()); + } + + FieldValueTuple tuple(sai_serialize_object_id(oid), key); + std::vector fields; + fields.push_back(tuple); + m_nameMapTable->set("", fields); + + m_vid2NameTable->set("", fields); + + setFlexCounter(oid); + + SWSS_LOG_NOTICE("Initialized %s", key.c_str()); + + return true; +} + +bool ObjectOrch::removeObject(const std::string &key) +{ + SWSS_LOG_ENTER(); + + sai_status_t status; + sai_object_id_t oid; + + if (m_key2oid.find(key) == m_key2oid.end()) + { + SWSS_LOG_ERROR("Failed to get oid, key=%s|%s", m_objectName.c_str(), key.c_str()); + return false; + } + + oid = m_key2oid[key]; + + /* clean flex counter first then remove object */ + clearFlexCounter(oid); + + status = m_removeFunc(oid); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to remove %s|%s, rv=%d", m_objectName.c_str(), key.c_str(), status); + return false; + } + + SWSS_LOG_NOTICE("Remove %s|%s oid:%" PRIx64, m_objectName.c_str(), key.c_str(), oid); + + m_keys.erase(key); + m_key2oid.erase(key); + m_key2createonlyAttrs.erase(key); + m_key2createandsetAttrs.erase(key); + + /* delete redis backed tables: + m_vid2NameTable + m_nameMapTable + */ + std::string oid_str = sai_serialize_object_id(oid); + m_vid2NameTable->hdel("", oid_str); + m_nameMapTable->hdel("", oid_str); + + return true; +} + +void ObjectOrch::publishOperationResult(const std::string &channel, sai_status_t status_code, const std::string &message) +{ + swss::NotificationProducer notifications(m_stateDb.get(), channel); + std::vector entry; + auto sent_clients = notifications.send(std::to_string(status_code), message, entry); + SWSS_LOG_NOTICE("publishresult %d, %s to %ld client on channel %s", + status_code, message.c_str(), sent_clients, channel.c_str()); +} + +bool ObjectOrch::setObjectAttrs(const std::string& key, std::map& field_values, std::string operation_id) +{ + SWSS_LOG_ENTER(); + + bool rv = true; + + if (m_key2oid.find(key) == m_key2oid.end()) + { + SWSS_LOG_ERROR("Failed to get oid, key=%s|%s", m_objectName.c_str(), key.c_str()); + return false; + } + + std::string error_msg; + sai_status_t status = SAI_STATUS_SUCCESS; + + for (const auto &fv : field_values) + { + std::string channel = fv.first + "-" + operation_id; + + SWSS_LOG_NOTICE("set field=%s value=%s", fv.first.c_str(), fv.second.c_str()); + + status = setObjectAttr(m_key2oid[key], fv.first, fv.second); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set %s|%s %s to %s, status=%d", + m_objectName.c_str(), + key.c_str(), + fv.first.c_str(), + fv.second.c_str(), + status); + + rv = false; + error_msg = "Failed to set " + key + " " + fv.first + " to " + fv.second; + } + else + { + SWSS_LOG_NOTICE("Set %s|%s %s to %s", + m_objectName.c_str(), + key.c_str(), + fv.first.c_str(), + fv.second.c_str()); + + copyConfigToState(key, fv); + + error_msg = "Set " + key + " " + fv.first + " to " + fv.second; + } + + publishOperationResult(channel, status, error_msg); + } + + return rv; +} + +bool ObjectOrch::translateObjectAttr( + _In_ const std::string &field, + _In_ const std::string &value, + _Out_ sai_attribute_t &attr) const +{ + if (m_createandsetAttrs.find(field) != m_createandsetAttrs.end()) + { + attr.id = m_createandsetAttrs.at(field); + } + else if (m_createonlyAttrs.find(field) != m_createonlyAttrs.end()) + { + attr.id = m_createonlyAttrs.at(field); + } + else + { + SWSS_LOG_ERROR("Unrecognized attr, %s|%s", m_objectName.c_str(), field.c_str()); + return false; + } + + auto meta = sai_metadata_get_attr_metadata(m_objectType, attr.id); + if (meta == nullptr) + { + SWSS_LOG_THROW("Unable to get %s metadata, attr=%d", m_objectName.c_str(), attr.id); + } + + /* Value translate */ + std::string newValue(value); + if (m_enumValues.find(value) != m_enumValues.end()) + { + newValue = m_enumValues.at(value); + } + else if (m_attrPrecisions.find(field) != m_attrPrecisions.end()) + { + try + { + newValue = otn::precisionEncode(value, m_attrPrecisions.at(field)); + } + catch (...) + { + SWSS_LOG_ERROR("Failed to encode precision value, %s|%s|%s", + m_objectName.c_str(), field.c_str(), value.c_str()); + return false; + } + } + + SWSS_LOG_NOTICE("translateObjectAttr, field = %s, value = %s", field.c_str(), newValue.c_str()); + + try + { + sai_deserialize_attr_value(newValue, *meta, attr); + } + catch (...) + { + SWSS_LOG_ERROR("Unrecognized attr value, %s|%s|%s", + m_objectName.c_str(), field.c_str(), newValue.c_str()); + return false; + } + + return true; +} + +sai_status_t ObjectOrch::setObjectAttr( + sai_object_id_t oid, + const std::string &field, + const std::string &value) +{ + SWSS_LOG_ENTER(); + + sai_attribute_t attr; + if (translateObjectAttr(field, value, attr) == false) + { + SWSS_LOG_ERROR("Failed to translate attr, %s|%s", + m_objectName.c_str(), field.c_str()); + return SAI_STATUS_FAILURE; + } + + sai_status_t status = m_setFunc(oid, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set %s attr, field=%s, value=%s, status=%d", + m_objectName.c_str(), field.c_str(), value.c_str(), status); + return status; + } + + SWSS_LOG_NOTICE("Set %s attr, pid:%" PRIx64 " field=%s, value=%s", + m_objectName.c_str(), oid, field.c_str(), value.c_str()); + + return SAI_STATUS_SUCCESS; +} + +sai_status_t ObjectOrch::getObjectAttr(sai_object_id_t oid, const std::string &field, std::string &value) +{ + SWSS_LOG_ENTER(); + + sai_attribute_t attr; + auto readonlyAttr = m_readonlyAttrs.find(field); + if (readonlyAttr == m_readonlyAttrs.end()) + { + SWSS_LOG_ERROR("Unsupported attr, %s|%s", m_objectName.c_str(), field.c_str()); + return SAI_STATUS_FAILURE; + } + attr.id = readonlyAttr->second; + + sai_status_t status = m_getFunc(oid, 1, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to get %s attr, field=%s, status=%d", + m_objectName.c_str(), field.c_str(), status); + return status; + } + auto meta = sai_metadata_get_attr_metadata(m_objectType, attr.id); + if (meta == NULL) + { + SWSS_LOG_ERROR("Unable to get %s metadata, attr=%d", m_objectName.c_str(), attr.id); + return SAI_STATUS_FAILURE; + } + + try + { + value = sai_serialize_attr_value(*meta, attr, false); + + auto precision = m_attrPrecisions.find(field); + if (precision != m_attrPrecisions.end()) + { + value = otn::precisionDecode(value, precision->second); + } + } + catch (...) + { + SWSS_LOG_ERROR("Failed to get attr value, %s|%s|%s", + m_objectName.c_str(), field.c_str(), value.c_str()); + return SAI_STATUS_FAILURE; + } + + SWSS_LOG_NOTICE("Get %s attr succeeded, pid:%" PRIx64 " field=%s, value=%s", + m_objectName.c_str(), oid, field.c_str(), value.c_str()); + + return SAI_STATUS_SUCCESS; +} + +void ObjectOrch::doTask(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + + if (consumer.getDbName() == "STATE_DB") + { + doStateTask(consumer); + return; + } + + auto it = consumer.m_toSync.begin(); + while (it != consumer.m_toSync.end()) + { + auto &t = it->second; + + std::string key = kfvKey(t); + std::string op = kfvOp(t); + + SWSS_LOG_NOTICE("doTask: Table = %s, key = %s, op = %s", m_objectName.c_str(), key.c_str(), op.c_str()); + + if (op == SET_COMMAND) + { + std::string operation_id = key; + + std::map createonly_attrs; + std::map createandset_attrs; + + for (const auto &i : kfvFieldsValues(t)) + { + const auto &name = fvField(i); + if (m_createonlyAttrs.find(name) != m_createonlyAttrs.end()) + { + createonly_attrs[name] = fvValue(i); + } + else if (m_createandsetAttrs.find(name) != m_createandsetAttrs.end()) + { + createandset_attrs[name] = fvValue(i); + SWSS_LOG_NOTICE("ObjectOrch::doTask, key=%s, value=%s", name.c_str(), fvValue(i).c_str()); + } + } + + // Add attribute name + createonly_attrs["name"] = key; + + if (m_keys.find(key) == m_keys.end()) + { + //Add create only attribute. + m_keys.insert(key); + m_key2createandsetAttrs[key] = createandset_attrs; + m_key2createonlyAttrs[key] = createonly_attrs; + } + + it = consumer.m_toSync.erase(it); + + /* Create object if needed */ + if (m_key2oid.find(key) == m_key2oid.end()) + { + if (!createObject(key)) + { + SWSS_LOG_THROW("Failed to create object"); + } + + continue; + } + + if (!setObjectAttrs(key, createandset_attrs, operation_id)) + { + SWSS_LOG_ERROR("Failed to set attributes, %s", key.c_str()); + } + } + else if (op == DEL_COMMAND) + { + SWSS_LOG_NOTICE("Deleting %s", key.c_str()); + if (!removeObject(key)) + { + SWSS_LOG_ERROR("Failed to remove object, %s", key.c_str()); + } + + it = consumer.m_toSync.erase(it); + } + else + { + SWSS_LOG_ERROR("Unknown operation type %s", op.c_str()); + it = consumer.m_toSync.erase(it); + } + } + + if (m_flex_stat_manager != nullptr) + { + m_flex_stat_manager->flush(); + } +} + +void ObjectOrch::doStateTask(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + + // TODO, need to solve present state. + + auto it = consumer.m_toSync.begin(); + while (it != consumer.m_toSync.end()) + { + auto &t = it->second; + + std::string key = kfvKey(t); + std::string op = kfvOp(t); + + bool has_present_field = false; + std::string present_value; + + SWSS_LOG_DEBUG("%s, key = %s, op = %s", m_objectName.c_str(), key.c_str(), op.c_str()); + + if (m_key2oid.find(key) == m_key2oid.end()) + { + it = consumer.m_toSync.erase(it); + continue; + } + + for (const auto &i : kfvFieldsValues(t)) + { + if (fvField(i) == "present") + { + has_present_field = true; + present_value = fvValue(i); + break; + } + } + if (has_present_field == false) + { + it = consumer.m_toSync.erase(it); + continue; + } + + sai_object_id_t id = m_key2oid[key]; + + std::string present; + + if (m_key2present.find(key) != m_key2present.end()) + { + present = m_key2present[key]; + } + + if (present_value != present) + { + if (present_value == "PRESENT") + { + SWSS_LOG_NOTICE("setCounterIdList 0x%" PRIx64 ", key = %s", id, key.c_str()); + setFlexCounter(id); + } + else if (present_value == "NOT_PRESENT") + { + SWSS_LOG_NOTICE("clearCounterIdList 0x%" PRIx64 ", key = %s", id, key.c_str()); + clearFlexCounter(id); + } + + doSubobjectStateTask(key, present_value); + m_key2present[key] = present_value; + } + + it = consumer.m_toSync.erase(it); + } +} + +void ObjectOrch::createFlexCounter( + _In_ const std::string& script_path, + _In_ const std::string& plugin_field, + _In_ const std::string& group_name, + _In_ const StatsMode stats_mode, + _In_ const uint polling_interval, + _In_ const bool enabled) +{ + SWSS_LOG_ENTER(); + + FieldValueTuple fv_stat = std::make_pair("",""); + + if (!script_path.empty()) + { + try + { + std::string path("/usr/share/sonic/platform/"); + path += script_path; + std::string att_script = swss::readTextFile(path); + std::string att_sha = swss::loadRedisScript(m_countersDb.get(), att_script); + fv_stat = FieldValueTuple(plugin_field, att_sha); + } + catch (const std::runtime_error &e) + { + SWSS_LOG_WARN("%s group plugins was not set successfully: %s", group_name.c_str(), e.what()); + fv_stat = std::make_pair("",""); + } + } + + m_flex_stat_manager = std::make_unique>( + group_name, stats_mode, polling_interval, enabled, fv_stat); +} + +void ObjectOrch::setFlexCounter(sai_object_id_t id) +{ + SWSS_LOG_ENTER(); + + if (m_flex_stat_manager == nullptr) + { + SWSS_LOG_WARN("Flex counter manager not initialized for %" PRIx64 "", id); + return; + } + + std::unordered_set counter_attrs; + for (const auto& it : m_readonlyOrgAttrs) { + counter_attrs.emplace(it.first); + } + + for (const auto& attrName : m_extraFlexCounterAttrs) + { + counter_attrs.emplace(attrName); + } + + m_flex_stat_manager->setCounterIdList(id, m_flex_counter_type, counter_attrs); +} + +void ObjectOrch::clearFlexCounter(sai_object_id_t id) { + SWSS_LOG_ENTER(); + + if (m_flex_stat_manager == nullptr) + { + SWSS_LOG_WARN("Flex counter manager not initialized"); + return; + } + + SWSS_LOG_NOTICE("Clear flex counter, id: %" PRIx64 "", id); + m_flex_stat_manager->clearCounterIdList(id); +} + +void ObjectOrch::copyConfigToState(const std::string &key, const FieldValueTuple &fv) +{ + if (m_needToCache.find(fv.first) != m_needToCache.end()) + { + std::vector fvs; + fvs.push_back(fv); + m_stateTable->set(key, fvs); + } +} + +void ObjectOrch::copyConfigToState(const std::string &key, std::map &fvs) +{ + for (const auto &fv : fvs) + { + copyConfigToState(key, fv); + } +} diff --git a/orchagent/otn/objectorch.h b/orchagent/otn/objectorch.h new file mode 100644 index 00000000000..e9aff5abc05 --- /dev/null +++ b/orchagent/otn/objectorch.h @@ -0,0 +1,170 @@ +#pragma once + +#include +#include +#include +#include +#include +#include "orch.h" +#include "saihelper.h" +#include "notifier.h" +#include "notificationproducer.h" +#include "notifications.h" +#include "timer.h" +#include "flex_counter_manager.h" + +using namespace swss; + +typedef sai_status_t (*CreateObjectFunc)( + sai_object_id_t *oid, + sai_object_id_t linecard_id, + uint32_t attr_count, + const sai_attribute_t *attr_list); + +typedef sai_status_t (*RemoveObjectFunc)( + sai_object_id_t oid); + +typedef sai_status_t (*SetObjectAttrFunc)( + sai_object_id_t oid, + const sai_attribute_t *attr); + +typedef sai_status_t (*GetObjectAttrFunc)( + sai_object_id_t oid, + uint32_t attr_count, + sai_attribute_t *attr_list); + +typedef enum _ConfigState_E +{ + CONFIG_MISSING = 0, + CONFIG_RECEIVED, + CONFIG_CREATED, + CONFIG_DONE, +} ConfigState_E; + +class ObjectOrch: public Orch +{ +public: + ObjectOrch(DBConnector *db, const std::vector &table_names): Orch(db, table_names) {} + + ObjectOrch(DBConnector *db, + const std::vector &table_names, + sai_object_type_t obj_type, + CounterType flex_counter_type); + + ObjectOrch(DBConnector *db, + std::vector &connectors, + sai_object_type_t obj_type, + CounterType flex_counter_type); + + void localDataInit(DBConnector *db); + + void doTask(Consumer &consumer); + + virtual void doTask(NotificationConsumer &consumer); + + void doStateTask(Consumer &consumer); + + bool createObject(const std::string &key); + bool removeObject(const std::string &key); + + virtual void addExtraAttrsOnCreate(const std::string &key, std::vector &attrs) {}; + + bool setObjectAttrs(const std::string &key, + std::map &field_values, + std::string operation_id=""); + + sai_status_t setObjectAttr(sai_object_id_t oid, const std::string &field, const std::string &value); + + sai_status_t getObjectAttr(sai_object_id_t oid, const std::string &field, std::string &value); + + virtual void setFlexCounter(sai_object_id_t id); + + virtual void clearFlexCounter(sai_object_id_t id); + + virtual void doSubobjectStateTask(const std::string &key, const std::string &present){}; + + void publishOperationResult(const std::string &channel, sai_status_t status_code, const std::string &message); + + bool translateObjectAttr(_In_ const std::string &field, + _In_ const std::string &value, + _Out_ sai_attribute_t &attr) const; + + void createFlexCounter(_In_ const std::string &script_path, + _In_ const std::string &plugin_field, + _In_ const std::string &group_name, + _In_ const StatsMode stats_mode, + _In_ const uint polling_interval, + _In_ const bool enabled); + + void copyConfigToState(const std::string &key, const FieldValueTuple &fv); + void copyConfigToState(const std::string &key, std::map &fvs); + +protected: + void loadExtraFlexCounterAttrs(); + + std::shared_ptr m_stateDb; + + std::unique_ptr
m_stateTable; + + std::shared_ptr m_countersDb; + + std::unique_ptr
m_nameMapTable; + + std::unique_ptr
m_vid2NameTable; + + CreateObjectFunc m_createFunc; + + RemoveObjectFunc m_removeFunc; + + SetObjectAttrFunc m_setFunc; + + GetObjectAttrFunc m_getFunc; + + uint32_t m_count; + + sai_object_type_t m_objectType; + + std::string m_objectName; + + CounterType m_flex_counter_type; + + /* Attributes that can be modified at anytime. */ + std::map m_createandsetAttrs; + + /* Attributes that can only be set during creation. */ + std::map m_createonlyAttrs; + + std::map m_mandatoryAttrs; + + std::map m_readonlyAttrs; + + std::map m_enumValues; + + /* record original name instead of short name above */ + std::map m_readonlyOrgAttrs; + + /* record precision */ + std::map m_attrPrecisions; + + ConfigState_E m_configState = CONFIG_MISSING; + + std::set m_keys; + + std::map m_key2oid; + + std::map> m_key2createonlyAttrs; + + std::map> m_key2createandsetAttrs; + + std::map m_key2present; + + std::set m_needToCache; + + NotificationConsumer *m_notificationConsumer; + + NotificationProducer *m_notificationProducer; + + std::vector m_extraFlexCounterAttrs; + + std::unique_ptr> m_flex_stat_manager; +}; diff --git a/orchagent/otn/otnorchdaemon.cpp b/orchagent/otn/otnorchdaemon.cpp new file mode 100644 index 00000000000..9b373ca1cde --- /dev/null +++ b/orchagent/otn/otnorchdaemon.cpp @@ -0,0 +1,40 @@ +#include "otnorchdaemon.h" +#include "attenuatororch.h" +#include "oaorch.h" + +OtnOrchDaemon::OtnOrchDaemon(DBConnector *applDb, DBConnector *configDb, DBConnector *stateDb, DBConnector *chassisAppDb, ZmqServer *zmqServer) : + OrchDaemon(applDb, configDb, stateDb, chassisAppDb, zmqServer), + m_applDb(applDb), + m_configDb(configDb) +{ + SWSS_LOG_ENTER(); + SWSS_LOG_NOTICE("OtnOrchDaemon starting..."); +} + +bool OtnOrchDaemon::init() +{ + SWSS_LOG_ENTER(); + SWSS_LOG_NOTICE("OtnOrchDaemon init"); + + /* attenuator */ + const std::vector attenuator_tables = { + APP_OTN_ATTENUATOR_TABLE_NAME + }; + AttenuatorOrch *attenuatorOrch = new AttenuatorOrch(m_applDb, attenuator_tables); + addOrchList(attenuatorOrch); + + /* OA */ + const std::vector oa_tables = { + APP_OTN_OA_TABLE_NAME + }; + OaOrch *oaOrch = new OaOrch(m_applDb, oa_tables); + addOrchList(oaOrch); + + /* Flex counter */ + std::vector flex_counter_tables = { + CFG_FLEX_COUNTER_TABLE_NAME + }; + addOrchList(new FlexCounterOrch(m_configDb, flex_counter_tables)); + + return true; +} diff --git a/orchagent/otn/otnorchdaemon.h b/orchagent/otn/otnorchdaemon.h new file mode 100644 index 00000000000..1c021eabb42 --- /dev/null +++ b/orchagent/otn/otnorchdaemon.h @@ -0,0 +1,13 @@ +#pragma once +#include "orchdaemon.h" + +class OtnOrchDaemon : public OrchDaemon +{ +public: + OtnOrchDaemon(DBConnector *applDb, DBConnector *configDb, DBConnector *stateDb, DBConnector *chassisAppDb, ZmqServer *zmqServer); + bool init() override; + +private: + DBConnector *m_applDb; + DBConnector *m_configDb; +}; diff --git a/orchagent/otn/otnutil.h b/orchagent/otn/otnutil.h new file mode 100644 index 00000000000..b753b232735 --- /dev/null +++ b/orchagent/otn/otnutil.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace otn { + +inline std::string precisionEncode(const std::string &value, size_t precision) +{ + double fval = std::stod(value); + int64_t ival = std::llround(fval * std::pow(10, precision)); + return std::to_string(ival); +} + +inline std::string precisionDecode(const std::string &value, size_t precision) +{ + double fval = std::stod(value) / std::pow(10, precision); + std::ostringstream oss; + oss << std::fixed + << std::setprecision(static_cast(precision)) + << fval; + return oss.str(); +} + +} // namespace otn diff --git a/orchagent/saihelper.cpp b/orchagent/saihelper.cpp index 7c86713002a..c39081016c4 100644 --- a/orchagent/saihelper.cpp +++ b/orchagent/saihelper.cpp @@ -105,6 +105,8 @@ sai_dash_meter_api_t* sai_dash_meter_api; sai_dash_outbound_port_map_api_t* sai_dash_outbound_port_map_api; sai_dash_trusted_vni_api_t* sai_dash_trusted_vni_api; sai_dash_flow_api_t* sai_dash_flow_api; +sai_otn_attenuator_api_t* sai_otn_attenuator_api; +sai_otn_oa_api_t* sai_otn_oa_api; extern sai_object_id_t gSwitchId; extern bool gTraditionalFlexCounter; @@ -330,6 +332,8 @@ void initSaiApi() sai_api_query(SAI_API_TWAMP, (void **)&sai_twamp_api); sai_api_query(SAI_API_TAM, (void **)&sai_tam_api); sai_api_query(SAI_API_STP, (void **)&sai_stp_api); + sai_api_query((sai_api_t)SAI_API_OTN_ATTENUATOR, (void **)&sai_otn_attenuator_api); + sai_api_query((sai_api_t)SAI_API_OTN_OA, (void **)&sai_otn_oa_api); sai_log_set(SAI_API_SWITCH, SAI_LOG_LEVEL_NOTICE); sai_log_set(SAI_API_BRIDGE, SAI_LOG_LEVEL_NOTICE);